All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opentripplanner.transit.raptor.rangeraptor.standard.configure.StdRangeRaptorConfig Maven / Gradle / Ivy

There is a newer version: 2.5.0
Show newest version
package org.opentripplanner.transit.raptor.rangeraptor.standard.configure;

import java.util.function.BiFunction;
import org.opentripplanner.transit.raptor.api.transit.RaptorTripSchedule;
import org.opentripplanner.transit.raptor.api.view.Heuristics;
import org.opentripplanner.transit.raptor.api.view.Worker;
import org.opentripplanner.transit.raptor.rangeraptor.RoutingStrategy;
import org.opentripplanner.transit.raptor.rangeraptor.WorkerState;
import org.opentripplanner.transit.raptor.rangeraptor.path.DestinationArrivalPaths;
import org.opentripplanner.transit.raptor.rangeraptor.path.configure.PathConfig;
import org.opentripplanner.transit.raptor.rangeraptor.standard.ArrivalTimeRoutingStrategy;
import org.opentripplanner.transit.raptor.rangeraptor.standard.ArrivedAtDestinationCheck;
import org.opentripplanner.transit.raptor.rangeraptor.standard.BestNumberOfTransfers;
import org.opentripplanner.transit.raptor.rangeraptor.standard.MinTravelDurationRoutingStrategy;
import org.opentripplanner.transit.raptor.rangeraptor.standard.StdRangeRaptorWorkerState;
import org.opentripplanner.transit.raptor.rangeraptor.standard.StdWorkerState;
import org.opentripplanner.transit.raptor.rangeraptor.standard.StopArrivalsState;
import org.opentripplanner.transit.raptor.rangeraptor.standard.besttimes.BestTimes;
import org.opentripplanner.transit.raptor.rangeraptor.standard.besttimes.BestTimesOnlyStopArrivalsState;
import org.opentripplanner.transit.raptor.rangeraptor.standard.besttimes.SimpleArrivedAtDestinationCheck;
import org.opentripplanner.transit.raptor.rangeraptor.standard.besttimes.SimpleBestNumberOfTransfers;
import org.opentripplanner.transit.raptor.rangeraptor.standard.debug.DebugStopArrivalsState;
import org.opentripplanner.transit.raptor.rangeraptor.standard.heuristics.HeuristicSearch;
import org.opentripplanner.transit.raptor.rangeraptor.standard.heuristics.HeuristicsAdapter;
import org.opentripplanner.transit.raptor.rangeraptor.standard.stoparrivals.StdStopArrivalsState;
import org.opentripplanner.transit.raptor.rangeraptor.standard.stoparrivals.StopArrivals;
import org.opentripplanner.transit.raptor.rangeraptor.standard.stoparrivals.path.EgressArrivalToPathAdapter;
import org.opentripplanner.transit.raptor.rangeraptor.standard.stoparrivals.view.StopsCursor;
import org.opentripplanner.transit.raptor.rangeraptor.transit.SearchContext;


/**
 * The responsibility of this class is to wire different standard range raptor
 * worker configurations together based on the context passed into the class.
 * There is a factory (create) method for each legal configuration.
 *
 * @param  The TripSchedule type defined by the user of the raptor API.
 */
public class StdRangeRaptorConfig {

    private final SearchContext ctx;
    private final PathConfig pathConfig;

    private BestTimes bestTimes = null;
    private StopArrivals arrivals = null;
    private ArrivedAtDestinationCheck destinationCheck = null;
    private BestNumberOfTransfers bestNumberOfTransfers = null;


    public StdRangeRaptorConfig(SearchContext context) {
        this.ctx = context;
        this.pathConfig = new PathConfig<>(context);
    }

    /**
     * Create a heuristic search using the provided callback to create the worker.
     * The callback is necessary because the heuristics MUST be created before the
     * worker, if not the heuristic can not be added to the worker lifecycle and fails.
     */
    public HeuristicSearch createHeuristicSearch(
            BiFunction, RoutingStrategy, Worker> createWorker
    ) {
        StdRangeRaptorWorkerState state = createState();
        Heuristics heuristics = createHeuristicsAdapter();
        return new HeuristicSearch<>(createWorker.apply(state, createWorkerStrategy(state)), heuristics);
    }

    public Worker createSearch(
            BiFunction, RoutingStrategy, Worker> createWorker
    ) {
        StdRangeRaptorWorkerState state = createState();
        return createWorker.apply(state, createWorkerStrategy(state));
    }


    /* private factory methods */

    private StdRangeRaptorWorkerState createState() {
        new VerifyRequestIsValid(ctx).verify();
        switch (ctx.profile()) {
            case STANDARD:
            case MIN_TRAVEL_DURATION:
                return workerState(stdStopArrivalsState());
            case BEST_TIME:
            case MIN_TRAVEL_DURATION_BEST_TIME:
                return workerState(bestTimeStopArrivalsState());
        }
        throw new IllegalArgumentException(ctx.profile().toString());
    }

