From fb365036afcda655ac6b4bb93ce6149e335e1f3f Mon Sep 17 00:00:00 2001 From: Stefan Schroeder <4sschroeder@gmail.com> Date: Wed, 9 Oct 2013 14:12:47 +0200 Subject: [PATCH 01/14] internals --- .../algorithms/CreateInitialSolution.java | 20 +++++------ .../algorithms/RuinAndRecreateModule.java | 4 +-- .../src/main/java/algorithms/StateIdImpl.java | 19 ++++++++++ .../main/java/algorithms/StateManager.java | 6 ++++ .../src/main/java/algorithms/StateTypes.java | 9 +++++ .../main/java/algorithms/StateUpdates.java | 36 ++++++++++++------- .../algorithms/VehicleRoutingAlgorithms.java | 32 +++++++++++------ .../main/java/basics/algo/SearchStrategy.java | 6 +++- .../basics/algo/SolutionCostCalculator.java | 14 ++++++++ .../main/java/basics/route/VehicleRoute.java | 24 +++++++------ .../route/VehicleRouteCostCalculator.java | 2 +- .../BuildCVRPAlgoFromScratchTest.java | 20 +++++++++-- .../BuildPDVRPAlgoFromScratchTest.java | 19 ++++++++-- .../java/algorithms/GendreauPostOptTest.java | 13 ++++++- .../java/basics/algo/SearchStrategyTest.java | 15 +++++--- 15 files changed, 177 insertions(+), 62 deletions(-) create mode 100644 jsprit-core/src/main/java/algorithms/StateIdImpl.java create mode 100644 jsprit-core/src/main/java/basics/algo/SolutionCostCalculator.java diff --git a/jsprit-core/src/main/java/algorithms/CreateInitialSolution.java b/jsprit-core/src/main/java/algorithms/CreateInitialSolution.java index e0b1cd6d..b0a91b6a 100644 --- a/jsprit-core/src/main/java/algorithms/CreateInitialSolution.java +++ b/jsprit-core/src/main/java/algorithms/CreateInitialSolution.java @@ -40,6 +40,7 @@ import org.apache.log4j.Logger; import basics.Job; import basics.VehicleRoutingProblem; import basics.VehicleRoutingProblemSolution; +import basics.algo.SolutionCostCalculator; import basics.route.DriverImpl; import basics.route.TourActivities; import basics.route.Vehicle; @@ -53,15 +54,18 @@ final class CreateInitialSolution implements InitialSolutionFactory { private final InsertionStrategy insertion; + private SolutionCostCalculator solutionCostCalculator; + private boolean generateAsMuchAsRoutesAsVehiclesExist = false; public void setGenerateAsMuchAsRoutesAsVehiclesExist(boolean generateAsMuchAsRoutesAsVehiclesExist) { this.generateAsMuchAsRoutesAsVehiclesExist = generateAsMuchAsRoutesAsVehiclesExist; } - public CreateInitialSolution(InsertionStrategy insertionStrategy) { + public CreateInitialSolution(InsertionStrategy insertionStrategy, SolutionCostCalculator solutionCostCalculator) { super(); this.insertion = insertionStrategy; + this.solutionCostCalculator = solutionCostCalculator; } @Override @@ -74,17 +78,11 @@ final class CreateInitialSolution implements InitialSolutionFactory { } } insertion.insertJobs(vehicleRoutes, getUnassignedJobs(vrp)); - double totalCost = getTotalCost(vehicleRoutes); +// double totalCost = getTotalCost(vehicleRoutes); logger.info("creation done"); - return new VehicleRoutingProblemSolution(vehicleRoutes, totalCost); - } - - private double getTotalCost(List serviceProviders) { - double c = 0.0; - for(VehicleRoute a : serviceProviders){ - c += a.getCost(); - } - return c; + VehicleRoutingProblemSolution vehicleRoutingProblemSolution = new VehicleRoutingProblemSolution(vehicleRoutes, 0.0); + solutionCostCalculator.calculateCosts(vehicleRoutingProblemSolution); + return vehicleRoutingProblemSolution; } private List getUnassignedJobs(VehicleRoutingProblem vrp) { diff --git a/jsprit-core/src/main/java/algorithms/RuinAndRecreateModule.java b/jsprit-core/src/main/java/algorithms/RuinAndRecreateModule.java index b296dd0f..65e44c76 100644 --- a/jsprit-core/src/main/java/algorithms/RuinAndRecreateModule.java +++ b/jsprit-core/src/main/java/algorithms/RuinAndRecreateModule.java @@ -49,8 +49,8 @@ class RuinAndRecreateModule implements SearchStrategyModule{ public VehicleRoutingProblemSolution runAndGetSolution(VehicleRoutingProblemSolution vrpSolution) { Collection ruinedJobs = ruin.ruin(vrpSolution.getRoutes()); insertion.insertJobs(vrpSolution.getRoutes(), ruinedJobs); - double totalCost = RouteUtils.getTotalCost(vrpSolution.getRoutes()); - vrpSolution.setCost(totalCost); +// double totalCost = RouteUtils.getTotalCost(vrpSolution.getRoutes()); +// vrpSolution.setCost(totalCost); return vrpSolution; } diff --git a/jsprit-core/src/main/java/algorithms/StateIdImpl.java b/jsprit-core/src/main/java/algorithms/StateIdImpl.java new file mode 100644 index 00000000..e0945e13 --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/StateIdImpl.java @@ -0,0 +1,19 @@ +package algorithms; + +import algorithms.StateManager.StateId; + +class StateIdImpl implements StateId { + + private String name; + + public StateIdImpl(String name) { + super(); + this.name = name; + } + + public String toString(){ + return name; + } + + +} \ No newline at end of file diff --git a/jsprit-core/src/main/java/algorithms/StateManager.java b/jsprit-core/src/main/java/algorithms/StateManager.java index efd8ad1b..a69989ec 100644 --- a/jsprit-core/src/main/java/algorithms/StateManager.java +++ b/jsprit-core/src/main/java/algorithms/StateManager.java @@ -55,6 +55,12 @@ interface StateManager { } + interface StateId { + + String toString(); + + } + // Map getRouteStates(); diff --git a/jsprit-core/src/main/java/algorithms/StateTypes.java b/jsprit-core/src/main/java/algorithms/StateTypes.java index 812a4ea8..ccd115f9 100644 --- a/jsprit-core/src/main/java/algorithms/StateTypes.java +++ b/jsprit-core/src/main/java/algorithms/StateTypes.java @@ -20,7 +20,12 @@ ******************************************************************************/ package algorithms; +import algorithms.StateManager.StateId; + class StateTypes { + +// final static StateId LOAD = new StateIdImpl("load"); + final static String LOAD = "load"; final static String LOAD_AT_DEPOT = "loadAtDepot"; @@ -36,4 +41,8 @@ class StateTypes { final static String FUTURE_PICKS = "futurePicks"; final static String PAST_DELIVERIES = "pastDeliveries"; + + public static StateId createId(String stateId){ + + } } diff --git a/jsprit-core/src/main/java/algorithms/StateUpdates.java b/jsprit-core/src/main/java/algorithms/StateUpdates.java index a0cdf286..35ee94ba 100644 --- a/jsprit-core/src/main/java/algorithms/StateUpdates.java +++ b/jsprit-core/src/main/java/algorithms/StateUpdates.java @@ -56,6 +56,7 @@ import basics.route.Start; import basics.route.TourActivity; import basics.route.Vehicle; import basics.route.VehicleRoute; +import basics.route.VehicleType; class StateUpdates { @@ -97,13 +98,13 @@ class StateUpdates { // IterateRouteForwardInTime forwardInTime = new IterateRouteForwardInTime(tpCosts); // forwardInTime.addListener(new UpdateCostsAtAllLevels(actCosts, tpCosts, states)); - for(VehicleRoute route : vehicleRoutes){ - if(route.isEmpty()) continue; - route.getVehicleRouteCostCalculator().reset(); - route.getVehicleRouteCostCalculator().addOtherCost(states.getRouteState(route, StateTypes.COSTS).toDouble()); - route.getVehicleRouteCostCalculator().price(route.getVehicle()); +// for(VehicleRoute route : vehicleRoutes){ +// if(route.isEmpty()) continue; +// route.getVehicleRouteCostCalculator().reset(); +// route.getVehicleRouteCostCalculator().addOtherCost(states.getRouteState(route, StateTypes.COSTS).toDouble()); +// route.getVehicleRouteCostCalculator().price(route.getVehicle()); // forwardInTime.iterate(route); - } +// } } @@ -188,8 +189,8 @@ class StateUpdates { double transportCost = this.transportCost.getTransportCost(prevAct.getLocationId(), act.getLocationId(), startTimeAtPrevAct, vehicleRoute.getDriver(), vehicleRoute.getVehicle()); double actCost = activityCost.getActivityCost(act, timeTracker.getActArrTime(), vehicleRoute.getDriver(), vehicleRoute.getVehicle()); - vehicleRoute.getVehicleRouteCostCalculator().addTransportCost(transportCost); - vehicleRoute.getVehicleRouteCostCalculator().addActivityCost(actCost); +// vehicleRoute.getVehicleRouteCostCalculator().addTransportCost(transportCost); +// vehicleRoute.getVehicleRouteCostCalculator().addActivityCost(actCost); totalOperationCost += transportCost; totalOperationCost += actCost; @@ -206,18 +207,19 @@ class StateUpdates { double transportCost = this.transportCost.getTransportCost(prevAct.getLocationId(), vehicleRoute.getEnd().getLocationId(), startTimeAtPrevAct, vehicleRoute.getDriver(), vehicleRoute.getVehicle()); double actCost = activityCost.getActivityCost(vehicleRoute.getEnd(), timeTracker.getActEndTime(), vehicleRoute.getDriver(), vehicleRoute.getVehicle()); - vehicleRoute.getVehicleRouteCostCalculator().addTransportCost(transportCost); - vehicleRoute.getVehicleRouteCostCalculator().addActivityCost(actCost); +// vehicleRoute.getVehicleRouteCostCalculator().addTransportCost(transportCost); +// vehicleRoute.getVehicleRouteCostCalculator().addActivityCost(actCost); totalOperationCost += transportCost; totalOperationCost += actCost; + totalOperationCost += getFixCosts(); states.putRouteState(vehicleRoute, StateTypes.COSTS, new StateImpl(totalOperationCost)); //this is rather strange and likely to change - vehicleRoute.getVehicleRouteCostCalculator().price(vehicleRoute.getDriver()); - vehicleRoute.getVehicleRouteCostCalculator().price(vehicleRoute.getVehicle()); - vehicleRoute.getVehicleRouteCostCalculator().finish(); +// vehicleRoute.getVehicleRouteCostCalculator().price(vehicleRoute.getDriver()); +// vehicleRoute.getVehicleRouteCostCalculator().price(vehicleRoute.getVehicle()); +// vehicleRoute.getVehicleRouteCostCalculator().finish(); startTimeAtPrevAct = 0.0; prevAct = null; @@ -225,6 +227,14 @@ class StateUpdates { totalOperationCost = 0.0; } + private double getFixCosts() { + Vehicle vehicle = vehicleRoute.getVehicle(); + if(vehicle == null) return 0.0; + VehicleType type = vehicle.getType(); + if(type == null) return 0.0; + return type.getVehicleCostParams().fix; + } + } static class UpdateEarliestStartTimeWindowAtActLocations implements ActivityVisitor{ diff --git a/jsprit-core/src/main/java/algorithms/VehicleRoutingAlgorithms.java b/jsprit-core/src/main/java/algorithms/VehicleRoutingAlgorithms.java index 3831069d..b86be126 100644 --- a/jsprit-core/src/main/java/algorithms/VehicleRoutingAlgorithms.java +++ b/jsprit-core/src/main/java/algorithms/VehicleRoutingAlgorithms.java @@ -36,12 +36,6 @@ import org.apache.commons.configuration.XMLConfiguration; import org.apache.log4j.Logger; import algorithms.HardConstraints.ConstraintManager; -import algorithms.HardConstraints.HardTimeWindowActivityLevelConstraint; -import algorithms.StateUpdates.UpdateActivityTimes; -import algorithms.StateUpdates.UpdateCostsAtAllLevels; -import algorithms.StateUpdates.UpdateEarliestStartTimeWindowAtActLocations; -import algorithms.StateUpdates.UpdateLatestOperationStartTimeAtActLocations; -import algorithms.StateUpdates.UpdateStates; import algorithms.VehicleRoutingAlgorithms.TypedMap.AbstractKey; import algorithms.VehicleRoutingAlgorithms.TypedMap.AcceptorKey; import algorithms.VehicleRoutingAlgorithms.TypedMap.InsertionStrategyKey; @@ -68,12 +62,14 @@ import basics.algo.SearchStrategy; import basics.algo.SearchStrategy.DiscoveredSolution; import basics.algo.SearchStrategyManager; import basics.algo.SearchStrategyModule; +import basics.algo.SolutionCostCalculator; import basics.algo.TimeBreaker; import basics.algo.VariationCoefficientBreaker; import basics.algo.VehicleRoutingAlgorithmListeners.PrioritizedVRAListener; import basics.algo.VehicleRoutingAlgorithmListeners.Priority; import basics.io.AlgorithmConfig; import basics.io.AlgorithmConfigXmlReader; +import basics.route.VehicleRoute; @@ -474,7 +470,8 @@ public class VehicleRoutingAlgorithms { String name = getName(strategyConfig); SolutionAcceptor acceptor = getAcceptor(strategyConfig,vrp,algorithmListeners,definedClasses,solutionMemory); SolutionSelector selector = getSelector(strategyConfig,vrp,algorithmListeners,definedClasses); - SearchStrategy strategy = new SearchStrategy(selector, acceptor); + SolutionCostCalculator costCalculator = getCostCalculator(stateManager); + SearchStrategy strategy = new SearchStrategy(selector, acceptor, costCalculator); strategy.setName(name); List modulesConfig = strategyConfig.configurationsAt("modules.module"); for(HierarchicalConfiguration moduleConfig : modulesConfig){ @@ -532,6 +529,21 @@ public class VehicleRoutingAlgorithms { return metaAlgorithm; } + private static SolutionCostCalculator getCostCalculator(final StateManagerImpl stateManager) { + SolutionCostCalculator calc = new SolutionCostCalculator() { + + @Override + public void calculateCosts(VehicleRoutingProblemSolution solution) { + double costs = 0.0; + for(VehicleRoute route : solution.getRoutes()){ + costs += stateManager.getRouteState(route, StateTypes.COSTS).toDouble(); + } + solution.setCost(costs); + } + }; + return calc; + } + private static VehicleFleetManager createFleetManager(final VehicleRoutingProblem vrp) { if(vrp.getFleetSize().equals(FleetSize.INFINITE)){ return new InfiniteVehicles(vrp.getVehicles()); @@ -611,7 +623,7 @@ public class VehicleRoutingAlgorithms { metaAlgorithm.getAlgorithmListeners().addAll(algorithmListeners); } - private static AlgorithmStartsListener createInitialSolution(XMLConfiguration config, final VehicleRoutingProblem vrp, VehicleFleetManager vehicleFleetManager, StateManagerImpl routeStates, Set algorithmListeners, TypedMap definedClasses, ExecutorService executorService, int nuOfThreads, ConstraintManager constraintManager) { + private static AlgorithmStartsListener createInitialSolution(XMLConfiguration config, final VehicleRoutingProblem vrp, VehicleFleetManager vehicleFleetManager, final StateManagerImpl routeStates, Set algorithmListeners, TypedMap definedClasses, ExecutorService executorService, int nuOfThreads, ConstraintManager constraintManager) { List modConfigs = config.configurationsAt("construction.insertion"); if(modConfigs == null) return null; if(modConfigs.isEmpty()) return null; @@ -636,12 +648,10 @@ public class VehicleRoutingAlgorithms { @Override public void informAlgorithmStarts(VehicleRoutingProblem problem, VehicleRoutingAlgorithm algorithm, Collection solutions) { - - CreateInitialSolution createInitialSolution = new CreateInitialSolution(finalInsertionStrategy); + CreateInitialSolution createInitialSolution = new CreateInitialSolution(finalInsertionStrategy, getCostCalculator(routeStates)); createInitialSolution.setGenerateAsMuchAsRoutesAsVehiclesExist(false); VehicleRoutingProblemSolution vrpSol = createInitialSolution.createInitialSolution(vrp); solutions.add(vrpSol); - } }; diff --git a/jsprit-core/src/main/java/basics/algo/SearchStrategy.java b/jsprit-core/src/main/java/basics/algo/SearchStrategy.java index 1140f5d0..a13ba263 100644 --- a/jsprit-core/src/main/java/basics/algo/SearchStrategy.java +++ b/jsprit-core/src/main/java/basics/algo/SearchStrategy.java @@ -68,15 +68,18 @@ public class SearchStrategy { private Collection searchStrategyModules = new ArrayList(); private SolutionSelector solutionSelector; + + private SolutionCostCalculator solutionCostCalculator; private SolutionAcceptor solutionAcceptor; private String name; - public SearchStrategy(SolutionSelector solutionSelector, SolutionAcceptor solutionAcceptor) { + public SearchStrategy(SolutionSelector solutionSelector, SolutionAcceptor solutionAcceptor, SolutionCostCalculator solutionCostCalculator) { super(); this.solutionSelector = solutionSelector; this.solutionAcceptor = solutionAcceptor; + this.solutionCostCalculator = solutionCostCalculator; logger.info("initialise " + this); } @@ -126,6 +129,7 @@ public class SearchStrategy { VehicleRoutingProblemSolution newSolution = module.runAndGetSolution(lastSolution); lastSolution = newSolution; } + solutionCostCalculator.calculateCosts(lastSolution); boolean solutionAccepted = solutionAcceptor.acceptSolution(solutions, lastSolution); DiscoveredSolution discoveredSolution = new DiscoveredSolution(lastSolution, solutionAccepted, getName()); return discoveredSolution; diff --git a/jsprit-core/src/main/java/basics/algo/SolutionCostCalculator.java b/jsprit-core/src/main/java/basics/algo/SolutionCostCalculator.java new file mode 100644 index 00000000..5d7b7473 --- /dev/null +++ b/jsprit-core/src/main/java/basics/algo/SolutionCostCalculator.java @@ -0,0 +1,14 @@ +package basics.algo; + +import basics.VehicleRoutingProblemSolution; + +public interface SolutionCostCalculator { + + /** + * This modifies the solution by setting its costs
+ * solution.setCost(costs); + * @param solution + */ + public void calculateCosts(VehicleRoutingProblemSolution solution); + +} diff --git a/jsprit-core/src/main/java/basics/route/VehicleRoute.java b/jsprit-core/src/main/java/basics/route/VehicleRoute.java index 95c8f3e0..97128ce5 100644 --- a/jsprit-core/src/main/java/basics/route/VehicleRoute.java +++ b/jsprit-core/src/main/java/basics/route/VehicleRoute.java @@ -86,21 +86,10 @@ public class VehicleRoute { private VehicleRouteCostCalculator costCalculator = new DefaultVehicleRouteCostCalculator(); - public void setVehicleRouteCostCalculator(VehicleRouteCostCalculator costAccumulator){ - this.costCalculator = costAccumulator; - } - public VehicleRouteCostCalculator getVehicleRouteCostCalculator(){ return costCalculator; } - public double getCost() { - if(tourActivities.isEmpty()){ - return 0.0; - } - return costCalculator.getCosts(); - } - private VehicleRoute(VehicleRoute route){ this.start = Start.copyOf(route.getStart()); this.end = End.copyOf(route.getEnd()); @@ -192,5 +181,18 @@ public class VehicleRoute { public End getEnd() { return end; } + + @Deprecated + public void setVehicleRouteCostCalculator(VehicleRouteCostCalculator costAccumulator){ + this.costCalculator = costAccumulator; + } + + @Deprecated + public double getCost() { + if(tourActivities.isEmpty()){ + return 0.0; + } + return costCalculator.getCosts(); + } } diff --git a/jsprit-core/src/main/java/basics/route/VehicleRouteCostCalculator.java b/jsprit-core/src/main/java/basics/route/VehicleRouteCostCalculator.java index 5d956265..80ffa2aa 100644 --- a/jsprit-core/src/main/java/basics/route/VehicleRouteCostCalculator.java +++ b/jsprit-core/src/main/java/basics/route/VehicleRouteCostCalculator.java @@ -20,7 +20,7 @@ ******************************************************************************/ package basics.route; - +@Deprecated public interface VehicleRouteCostCalculator { public void addTransportCost(double cost); diff --git a/jsprit-core/src/test/java/algorithms/BuildCVRPAlgoFromScratchTest.java b/jsprit-core/src/test/java/algorithms/BuildCVRPAlgoFromScratchTest.java index 5fa6e7d3..63df0617 100644 --- a/jsprit-core/src/test/java/algorithms/BuildCVRPAlgoFromScratchTest.java +++ b/jsprit-core/src/test/java/algorithms/BuildCVRPAlgoFromScratchTest.java @@ -39,8 +39,10 @@ import basics.VehicleRoutingProblemSolution; import basics.algo.IterationStartsListener; import basics.algo.SearchStrategy; import basics.algo.SearchStrategyManager; +import basics.algo.SolutionCostCalculator; import basics.io.VrpXMLReader; import basics.route.TourActivity; +import basics.route.VehicleRoute; public class BuildCVRPAlgoFromScratchTest { @@ -73,11 +75,23 @@ public class BuildCVRPAlgoFromScratchTest { RuinRadial radial = new RuinRadial(vrp, 0.15, new JobDistanceAvgCosts(vrp.getTransportCosts())); RuinRandom random = new RuinRandom(vrp, 0.25); - SearchStrategy randomStrategy = new SearchStrategy(new SelectBest(), new AcceptNewIfBetterThanWorst(1)); + SolutionCostCalculator solutionCostCalculator = new SolutionCostCalculator() { + + @Override + public void calculateCosts(VehicleRoutingProblemSolution solution) { + double costs = 0.0; + for(VehicleRoute route : solution.getRoutes()){ + costs += stateManager.getRouteState(route, StateTypes.COSTS).toDouble(); + } + solution.setCost(costs); + } + }; + + SearchStrategy randomStrategy = new SearchStrategy(new SelectBest(), new AcceptNewIfBetterThanWorst(1), solutionCostCalculator); RuinAndRecreateModule randomModule = new RuinAndRecreateModule("randomRuin_bestInsertion", bestInsertion, random); randomStrategy.addModule(randomModule); - SearchStrategy radialStrategy = new SearchStrategy(new SelectBest(), new AcceptNewIfBetterThanWorst(1)); + SearchStrategy radialStrategy = new SearchStrategy(new SelectBest(), new AcceptNewIfBetterThanWorst(1), solutionCostCalculator); RuinAndRecreateModule radialModule = new RuinAndRecreateModule("radialRuin_bestInsertion", bestInsertion, radial); radialStrategy.addModule(radialModule); @@ -101,7 +115,7 @@ public class BuildCVRPAlgoFromScratchTest { vra.getSearchStrategyManager().addSearchStrategyModuleListener(new UpdateCostsAtRouteLevel(stateManager, vrp.getTransportCosts(), vrp.getActivityCosts())); vra.getSearchStrategyManager().addSearchStrategyModuleListener(new UpdateLoadAtRouteLevel(stateManager)); - VehicleRoutingProblemSolution iniSolution = new CreateInitialSolution(bestInsertion).createInitialSolution(vrp); + VehicleRoutingProblemSolution iniSolution = new CreateInitialSolution(bestInsertion, solutionCostCalculator).createInitialSolution(vrp); // System.out.println("ini: costs="+iniSolution.getCost()+";#routes="+iniSolution.getRoutes().size()); vra.addInitialSolution(iniSolution); diff --git a/jsprit-core/src/test/java/algorithms/BuildPDVRPAlgoFromScratchTest.java b/jsprit-core/src/test/java/algorithms/BuildPDVRPAlgoFromScratchTest.java index 65933e82..b96ce7ec 100644 --- a/jsprit-core/src/test/java/algorithms/BuildPDVRPAlgoFromScratchTest.java +++ b/jsprit-core/src/test/java/algorithms/BuildPDVRPAlgoFromScratchTest.java @@ -48,6 +48,7 @@ import basics.algo.IterationStartsListener; import basics.algo.JobInsertedListener; import basics.algo.SearchStrategy; import basics.algo.SearchStrategyManager; +import basics.algo.SolutionCostCalculator; import basics.io.VrpXMLReader; import basics.io.VrpXMLWriter; import basics.route.DeliveryActivity; @@ -91,11 +92,23 @@ public class BuildPDVRPAlgoFromScratchTest { RuinRadial radial = new RuinRadial(vrp, 0.15, new JobDistanceAvgCosts(vrp.getTransportCosts())); RuinRandom random = new RuinRandom(vrp, 0.25); - SearchStrategy randomStrategy = new SearchStrategy(new SelectBest(), new AcceptNewIfBetterThanWorst(1)); + SolutionCostCalculator solutionCostCalculator = new SolutionCostCalculator() { + + @Override + public void calculateCosts(VehicleRoutingProblemSolution solution) { + double costs = 0.0; + for(VehicleRoute route : solution.getRoutes()){ + costs += stateManager.getRouteState(route, StateTypes.COSTS).toDouble(); + } + solution.setCost(costs); + } + }; + + SearchStrategy randomStrategy = new SearchStrategy(new SelectBest(), new AcceptNewIfBetterThanWorst(1), solutionCostCalculator); RuinAndRecreateModule randomModule = new RuinAndRecreateModule("randomRuin_bestInsertion", bestInsertion, random); randomStrategy.addModule(randomModule); - SearchStrategy radialStrategy = new SearchStrategy(new SelectBest(), new AcceptNewIfBetterThanWorst(1)); + SearchStrategy radialStrategy = new SearchStrategy(new SelectBest(), new AcceptNewIfBetterThanWorst(1), solutionCostCalculator); RuinAndRecreateModule radialModule = new RuinAndRecreateModule("radialRuin_bestInsertion", bestInsertion, radial); radialStrategy.addModule(radialModule); @@ -172,7 +185,7 @@ public class BuildPDVRPAlgoFromScratchTest { bestInsertion.addListener(loadVehicleInDepot); bestInsertion.addListener(updateLoadAfterJobHasBeenInserted); - VehicleRoutingProblemSolution iniSolution = new CreateInitialSolution(bestInsertion).createInitialSolution(vrp); + VehicleRoutingProblemSolution iniSolution = new CreateInitialSolution(bestInsertion, solutionCostCalculator).createInitialSolution(vrp); // System.out.println("ini: costs="+iniSolution.getCost()+";#routes="+iniSolution.getRoutes().size()); vra.addInitialSolution(iniSolution); diff --git a/jsprit-core/src/test/java/algorithms/GendreauPostOptTest.java b/jsprit-core/src/test/java/algorithms/GendreauPostOptTest.java index 7642b043..f8234d6e 100644 --- a/jsprit-core/src/test/java/algorithms/GendreauPostOptTest.java +++ b/jsprit-core/src/test/java/algorithms/GendreauPostOptTest.java @@ -187,7 +187,7 @@ public class GendreauPostOptTest { // routes.add(new VehicleRoute(getEmptyTour(),getDriver(),getNoVehicle())); // routes.add(new VehicleRoute(getEmptyTour(),getDriver(),getNoVehicle())); - VehicleRoutingProblemSolution sol = new VehicleRoutingProblemSolution(routes, route.getCost()); + VehicleRoutingProblemSolution sol = new VehicleRoutingProblemSolution(routes, states.getRouteState(route, StateTypes.COSTS).toDouble()); assertEquals(110.0, sol.getCost(), 0.5); @@ -202,12 +202,21 @@ public class GendreauPostOptTest { postOpt.setFleetManager(fleetManager); VehicleRoutingProblemSolution newSolution = postOpt.runAndGetSolution(sol); + newSolution.setCost(getCosts(newSolution,states)); assertEquals(2,RouteUtils.getNuOfActiveRoutes(newSolution.getRoutes())); assertEquals(2,newSolution.getRoutes().size()); assertEquals(80.0,newSolution.getCost(),0.5); } + private double getCosts(VehicleRoutingProblemSolution newSolution, StateManagerImpl states) { + double c = 0.0; + for(VehicleRoute r : newSolution.getRoutes()){ + c += states.getRouteState(r, StateTypes.COSTS).toDouble(); + } + return c; + } + @Test public void whenPostOpt_optsRoutesWithMoreThanTwoJobs_oneRouteBecomesTwoRoutes(){ Collection jobs = new ArrayList(); @@ -233,6 +242,7 @@ public class GendreauPostOptTest { routes.add(route); VehicleRoutingProblemSolution sol = new VehicleRoutingProblemSolution(routes, route.getCost()); + sol.setCost(getCosts(sol,states)); assertEquals(110.0, sol.getCost(), 0.5); @@ -246,6 +256,7 @@ public class GendreauPostOptTest { postOpt.setFleetManager(fleetManager); // postOpt.setWithFix(withFixCost); VehicleRoutingProblemSolution newSolution = postOpt.runAndGetSolution(sol); + newSolution.setCost(getCosts(newSolution,states)); assertEquals(2,RouteUtils.getNuOfActiveRoutes(newSolution.getRoutes())); assertEquals(2,newSolution.getRoutes().size()); diff --git a/jsprit-core/src/test/java/basics/algo/SearchStrategyTest.java b/jsprit-core/src/test/java/basics/algo/SearchStrategyTest.java index 183f245b..abc56317 100644 --- a/jsprit-core/src/test/java/basics/algo/SearchStrategyTest.java +++ b/jsprit-core/src/test/java/basics/algo/SearchStrategyTest.java @@ -46,8 +46,9 @@ public class SearchStrategyTest { public void whenANullModule_IsAdded_throwException(){ SolutionSelector select = mock(SolutionSelector.class); SolutionAcceptor accept = mock(SolutionAcceptor.class); + SolutionCostCalculator calc = mock(SolutionCostCalculator.class); - SearchStrategy strat = new SearchStrategy(select, accept); + SearchStrategy strat = new SearchStrategy(select, accept, calc); strat.addModule(null); } @@ -56,6 +57,7 @@ public class SearchStrategyTest { public void whenStratRunsWithOneModule_runItOnes(){ SolutionSelector select = mock(SolutionSelector.class); SolutionAcceptor accept = mock(SolutionAcceptor.class); + SolutionCostCalculator calc = mock(SolutionCostCalculator.class); final VehicleRoutingProblem vrp = mock(VehicleRoutingProblem.class); final VehicleRoutingProblemSolution newSol = mock(VehicleRoutingProblemSolution.class); @@ -64,7 +66,7 @@ public class SearchStrategyTest { final Collection runs = new ArrayList(); - SearchStrategy strat = new SearchStrategy(select, accept); + SearchStrategy strat = new SearchStrategy(select, accept, calc); SearchStrategyModule mod = new SearchStrategyModule() { @Override @@ -96,6 +98,7 @@ public class SearchStrategyTest { public void whenStratRunsWithTwoModule_runItTwice(){ SolutionSelector select = mock(SolutionSelector.class); SolutionAcceptor accept = mock(SolutionAcceptor.class); + SolutionCostCalculator calc = mock(SolutionCostCalculator.class); final VehicleRoutingProblem vrp = mock(VehicleRoutingProblem.class); final VehicleRoutingProblemSolution newSol = mock(VehicleRoutingProblemSolution.class); @@ -104,7 +107,7 @@ public class SearchStrategyTest { final Collection runs = new ArrayList(); - SearchStrategy strat = new SearchStrategy(select, accept); + SearchStrategy strat = new SearchStrategy(select, accept, calc); SearchStrategyModule mod = new SearchStrategyModule() { @@ -159,6 +162,7 @@ public class SearchStrategyTest { public void whenStratRunsWithNModule_runItNTimes(){ SolutionSelector select = mock(SolutionSelector.class); SolutionAcceptor accept = mock(SolutionAcceptor.class); + SolutionCostCalculator calc = mock(SolutionCostCalculator.class); final VehicleRoutingProblem vrp = mock(VehicleRoutingProblem.class); final VehicleRoutingProblemSolution newSol = mock(VehicleRoutingProblemSolution.class); @@ -169,7 +173,7 @@ public class SearchStrategyTest { final Collection runs = new ArrayList(); - SearchStrategy strat = new SearchStrategy(select, accept); + SearchStrategy strat = new SearchStrategy(select, accept, calc); for(int i=0;i runs = new ArrayList(); - SearchStrategy strat = new SearchStrategy(select, accept); + SearchStrategy strat = new SearchStrategy(select, accept, calc); for(int i=0;i Date: Wed, 9 Oct 2013 15:53:32 +0200 Subject: [PATCH 02/14] mod solutionCalcCosts --- .../main/java/analysis/SolutionPrinter.java | 1 + .../src/main/java/algorithms/StateIdImpl.java | 19 ----------------- .../main/java/algorithms/StateManager.java | 21 ------------------- .../src/main/java/algorithms/StateTypes.java | 4 ---- 4 files changed, 1 insertion(+), 44 deletions(-) delete mode 100644 jsprit-core/src/main/java/algorithms/StateIdImpl.java diff --git a/jsprit-analysis/src/main/java/analysis/SolutionPrinter.java b/jsprit-analysis/src/main/java/analysis/SolutionPrinter.java index 01476de8..bf4b707c 100644 --- a/jsprit-analysis/src/main/java/analysis/SolutionPrinter.java +++ b/jsprit-analysis/src/main/java/analysis/SolutionPrinter.java @@ -66,6 +66,7 @@ public class SolutionPrinter { * @param solution * @param level */ + @Deprecated public static void print(VehicleRoutingProblemSolution solution, Print level){ if(level.equals(Print.CONCISE)){ print(solution); diff --git a/jsprit-core/src/main/java/algorithms/StateIdImpl.java b/jsprit-core/src/main/java/algorithms/StateIdImpl.java deleted file mode 100644 index e0945e13..00000000 --- a/jsprit-core/src/main/java/algorithms/StateIdImpl.java +++ /dev/null @@ -1,19 +0,0 @@ -package algorithms; - -import algorithms.StateManager.StateId; - -class StateIdImpl implements StateId { - - private String name; - - public StateIdImpl(String name) { - super(); - this.name = name; - } - - public String toString(){ - return name; - } - - -} \ No newline at end of file diff --git a/jsprit-core/src/main/java/algorithms/StateManager.java b/jsprit-core/src/main/java/algorithms/StateManager.java index a69989ec..b938eb0f 100644 --- a/jsprit-core/src/main/java/algorithms/StateManager.java +++ b/jsprit-core/src/main/java/algorithms/StateManager.java @@ -42,35 +42,14 @@ interface StateManager { return state; } -// public void setState(double val){ -// state=val; -// } } interface States { -// void putState(String key, State state); - State getState(String key); } - - interface StateId { - String toString(); - - } - - - -// Map getRouteStates(); - -// void put(VehicleRoute route, States states); - -// Map getActivityStates(); - -// void put(TourActivity act, States states); - State getActivityState(TourActivity act, String stateType); State getRouteState(VehicleRoute route, String stateType); diff --git a/jsprit-core/src/main/java/algorithms/StateTypes.java b/jsprit-core/src/main/java/algorithms/StateTypes.java index ccd115f9..2be93461 100644 --- a/jsprit-core/src/main/java/algorithms/StateTypes.java +++ b/jsprit-core/src/main/java/algorithms/StateTypes.java @@ -20,7 +20,6 @@ ******************************************************************************/ package algorithms; -import algorithms.StateManager.StateId; class StateTypes { @@ -42,7 +41,4 @@ class StateTypes { final static String PAST_DELIVERIES = "pastDeliveries"; - public static StateId createId(String stateId){ - - } } From 88ee91370d07e09f3d156e162ac20657b1576e65 Mon Sep 17 00:00:00 2001 From: jsprit Date: Thu, 10 Oct 2013 08:28:43 +0200 Subject: [PATCH 03/14] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5b77fca7..210e3177 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ It is lightweight and easy-to-use, and based on heuristics currently solving - Multiple Depot VRP - VRP with Time Windows - VRP with Backhauls -- VRP with Pickups and Deliveries +- VRP with Pickups and Deliveries (all Pickups and Deliveries are Depot-bound) - VRP with Heterogeneous Fleet - Time-dependent VRP - Various combination of these types From 1686b662ea1a1b2f86f073a2267c403324a40b28 Mon Sep 17 00:00:00 2001 From: jsprit Date: Thu, 10 Oct 2013 08:29:13 +0200 Subject: [PATCH 04/14] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 210e3177..5b77fca7 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ It is lightweight and easy-to-use, and based on heuristics currently solving - Multiple Depot VRP - VRP with Time Windows - VRP with Backhauls -- VRP with Pickups and Deliveries (all Pickups and Deliveries are Depot-bound) +- VRP with Pickups and Deliveries - VRP with Heterogeneous Fleet - Time-dependent VRP - Various combination of these types From 5ac21840b754b40eacb8610103f37e4bfc95e932 Mon Sep 17 00:00:00 2001 From: jsprit Date: Thu, 10 Oct 2013 08:33:00 +0200 Subject: [PATCH 05/14] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 5b77fca7..9e21f738 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,6 @@ It is lightweight and easy-to-use, and based on heuristics currently solving - Multiple Depot VRP - VRP with Time Windows - VRP with Backhauls -- VRP with Pickups and Deliveries - VRP with Heterogeneous Fleet - Time-dependent VRP - Various combination of these types From 966de5887091369796a9d96efaff720775111976 Mon Sep 17 00:00:00 2001 From: jsprit Date: Thu, 10 Oct 2013 08:34:15 +0200 Subject: [PATCH 06/14] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9e21f738..c479a7c1 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ It is lightweight and easy-to-use, and based on heuristics currently solving - Capacitated VRP - Multiple Depot VRP - VRP with Time Windows -- VRP with Backhauls +- VRP with Backhauls (pickups and deliveries from and/to depot) - VRP with Heterogeneous Fleet - Time-dependent VRP - Various combination of these types From 23c84f4b7e1f50817c132e511852ef5e09274115 Mon Sep 17 00:00:00 2001 From: jsprit Date: Thu, 10 Oct 2013 08:35:43 +0200 Subject: [PATCH 07/14] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c479a7c1..cfd9ef64 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ It is lightweight and easy-to-use, and based on heuristics currently solving - Capacitated VRP - Multiple Depot VRP - VRP with Time Windows -- VRP with Backhauls (pickups and deliveries from and/to depot) +- VRP with Backhauls* - VRP with Heterogeneous Fleet - Time-dependent VRP - Various combination of these types @@ -17,6 +17,8 @@ Additionally, jsprit can be used along with Date: Thu, 10 Oct 2013 08:36:21 +0200 Subject: [PATCH 08/14] Update README.md --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index cfd9ef64..9e21f738 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ It is lightweight and easy-to-use, and based on heuristics currently solving - Capacitated VRP - Multiple Depot VRP - VRP with Time Windows -- VRP with Backhauls* +- VRP with Backhauls - VRP with Heterogeneous Fleet - Time-dependent VRP - Various combination of these types @@ -17,8 +17,6 @@ Additionally, jsprit can be used along with Date: Thu, 10 Oct 2013 08:37:24 +0200 Subject: [PATCH 09/14] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9e21f738..8027d863 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ It is lightweight and easy-to-use, and based on heuristics currently solving - Capacitated VRP - Multiple Depot VRP - VRP with Time Windows -- VRP with Backhauls +- VRP with Backhauls (transportation from/to a depot) - VRP with Heterogeneous Fleet - Time-dependent VRP - Various combination of these types From 46a8103114c153fec8f6bac332dfd8979be09f6a Mon Sep 17 00:00:00 2001 From: jsprit Date: Thu, 10 Oct 2013 08:37:53 +0200 Subject: [PATCH 10/14] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8027d863..9e21f738 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ It is lightweight and easy-to-use, and based on heuristics currently solving - Capacitated VRP - Multiple Depot VRP - VRP with Time Windows -- VRP with Backhauls (transportation from/to a depot) +- VRP with Backhauls - VRP with Heterogeneous Fleet - Time-dependent VRP - Various combination of these types From 9e7b47d2a8c8b7bdab1fb0caead2028bab65c5d3 Mon Sep 17 00:00:00 2001 From: jsprit Date: Thu, 10 Oct 2013 08:38:59 +0200 Subject: [PATCH 11/14] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 9e21f738..3d59103a 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,8 @@ can be used, and a dynamic and interactive visualiser greatly enhances the analy ##In Development - continues improvement of code, handling and performance - stable API to easily build algorithms from scratch +- release 1.0.0 +- VRP with pickup and deliveries ##Documentation From 859559c2705859d09e1d5e86a683f69ccc60c24e Mon Sep 17 00:00:00 2001 From: jsprit Date: Thu, 10 Oct 2013 08:39:49 +0200 Subject: [PATCH 12/14] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3d59103a..cb7336bc 100644 --- a/README.md +++ b/README.md @@ -20,8 +20,8 @@ can be used, and a dynamic and interactive visualiser greatly enhances the analy ##In Development - continues improvement of code, handling and performance - stable API to easily build algorithms from scratch -- release 1.0.0 - VRP with pickup and deliveries +- release 1.0.0 ##Documentation From de54b79786cd1faa394ec1ae6dc5c61c324e7346 Mon Sep 17 00:00:00 2001 From: jsprit Date: Thu, 10 Oct 2013 11:54:30 +0200 Subject: [PATCH 13/14] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cb7336bc..bc154757 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ can be used, and a dynamic and interactive visualiser greatly enhances the analy ##In Development - continues improvement of code, handling and performance - stable API to easily build algorithms from scratch -- VRP with pickup and deliveries +- VRP with pickups and deliveries - release 1.0.0 ##Documentation From b37064ec1784741e2d970ebb4ff1e9b52d7a09cd Mon Sep 17 00:00:00 2001 From: Stefan Schroeder <4sschroeder@gmail.com> Date: Thu, 10 Oct 2013 13:59:22 +0200 Subject: [PATCH 14/14] introduce SolutionCostCalculator --- .../src/main/java/analysis/SolutionPrinter.java | 2 ++ jsprit-core/pom.xml | 1 + .../src/main/java/algorithms/StateUpdates.java | 16 ++++++++-------- .../java/basics/algo/SolutionCostCalculator.java | 2 +- .../src/main/java/basics/route/VehicleRoute.java | 2 ++ 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/jsprit-analysis/src/main/java/analysis/SolutionPrinter.java b/jsprit-analysis/src/main/java/analysis/SolutionPrinter.java index bf4b707c..77de2a5a 100644 --- a/jsprit-analysis/src/main/java/analysis/SolutionPrinter.java +++ b/jsprit-analysis/src/main/java/analysis/SolutionPrinter.java @@ -65,6 +65,8 @@ public class SolutionPrinter { * * @param solution * @param level + * + * @deprecated is not going to work anymore */ @Deprecated public static void print(VehicleRoutingProblemSolution solution, Print level){ diff --git a/jsprit-core/pom.xml b/jsprit-core/pom.xml index 39ad5986..80a1cd52 100644 --- a/jsprit-core/pom.xml +++ b/jsprit-core/pom.xml @@ -50,6 +50,7 @@ xerces xerces 2.4.0 + compile diff --git a/jsprit-core/src/main/java/algorithms/StateUpdates.java b/jsprit-core/src/main/java/algorithms/StateUpdates.java index 35ee94ba..ed3e85a8 100644 --- a/jsprit-core/src/main/java/algorithms/StateUpdates.java +++ b/jsprit-core/src/main/java/algorithms/StateUpdates.java @@ -189,8 +189,8 @@ class StateUpdates { double transportCost = this.transportCost.getTransportCost(prevAct.getLocationId(), act.getLocationId(), startTimeAtPrevAct, vehicleRoute.getDriver(), vehicleRoute.getVehicle()); double actCost = activityCost.getActivityCost(act, timeTracker.getActArrTime(), vehicleRoute.getDriver(), vehicleRoute.getVehicle()); -// vehicleRoute.getVehicleRouteCostCalculator().addTransportCost(transportCost); -// vehicleRoute.getVehicleRouteCostCalculator().addActivityCost(actCost); + vehicleRoute.getVehicleRouteCostCalculator().addTransportCost(transportCost); + vehicleRoute.getVehicleRouteCostCalculator().addActivityCost(actCost); totalOperationCost += transportCost; totalOperationCost += actCost; @@ -207,8 +207,8 @@ class StateUpdates { double transportCost = this.transportCost.getTransportCost(prevAct.getLocationId(), vehicleRoute.getEnd().getLocationId(), startTimeAtPrevAct, vehicleRoute.getDriver(), vehicleRoute.getVehicle()); double actCost = activityCost.getActivityCost(vehicleRoute.getEnd(), timeTracker.getActEndTime(), vehicleRoute.getDriver(), vehicleRoute.getVehicle()); -// vehicleRoute.getVehicleRouteCostCalculator().addTransportCost(transportCost); -// vehicleRoute.getVehicleRouteCostCalculator().addActivityCost(actCost); + vehicleRoute.getVehicleRouteCostCalculator().addTransportCost(transportCost); + vehicleRoute.getVehicleRouteCostCalculator().addActivityCost(actCost); totalOperationCost += transportCost; totalOperationCost += actCost; @@ -216,10 +216,10 @@ class StateUpdates { states.putRouteState(vehicleRoute, StateTypes.COSTS, new StateImpl(totalOperationCost)); - //this is rather strange and likely to change -// vehicleRoute.getVehicleRouteCostCalculator().price(vehicleRoute.getDriver()); -// vehicleRoute.getVehicleRouteCostCalculator().price(vehicleRoute.getVehicle()); -// vehicleRoute.getVehicleRouteCostCalculator().finish(); +// this is rather strange and likely to change + vehicleRoute.getVehicleRouteCostCalculator().price(vehicleRoute.getDriver()); + vehicleRoute.getVehicleRouteCostCalculator().price(vehicleRoute.getVehicle()); + vehicleRoute.getVehicleRouteCostCalculator().finish(); startTimeAtPrevAct = 0.0; prevAct = null; diff --git a/jsprit-core/src/main/java/basics/algo/SolutionCostCalculator.java b/jsprit-core/src/main/java/basics/algo/SolutionCostCalculator.java index 5d7b7473..0e7a148c 100644 --- a/jsprit-core/src/main/java/basics/algo/SolutionCostCalculator.java +++ b/jsprit-core/src/main/java/basics/algo/SolutionCostCalculator.java @@ -5,7 +5,7 @@ import basics.VehicleRoutingProblemSolution; public interface SolutionCostCalculator { /** - * This modifies the solution by setting its costs
+ * This assumes that the solution is modified by setting its costs
* solution.setCost(costs); * @param solution */ diff --git a/jsprit-core/src/main/java/basics/route/VehicleRoute.java b/jsprit-core/src/main/java/basics/route/VehicleRoute.java index 97128ce5..7c1bb271 100644 --- a/jsprit-core/src/main/java/basics/route/VehicleRoute.java +++ b/jsprit-core/src/main/java/basics/route/VehicleRoute.java @@ -84,8 +84,10 @@ public class VehicleRoute { private End end; + @Deprecated private VehicleRouteCostCalculator costCalculator = new DefaultVehicleRouteCostCalculator(); + @Deprecated public VehicleRouteCostCalculator getVehicleRouteCostCalculator(){ return costCalculator; }