
org.opentripplanner.raptor.api.request.MultiCriteriaRequest Maven / Gradle / Ivy
Show all versions of otp Show documentation
package org.opentripplanner.raptor.api.request;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import javax.annotation.Nullable;
import org.opentripplanner.framework.tostring.ToStringBuilder;
import org.opentripplanner.raptor.api.model.RaptorTripSchedule;
import org.opentripplanner.raptor.api.model.RelaxFunction;
/**
* Parameters to configure the multi-criteria search.
*
* @param The TripSchedule type defined by the user of the raptor API.
*/
public class MultiCriteriaRequest {
private final RelaxFunction relaxC1;
@Nullable
private final RaptorTransitGroupPriorityCalculator transitPriorityCalculator;
private final List passThroughPoints;
@Nullable
private final Double relaxCostAtDestination;
private MultiCriteriaRequest() {
this.relaxC1 = RelaxFunction.NORMAL;
this.transitPriorityCalculator = null;
this.passThroughPoints = List.of();
this.relaxCostAtDestination = null;
}
public MultiCriteriaRequest(Builder builder) {
this.relaxC1 = Objects.requireNonNull(builder.relaxC1());
this.transitPriorityCalculator = builder.transitPriorityCalculator();
this.passThroughPoints = builder.passThroughPoints();
this.relaxCostAtDestination = builder.relaxCostAtDestination();
}
public static Builder of() {
return new Builder(new MultiCriteriaRequest<>());
}
public Builder copyOf() {
return new Builder<>(this);
}
/**
* Whether to accept non-optimal trips if they are close enough with respect to
* c1(generalized-cost). In other words this relaxes the pareto comparison at
* each stop and at the destination.
*
* Let {@code c} be the existing minimum pareto optimal cost to beat. Then a trip
* with cost {@code c'} is accepted if the following is true:
*
* c' < RelaxFunction.relax(c)
*
* The default is {@link RelaxFunction#NORMAL}.
*/
public RelaxFunction relaxC1() {
return relaxC1;
}
public Optional transitPriorityCalculator() {
return Optional.ofNullable(transitPriorityCalculator);
}
public boolean hasPassThroughPoints() {
return !passThroughPoints.isEmpty();
}
public List passThroughPoints() {
return passThroughPoints;
}
/**
* Whether to accept non-optimal trips if they are close enough - if and only if they represent
* an optimal path for their given iteration. In other words this slack only relaxes the pareto
* comparison at the destination.
*
* Let {@code c} be the existing minimum pareto optimal cost to beat. Then a trip with cost
* {@code c'} is accepted if the following is true:
*
* c' < Math.round(c * relaxCostAtDestination)
*
* If the value is less than 1.0 a normal '<' comparison is performed.
*
* The default is not set.
*
* @deprecated This parameter only relax the cost at the destination, not at each stop. This
* is replaced by {@link #relaxC1()}. This parameter is ignored if {@link #relaxC1()} exist.
*/
@Deprecated
@Nullable
public Double relaxCostAtDestination() {
return relaxCostAtDestination;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MultiCriteriaRequest> that = (MultiCriteriaRequest>) o;
return (
Objects.equals(relaxC1, that.relaxC1) &&
Objects.equals(transitPriorityCalculator, that.transitPriorityCalculator) &&
Objects.equals(passThroughPoints, that.passThroughPoints) &&
Objects.equals(relaxCostAtDestination, that.relaxCostAtDestination)
);
}
@Override
public int hashCode() {
return Objects.hash(
relaxC1,
transitPriorityCalculator,
passThroughPoints,
relaxCostAtDestination
);
}
@Override
public String toString() {
return ToStringBuilder
.of(MultiCriteriaRequest.class)
.addObj("relaxC1", relaxC1, RelaxFunction.NORMAL)
.addObj("transitPriorityCalculator", transitPriorityCalculator)
.addObj("passThroughPoints", passThroughPoints)
.addNum("relaxCostAtDestination", relaxCostAtDestination)
.toString();
}
public boolean includeC2() {
return hasPassThroughPoints() || transitPriorityCalculator != null;
}
public static class Builder {
private final MultiCriteriaRequest original;
private RelaxFunction relaxC1;
private RaptorTransitGroupPriorityCalculator transitPriorityCalculator;
private List passThroughPoints;
private Double relaxCostAtDestination;
public Builder(MultiCriteriaRequest original) {
this.original = original;
this.relaxC1 = original.relaxC1;
this.passThroughPoints = original.passThroughPoints;
this.transitPriorityCalculator = original.transitPriorityCalculator;
this.relaxCostAtDestination = original.relaxCostAtDestination;
}
@Nullable
public RelaxFunction relaxC1() {
return relaxC1;
}
public Builder withRelaxC1(RelaxFunction relaxC1) {
this.relaxC1 = relaxC1;
return this;
}
@Nullable
public RaptorTransitGroupPriorityCalculator transitPriorityCalculator() {
return transitPriorityCalculator;
}
public Builder withTransitPriorityCalculator(RaptorTransitGroupPriorityCalculator value) {
transitPriorityCalculator = value;
return this;
}
public List passThroughPoints() {
return passThroughPoints;
}
@Nullable
public Builder withPassThroughPoints(List points) {
// Prevent setting this to an empty list - here we use null to represent NOT_SET
passThroughPoints = (points == null || points.isEmpty()) ? List.of() : points;
return this;
}
@Nullable
@Deprecated
public Double relaxCostAtDestination() {
return relaxCostAtDestination;
}
@Deprecated
public Builder withRelaxCostAtDestination(Double value) {
relaxCostAtDestination = value;
return this;
}
public MultiCriteriaRequest build() {
var newInstance = new MultiCriteriaRequest(this);
return original.equals(newInstance) ? original : newInstance;
}
@Override
public String toString() {
return ToStringBuilder
.of(MultiCriteriaRequest.Builder.class)
.addObj("relaxC1", relaxC1)
.addObj("transitPriorityCalculator", transitPriorityCalculator)
.addObj("passThroughPoints", passThroughPoints)
.addNum("relaxCostAtDestination", relaxCostAtDestination)
.toString();
}
}
}