    private RoutingStrategy createWorkerStrategy(StdWorkerState state) {
        switch (ctx.profile()) {
            case STANDARD:
            case BEST_TIME:
                return new ArrivalTimeRoutingStrategy<>(ctx.calculator(), state);
            case MIN_TRAVEL_DURATION:
            case MIN_TRAVEL_DURATION_BEST_TIME:
                return new MinTravelDurationRoutingStrategy<>(ctx.calculator(), state);
        }
        throw new IllegalArgumentException(ctx.profile().toString());
    }

    private Heuristics createHeuristicsAdapter() {
        assertNotNull(bestNumberOfTransfers);
        return new HeuristicsAdapter(
                bestTimes(),
                this.bestNumberOfTransfers,
                ctx.egressPaths(),
                ctx.calculator(),
                ctx.lifeCycle()
        );
    }

    private StdRangeRaptorWorkerState workerState(StopArrivalsState stopArrivalsState) {
        return new StdRangeRaptorWorkerState<>(ctx.calculator(), bestTimes(), stopArrivalsState, destinationCheck());
    }

    private BestTimesOnlyStopArrivalsState bestTimeStopArrivalsState() {
        return new BestTimesOnlyStopArrivalsState<>(bestTimes(), simpleBestNumberOfTransfers());
    }

    /**
     * Return instance if created by heuristics or null if not needed.
     */
    private SimpleBestNumberOfTransfers simpleBestNumberOfTransfers() {
        SimpleBestNumberOfTransfers value = new SimpleBestNumberOfTransfers(
                ctx.nStops(),
                ctx.roundProvider()
        );
        setBestNumberOfTransfers(value);
        return value;
    }

    /**
     * Create a Standard Range Raptor state for the given context. If debugging is enabled,
     * the stop arrival state is wrapped.
     */
    private StopArrivalsState stdStopArrivalsState() {
        StdStopArrivalsState state = new StdStopArrivalsState<>(stopArrivals(), destinationArrivalPaths());
        return wrapStopArrivalsStateWithDebugger(state);
    }

    private StopArrivalsState wrapStopArrivalsStateWithDebugger(StopArrivalsState state) {
        if (ctx.debugFactory().isDebugStopArrival()) {
            return new DebugStopArrivalsState<>(ctx.roundProvider(), ctx.debugFactory(), stopsCursor(), state);
        } else {
            return state;
        }
    }

    private StopArrivals stopArrivals() {
        if (arrivals == null) {
            arrivals = new StopArrivals<>(
                    ctx.nRounds(),
                    ctx.nStops(),
                    ctx.roundProvider()
            );
            setBestNumberOfTransfers(arrivals);
        }
        return arrivals;
    }

    private void setBestNumberOfTransfers(BestNumberOfTransfers bestNumberOfTransfers) {
        assertSetValueIsNull("bestNumberOfTransfers", this.bestNumberOfTransfers, bestNumberOfTransfers);
        this.bestNumberOfTransfers = bestNumberOfTransfers;
    }

    private StopsCursor stopsCursor() {
        // Always create new cursors
        return new StopsCursor<>(stopArrivals(), ctx.calculator(), ctx.boardSlackProvider());
    }

    private DestinationArrivalPaths destinationArrivalPaths() {
        DestinationArrivalPaths destinationArrivalPaths = pathConfig.createDestArrivalPaths(false);

        // Add egressArrivals to stops and bind them to the destination arrival paths. The
        // adapter notify the destination on each new egress stop arrival.
        EgressArrivalToPathAdapter pathsAdapter = new EgressArrivalToPathAdapter<>(
                destinationArrivalPaths,
                ctx.calculator(),
                stopsCursor(),
                ctx.lifeCycle()
        );

        // Use the  adapter to play the role of the destination arrival check
        setDestinationCheck(pathsAdapter);

        stopArrivals().setupEgressStopStates(ctx.egressPaths(), pathsAdapter);

        return destinationArrivalPaths;
    }

    private BestTimes bestTimes() {
        // Cache best times; request scope
        if (bestTimes == null) {
            bestTimes = new BestTimes(ctx.nStops(), ctx.calculator(), ctx.lifeCycle());
        }
        return bestTimes;
    }

    private ArrivedAtDestinationCheck destinationCheck() {
        // Cache best times; request scope
        if (destinationCheck == null) {
            setDestinationCheck(simpleDestinationCheck());
        }
        return destinationCheck;
    }

    private void setDestinationCheck(ArrivedAtDestinationCheck check) {
        // Cache best times; request scope
        if (destinationCheck != null) {
            throw new IllegalStateException(
                    "ArrivedAtDestinationCheck is alredy initialized: " + destinationCheck.getClass().getSimpleName()
            );
        }
        destinationCheck = check;
    }

    private SimpleArrivedAtDestinationCheck simpleDestinationCheck() {
        return new SimpleArrivedAtDestinationCheck(ctx.egressStops(), bestTimes());
    }

    private void assertSetValueIsNull(String name, Object setValue, Object newValue) {
        if (setValue != null) {
            throw new IllegalStateException(
                    "There is more than one instance of " + name + ": " +
                            newValue.getClass().getSimpleName() + ", " +
                            setValue.getClass().getSimpleName()
            );
        }
    }

    private void assertNotNull(Object value) {
        if(value == null) {
            throw new NullPointerException();
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy