Try Live
Add Docs
Rankings
Pricing
Docs
Install
Theme
Install
Docs
Pricing
More...
More...
Try Live
Rankings
Enterprise
Create API Key
Add Docs
jsprit
https://github.com/graphhopper/jsprit
Admin
jsprit is a Java-based, open source toolkit for solving rich Vehicle Routing Problems and Traveling
...
Tokens:
24,846
Snippets:
205
Trust Score:
7.6
Update:
1 month ago
Context
Skills
Chat
Benchmark
89.5
Suggestions
Latest
Show doc for...
Code
Info
Show Results
Context Summary (auto-generated)
Raw
Copy
Link
# jsprit jsprit is a Java-based, open-source toolkit for solving rich Vehicle Routing Problems (VRP) and Traveling Salesman Problems (TSP). It provides a flexible, lightweight framework based on a powerful meta-heuristic algorithm that combines ruin-and-recreate principles with adaptive large neighborhood search. The library supports a wide range of problem variants including Capacitated VRP, Multiple Depot VRP, VRP with Time Windows, VRP with Pickups and Deliveries, Heterogeneous Fleet VRP, and various combinations thereof. The toolkit is designed with modularity and extensibility in mind, allowing users to define custom constraints, objective functions, and algorithm configurations. jsprit uses builder patterns throughout its API to construct immutable problem definitions, making it easy to set up complex routing scenarios. The library includes visualization tools for analyzing problems and solutions, and supports both finite and infinite fleet sizes for tactical and operational planning use cases. ## Getting Started with Maven Add jsprit to your project using Maven to access all core vehicle routing capabilities. ```xml <dependency> <groupId>com.graphhopper</groupId> <artifactId>jsprit-core</artifactId> <version>1.7.3</version> </dependency> <!-- Optional: For visualization and analysis --> <dependency> <groupId>com.graphhopper</groupId> <artifactId>jsprit-analysis</artifactId> <version>1.7.3</version> </dependency> ``` ## VehicleTypeImpl.Builder - Define Vehicle Types Create vehicle types with capacity dimensions, fixed costs, and variable costs per distance/time using the builder pattern. ```java // Create a vehicle type with capacity of 200 units and cost parameters VehicleTypeImpl vehicleType = VehicleTypeImpl.Builder.newInstance("largeVan") .addCapacityDimension(0, 200) // Index 0 = weight capacity .addCapacityDimension(1, 50) // Index 1 = volume capacity .setFixedCost(100.0) // Fixed cost per vehicle used .setCostPerDistance(1.0) // Cost per unit distance .setCostPerTransportTime(0.5) // Cost per unit time .setCostPerServiceTime(0.3) // Cost per service duration .build(); // Create a smaller vehicle type for comparison VehicleTypeImpl smallVan = VehicleTypeImpl.Builder.newInstance("smallVan") .addCapacityDimension(0, 80) .setFixedCost(50.0) .setCostPerDistance(0.8) .build(); ``` ## VehicleImpl.Builder - Create Vehicles Build vehicles with start/end locations, time windows, skills, and breaks using the fluent builder API. ```java // Create a vehicle starting at depot (10,10) with operating time window VehicleImpl vehicle = VehicleImpl.Builder.newInstance("vehicle1") .setStartLocation(Location.newInstance(10, 10)) .setEndLocation(Location.newInstance(10, 10)) // Return to depot .setType(vehicleType) .setEarliestStart(0) // Can depart at time 0 .setLatestArrival(480) // Must return by time 480 (e.g., 8 hours) .setReturnToDepot(true) .addSkill("refrigerated") // Vehicle has refrigeration capability .addSkill("forklift") .build(); // Vehicle that doesn't need to return to depot (open-ended route) VehicleImpl openVehicle = VehicleImpl.Builder.newInstance("vehicle2") .setStartLocation(Location.newInstance(20, 30)) .setType(smallVan) .setReturnToDepot(false) // End location is endogenous .build(); // Vehicle with scheduled break Break lunch = Break.Builder.newInstance("lunch") .setTimeWindow(TimeWindow.newInstance(180, 240)) // Break window .setServiceTime(30) // 30-minute break .build(); VehicleImpl vehicleWithBreak = VehicleImpl.Builder.newInstance("vehicle3") .setStartLocation(Location.newInstance(15, 15)) .setType(vehicleType) .setBreak(lunch) .build(); ``` ## Service.Builder - Define Delivery/Pickup Services Create service jobs representing single-location activities like deliveries, pickups, or service visits. ```java // Basic delivery service at customer location Service delivery1 = Service.Builder.newInstance("customer1") .setLocation(Location.newInstance(25, 35)) .addSizeDimension(0, 20) // Delivers 20 units (weight) .addSizeDimension(1, 5) // Delivers 5 units (volume) .setServiceTime(15) // Takes 15 time units to service .build(); // Service with time window constraint Service delivery2 = Service.Builder.newInstance("customer2") .setLocation(Location.newInstance(45, 68)) .addSizeDimension(0, 30) .setServiceTime(20) .setTimeWindow(TimeWindow.newInstance(60, 120)) // Must arrive 60-120 .build(); // Service with multiple time windows (customer available at different times) Service delivery3 = Service.Builder.newInstance("customer3") .setLocation(Location.newInstance(30, 50)) .addSizeDimension(0, 15) .setServiceTime(10) .addTimeWindow(TimeWindow.newInstance(0, 60)) // Morning slot .addTimeWindow(TimeWindow.newInstance(180, 240)) // Afternoon slot .build(); // Pickup job (negative demand = pickup) Pickup pickup1 = Pickup.Builder.newInstance("pickup1") .setLocation(Location.newInstance(55, 25)) .addSizeDimension(0, 25) // Picks up 25 units .setServiceTime(10) .addRequiredSkill("refrigerated") // Requires refrigerated vehicle .build(); // Service with priority (1=highest, 10=lowest, default=2) Service urgentDelivery = Service.Builder.newInstance("urgent") .setLocation(Location.newInstance(40, 40)) .addSizeDimension(0, 10) .setServiceTime(5) .setPriority(1) // High priority .build(); ``` ## Shipment.Builder - Define Pickup-Delivery Pairs Create shipment jobs that require both pickup and delivery operations at different locations. ```java // Basic shipment from pickup to delivery location Shipment shipment1 = Shipment.Builder.newInstance("shipment1") .setPickupLocation(Location.newInstance(5, 7)) .setDeliveryLocation(Location.newInstance(15, 25)) .addSizeDimension(0, 10) // Size of shipment .setPickupServiceTime(5) // Time to load .setDeliveryServiceTime(5) // Time to unload .build(); // Shipment with time windows on both pickup and delivery Shipment shipment2 = Shipment.Builder.newInstance("shipment2") .setPickupLocation(Location.newInstance(10, 20)) .setDeliveryLocation(Location.newInstance(50, 60)) .addSizeDimension(0, 15) .setPickupTimeWindow(TimeWindow.newInstance(0, 60)) // Pickup window .setDeliveryTimeWindow(TimeWindow.newInstance(120, 180)) // Delivery window .setPickupServiceTime(10) .setDeliveryServiceTime(10) .build(); // Shipment with max time in vehicle constraint (freshness/perishability) Shipment perishable = Shipment.Builder.newInstance("perishable1") .setPickupLocation(Location.newInstance(8, 12)) .setDeliveryLocation(Location.newInstance(45, 55)) .addSizeDimension(0, 20) .setMaxTimeInVehicle(60) // Must be delivered within 60 units .addRequiredSkill("refrigerated") .build(); ``` ## VehicleRoutingProblem.Builder - Assemble the Problem Combine vehicles and jobs into a complete vehicle routing problem definition. ```java // Build a basic VRP with services VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance(); // Add vehicles vrpBuilder.addVehicle(vehicle); vrpBuilder.addVehicle(openVehicle); // Add jobs vrpBuilder.addJob(delivery1); vrpBuilder.addJob(delivery2); vrpBuilder.addJob(delivery3); vrpBuilder.addJob(pickup1); vrpBuilder.addJob(shipment1); vrpBuilder.addJob(shipment2); // Set fleet size (INFINITE = can use unlimited copies of each vehicle type) vrpBuilder.setFleetSize(VehicleRoutingProblem.FleetSize.INFINITE); // Build the problem (uses Euclidean distances by default) VehicleRoutingProblem problem = vrpBuilder.build(); // For finite fleet (use exact vehicles defined) VehicleRoutingProblem finiteProblem = VehicleRoutingProblem.Builder.newInstance() .addVehicle(vehicle) .addJob(delivery1) .addJob(delivery2) .setFleetSize(VehicleRoutingProblem.FleetSize.FINITE) .build(); ``` ## Jsprit - Create and Run Algorithm Use the Jsprit factory to create an out-of-the-box algorithm and search for solutions. ```java // Create algorithm with default settings VehicleRoutingAlgorithm algorithm = Jsprit.createAlgorithm(problem); // Search for solutions Collection<VehicleRoutingProblemSolution> solutions = algorithm.searchSolutions(); // Get the best solution VehicleRoutingProblemSolution bestSolution = Solutions.bestOf(solutions); // Access solution details System.out.println("Total cost: " + bestSolution.getCost()); System.out.println("Number of routes: " + bestSolution.getRoutes().size()); System.out.println("Unassigned jobs: " + bestSolution.getUnassignedJobs().size()); // Iterate through routes for (VehicleRoute route : bestSolution.getRoutes()) { System.out.println("\nVehicle: " + route.getVehicle().getId()); System.out.println("Start: " + route.getStart().getEndTime()); for (TourActivity activity : route.getActivities()) { if (activity instanceof TourActivity.JobActivity) { TourActivity.JobActivity jobAct = (TourActivity.JobActivity) activity; System.out.println(" Job: " + jobAct.getJob().getId() + " Arrive: " + activity.getArrTime() + " End: " + activity.getEndTime()); } } System.out.println("End: " + route.getEnd().getArrTime()); } ``` ## Jsprit.Builder - Customize Algorithm Parameters Fine-tune the algorithm with custom parameters, iterations, threads, and strategies. ```java // Build algorithm with custom parameters VehicleRoutingAlgorithm customAlgorithm = Jsprit.Builder.newInstance(problem) .setProperty(Jsprit.Parameter.ITERATIONS, "5000") // More iterations .setProperty(Jsprit.Parameter.THREADS, "4") // Parallel execution .setProperty(Jsprit.Parameter.FIXED_COST_PARAM, "0.5") // Consider fixed costs .setProperty(Jsprit.Parameter.VEHICLE_SWITCH, "true") // Allow vehicle switching .setProperty(Jsprit.Parameter.CONSTRUCTION, "regret_insertion") .buildAlgorithm(); // Set maximum iterations programmatically customAlgorithm.setMaxIterations(3000); // Add termination criteria based on iterations without improvement customAlgorithm.setPrematureAlgorithmTermination( new IterationWithoutImprovementTermination(200) ); // Add time-based termination (in seconds) TimeTermination timeTermination = new TimeTermination(30.0); customAlgorithm.setPrematureAlgorithmTermination(timeTermination); customAlgorithm.addListener(timeTermination); // Run the customized algorithm Collection<VehicleRoutingProblemSolution> solutions = customAlgorithm.searchSolutions(); ``` ## Custom Transport Costs - Define Distance/Time Matrices Implement custom transport costs using distance matrices or real-world routing data. ```java // Create a custom cost matrix VehicleRoutingTransportCostsMatrix.Builder costMatrixBuilder = VehicleRoutingTransportCostsMatrix.Builder.newInstance(true); // true = symmetric // Add distances between locations (by location ID) costMatrixBuilder.addTransportDistance("depot", "customer1", 10.0); costMatrixBuilder.addTransportDistance("depot", "customer2", 15.0); costMatrixBuilder.addTransportDistance("customer1", "customer2", 8.0); // Add travel times costMatrixBuilder.addTransportTime("depot", "customer1", 12.0); costMatrixBuilder.addTransportTime("depot", "customer2", 18.0); costMatrixBuilder.addTransportTime("customer1", "customer2", 10.0); VehicleRoutingTransportCosts costMatrix = costMatrixBuilder.build(); // Use custom costs in problem VehicleRoutingProblem problem = VehicleRoutingProblem.Builder.newInstance() .setRoutingCost(costMatrix) .addVehicle(vehicle) .addJob(delivery1) .addJob(delivery2) .build(); // Or implement custom transport costs class VehicleRoutingTransportCosts customCosts = new VehicleRoutingTransportCosts() { @Override public double getTransportCost(Location from, Location to, double departureTime, Driver driver, Vehicle vehicle) { // Calculate cost based on distance and vehicle type double distance = calculateDistance(from, to); return distance * vehicle.getType().getVehicleCostParams().perDistanceUnit; } @Override public double getTransportTime(Location from, Location to, double departureTime, Driver driver, Vehicle vehicle) { // Calculate time (could include traffic patterns) return calculateDistance(from, to) / 50.0; // Assume 50 km/h } private double calculateDistance(Location from, Location to) { double dx = from.getCoordinate().getX() - to.getCoordinate().getX(); double dy = from.getCoordinate().getY() - to.getCoordinate().getY(); return Math.sqrt(dx * dx + dy * dy); } }; ``` ## StateManager and ConstraintManager - Add Custom Constraints Define custom hard and soft constraints to model complex business rules. ```java // Create state and constraint managers StateManager stateManager = new StateManager(problem); ConstraintManager constraintManager = new ConstraintManager(problem, stateManager); // Add a hard route constraint: Vehicle "van1" cannot serve "customer5" final Job restrictedJob = problem.getJobs().get("customer5"); HardRouteConstraint vehicleRestriction = new HardRouteConstraint() { @Override public boolean fulfilled(JobInsertionContext context) { if (context.getNewVehicle().getId().equals("van1")) { // Check if trying to insert restricted job or route already contains it if (context.getJob() == restrictedJob || context.getRoute().getTourActivities().servesJob(restrictedJob)) { return false; } } return true; } }; constraintManager.addConstraint(vehicleRestriction); // Add a soft route constraint: Prefer certain vehicles for certain jobs SoftRouteConstraint vehiclePreference = new SoftRouteConstraint() { @Override public double getCosts(JobInsertionContext context) { // Add penalty if preferred vehicle not used if (context.getJob().getId().startsWith("priority_") && !context.getNewVehicle().getId().equals("express_van")) { return 100.0; // Penalty for using non-preferred vehicle } return 0.0; } }; constraintManager.addConstraint(vehiclePreference); // Build algorithm with custom constraints VehicleRoutingAlgorithm algorithm = Jsprit.Builder.newInstance(problem) .setStateAndConstraintManager(stateManager, constraintManager) .buildAlgorithm(); Collection<VehicleRoutingProblemSolution> solutions = algorithm.searchSolutions(); ``` ## SolutionPrinter - Display Solution Results Print formatted solution summaries and detailed route information to console. ```java // Print concise summary SolutionPrinter.print(problem, bestSolution, SolutionPrinter.Print.CONCISE); /* Output: +--------------------------+ | problem | +---------------+----------+ | indicator | value | +---------------+----------+ | nJobs | 10 | | nServices | 8 | | nShipments | 2 | | fleetsize | INFINITE | +--------------------------+ +----------------------------------------------------------+ | solution | +---------------+------------------------------------------+ | indicator | value | +---------------+------------------------------------------+ | costs | 245.67 | | nVehicles | 3 | +----------------------------------------------------------+ */ // Print verbose output with route details SolutionPrinter.print(problem, bestSolution, SolutionPrinter.Print.VERBOSE); /* Additional output showing each route: +----------------------------------------------------------------+ | detailed solution | +---------+------------+-------------+----------+--------+--------+ | route | vehicle | activity | job | arrTime| endTime| +---------+------------+-------------+----------+--------+--------+ | 1 | vehicle1 | start | - | undef | 0 | | 1 | vehicle1 | service | cust1 | 15 | 25 | | 1 | vehicle1 | service | cust3 | 40 | 50 | | 1 | vehicle1 | end | - | 65 | undef | +---------+------------+-------------+----------+--------+--------+ */ ``` ## Plotter - Visualize Problems and Solutions Generate PNG images showing routes, customers, and depots on a 2D plot. ```java // Plot just the problem (shows locations without routes) new Plotter(problem).plot("output/problem.png", "My VRP Problem"); // Plot the solution with routes new Plotter(problem, bestSolution).plot("output/solution.png", "Optimized Routes"); // Customize plotter settings Plotter plotter = new Plotter(problem, bestSolution); plotter.setLabel(Plotter.Label.ID); // Label points with job IDs plotter.setShowFirstActivity(true); // Mark first activity in each route plotter.plot("output/labeled_solution.png", "Labeled Solution"); // Plot with size labels (shows capacity dimensions) Plotter sizePlotter = new Plotter(problem, bestSolution); sizePlotter.setLabel(Plotter.Label.SIZE); sizePlotter.plot("output/size_solution.png", "Solution with Demand Labels"); ``` ## GraphStreamViewer - Interactive Route Visualization Display an interactive, animated visualization of the routing solution using GraphStream. ```java // Create interactive viewer with animation new GraphStreamViewer(problem, bestSolution) .setRenderDelay(100) // Delay between rendering each activity (ms) .setRenderShipments(true) // Show shipment pickup-delivery connections .setGraphStreamFrameScalingFactor(2.0) .display(); // Viewer with custom settings for large problems GraphStreamViewer viewer = new GraphStreamViewer(problem, bestSolution); viewer.labelWith(GraphStreamViewer.Label.ID); viewer.setRenderDelay(50); viewer.display(); ``` ## Algorithm Listeners - Monitor Algorithm Progress Add listeners to track algorithm execution, log progress, or implement custom logic. ```java // Listen to iteration events algorithm.addListener(new IterationStartsListener() { @Override public void informIterationStarts(int iteration, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) { if (iteration % 100 == 0) { VehicleRoutingProblemSolution best = Solutions.bestOf(solutions); System.out.println("Iteration " + iteration + " - Best cost: " + best.getCost()); } } }); // Listen to algorithm completion algorithm.addListener(new AlgorithmEndsListener() { @Override public void informAlgorithmEnds(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) { System.out.println("Algorithm finished!"); System.out.println("Final solution cost: " + Solutions.bestOf(solutions).getCost()); } }); // Track search progress with chart listener (requires jsprit-analysis) AlgorithmSearchProgressChartListener chartListener = new AlgorithmSearchProgressChartListener("output/progress.png"); algorithm.addListener(chartListener); // Run algorithm with listeners Collection<VehicleRoutingProblemSolution> solutions = algorithm.searchSolutions(); ``` ## Multiple Depot VRP - Assign Jobs to Multiple Depots Model problems where vehicles operate from different depot locations. ```java // Define multiple depots by creating vehicles at different locations VehicleType type = VehicleTypeImpl.Builder.newInstance("truck") .addCapacityDimension(0, 100) .setCostPerDistance(1.0) .build(); // Depot 1 vehicles VehicleImpl depot1_v1 = VehicleImpl.Builder.newInstance("depot1_vehicle1") .setStartLocation(Location.newInstance(10, 10)) .setType(type) .build(); VehicleImpl depot1_v2 = VehicleImpl.Builder.newInstance("depot1_vehicle2") .setStartLocation(Location.newInstance(10, 10)) .setType(type) .build(); // Depot 2 vehicles VehicleImpl depot2_v1 = VehicleImpl.Builder.newInstance("depot2_vehicle1") .setStartLocation(Location.newInstance(50, 50)) .setType(type) .build(); VehicleImpl depot2_v2 = VehicleImpl.Builder.newInstance("depot2_vehicle2") .setStartLocation(Location.newInstance(50, 50)) .setType(type) .build(); // Build problem with finite fleet VehicleRoutingProblem multiDepotProblem = VehicleRoutingProblem.Builder.newInstance() .addVehicle(depot1_v1) .addVehicle(depot1_v2) .addVehicle(depot2_v1) .addVehicle(depot2_v2) .addJob(Service.Builder.newInstance("c1").setLocation(Location.newInstance(15, 20)) .addSizeDimension(0, 10).build()) .addJob(Service.Builder.newInstance("c2").setLocation(Location.newInstance(45, 55)) .addSizeDimension(0, 15).build()) // Add more jobs... .setFleetSize(VehicleRoutingProblem.FleetSize.FINITE) .build(); VehicleRoutingAlgorithm algorithm = Jsprit.createAlgorithm(multiDepotProblem); VehicleRoutingProblemSolution solution = Solutions.bestOf(algorithm.searchSolutions()); ``` ## Heterogeneous Fleet - Mix Vehicle Types Optimize fleet composition with different vehicle types having different costs and capacities. ```java // Define vehicle types with different characteristics VehicleTypeImpl smallType = VehicleTypeImpl.Builder.newInstance("small") .addCapacityDimension(0, 50) .setFixedCost(50.0) .setCostPerDistance(0.5) .build(); VehicleTypeImpl mediumType = VehicleTypeImpl.Builder.newInstance("medium") .addCapacityDimension(0, 100) .setFixedCost(100.0) .setCostPerDistance(0.8) .build(); VehicleTypeImpl largeType = VehicleTypeImpl.Builder.newInstance("large") .addCapacityDimension(0, 200) .setFixedCost(200.0) .setCostPerDistance(1.2) .build(); // Create vehicles of each type at depot Location depot = Location.newInstance(25, 25); VehicleImpl small1 = VehicleImpl.Builder.newInstance("small1") .setStartLocation(depot).setType(smallType).build(); VehicleImpl medium1 = VehicleImpl.Builder.newInstance("medium1") .setStartLocation(depot).setType(mediumType).build(); VehicleImpl large1 = VehicleImpl.Builder.newInstance("large1") .setStartLocation(depot).setType(largeType).build(); // Build problem - algorithm will optimize which vehicles to use VehicleRoutingProblem problem = VehicleRoutingProblem.Builder.newInstance() .addVehicle(small1) .addVehicle(medium1) .addVehicle(large1) .addAllJobs(createJobs()) // Your jobs .setFleetSize(VehicleRoutingProblem.FleetSize.INFINITE) // Can use multiple of each .build(); // Use algorithm that considers fixed costs VehicleRoutingAlgorithm algorithm = Jsprit.Builder.newInstance(problem) .setProperty(Jsprit.Parameter.FIXED_COST_PARAM, "1.0") // Weight for fixed costs .buildAlgorithm(); VehicleRoutingProblemSolution solution = Solutions.bestOf(algorithm.searchSolutions()); ``` ## Initial Solution - Provide Starting Point Warm-start the algorithm with an existing solution for faster convergence. ```java // Build initial routes manually VehicleRoute route1 = VehicleRoute.Builder.newInstance(vehicle) .addService(service1) .addService(service2) .build(); VehicleRoute route2 = VehicleRoute.Builder.newInstance(vehicle2) .addPickup(shipment1) .addDelivery(shipment1) .build(); // Create initial solution VehicleRoutingProblemSolution initialSolution = new VehicleRoutingProblemSolution( Arrays.asList(route1, route2), 1000.0 // Initial cost estimate ); // Add to algorithm as starting point VehicleRoutingAlgorithm algorithm = Jsprit.createAlgorithm(problem); algorithm.addInitialSolution(initialSolution); // Or add locked routes to the problem (cannot be modified by algorithm) VehicleRoutingProblem lockedProblem = VehicleRoutingProblem.Builder.newInstance() .addVehicle(vehicle) .addJob(service1) .addJob(service2) .addInitialVehicleRoute(route1) // This route is locked .build(); ``` ## Summary jsprit provides a comprehensive solution for vehicle routing optimization, supporting everything from simple delivery routes to complex multi-depot, heterogeneous fleet scenarios with time windows and pickup-delivery constraints. The library's strength lies in its flexible builder-based API that allows incremental problem construction, combined with a powerful adaptive large neighborhood search algorithm that can be customized through parameters or extended with custom constraints and objective functions. For integration into production systems, jsprit offers multiple extension points: custom transport cost implementations for real-world routing engines, constraint managers for business rules, algorithm listeners for progress monitoring, and visualization tools for solution analysis. The library works well with standard Java build tools and can be parallelized for improved performance on large-scale problems. Whether used for tactical fleet planning or operational route optimization, jsprit delivers high-quality solutions while maintaining the flexibility needed for real-world logistics applications.