diff --git a/jsprit-core/src/main/java/jsprit/core/problem/VehicleRoutingProblem.java b/jsprit-core/src/main/java/jsprit/core/problem/VehicleRoutingProblem.java index 56d2c28e..eb263d6f 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/VehicleRoutingProblem.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/VehicleRoutingProblem.java @@ -20,7 +20,10 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; +import java.util.List; import java.util.Map; +import java.util.Set; import jsprit.core.problem.cost.VehicleRoutingActivityCosts; import jsprit.core.problem.cost.VehicleRoutingTransportCosts; @@ -29,7 +32,9 @@ import jsprit.core.problem.job.Job; import jsprit.core.problem.job.Service; import jsprit.core.problem.job.Shipment; import jsprit.core.problem.solution.route.activity.TourActivity; +import jsprit.core.problem.vehicle.PenaltyVehicleType; import jsprit.core.problem.vehicle.Vehicle; +import jsprit.core.problem.vehicle.VehicleImpl; import jsprit.core.problem.vehicle.VehicleType; import jsprit.core.problem.vehicle.VehicleTypeImpl; import jsprit.core.util.Coordinate; @@ -79,6 +84,57 @@ public class VehicleRoutingProblem { */ public static class Builder { + /** + * Two locTypeKeys are equal if they have the same locationId and typeId + * + * @author schroeder + * + */ + private static class LocTypeKey { + String locationId; + String typeId; + + public LocTypeKey(String locationId, String typeId) { + super(); + this.locationId = locationId; + this.typeId = typeId; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + + ((locationId == null) ? 0 : locationId.hashCode()); + result = prime * result + + ((typeId == null) ? 0 : typeId.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + LocTypeKey other = (LocTypeKey) obj; + if (locationId == null) { + if (other.locationId != null) + return false; + } else if (!locationId.equals(other.locationId)) + return false; + if (typeId == null) { + if (other.typeId != null) + return false; + } else if (!typeId.equals(other.typeId)) + return false; + return true; + } + + } + /** * Returns a new instance of this builder. * @@ -138,6 +194,16 @@ public class VehicleRoutingProblem { } }; + private boolean addPenaltyVehicles = false; + + private double penaltyFactor = 1.0; + + private Double penaltyFixedCosts = null; + + /** + * @deprecated use static method .newInstance() instead + */ + @Deprecated public Builder() { jobs = new HashMap(); vehicles = new ArrayList(); @@ -169,7 +235,7 @@ public class VehicleRoutingProblem { /** * Returns the unmodifiable map of locations (mapped by their id). * - * @return + * @return map with locations */ public Map getLocationMap(){ return Collections.unmodifiableMap(coordinates); @@ -209,10 +275,10 @@ public class VehicleRoutingProblem { /** * Sets the type of fleetSize. * - *

FleetSize is either FleetSize.INFINITE or FleetSize.FINITE + *

FleetSize is either FleetSize.INFINITE or FleetSize.FINITE. By default it is FleetSize.INFINITE. * * @param fleetSize - * @return + * @return this builder */ public Builder setFleetSize(FleetSize fleetSize){ this.fleetSize = fleetSize; @@ -225,7 +291,7 @@ public class VehicleRoutingProblem { *

Note that job.getId() must be unique, i.e. no job (either it is a shipment or a service) is allowed to have an already allocated id. * * @param job - * @return + * @return this builder * @throws IllegalStateException if job is neither a shipment nor a service, or jobId has already been added. */ public Builder addJob(Job job) { @@ -254,7 +320,7 @@ public class VehicleRoutingProblem { * * * @param vehicle - * @return + * @return this builder */ public Builder addVehicle(Vehicle vehicle) { vehicles.add(vehicle); @@ -271,7 +337,7 @@ public class VehicleRoutingProblem { *

By default it is set to zero. * * @param activityCosts - * @return + * @return this builder * @see VehicleRoutingActivityCosts */ public Builder setActivityCosts(VehicleRoutingActivityCosts activityCosts){ @@ -292,9 +358,46 @@ public class VehicleRoutingProblem { logger.warn("set routing costs crowFlyDistance."); transportCosts = new CrowFlyCosts(getLocations()); } + if(addPenaltyVehicles){ + if(fleetSize.equals(FleetSize.INFINITE)){ + logger.warn("penaltyType and FleetSize.INFINITE does not make sense. thus no penalty-types are added."); + } + else{ + addPenaltyVehicles(); + } + } return new VehicleRoutingProblem(this); } + private void addPenaltyVehicles() { + Set locTypeKeys = new HashSet(); + List uniqueVehicles = new ArrayList(); + for(Vehicle v : vehicles){ + LocTypeKey key = new LocTypeKey(v.getLocationId(),v.getType().getTypeId()); + if(!locTypeKeys.contains(key)){ + uniqueVehicles.add(v); + locTypeKeys.add(key); + } + } + for(Vehicle v : uniqueVehicles){ + double fixed = v.getType().getVehicleCostParams().fix * penaltyFactor; + if(penaltyFixedCosts!=null){ + fixed = penaltyFixedCosts; + } + VehicleTypeImpl t = VehicleTypeImpl.Builder.newInstance(v.getType().getTypeId(), v.getCapacity()) + .setCostPerDistance(penaltyFactor*v.getType().getVehicleCostParams().perDistanceUnit) + .setCostPerTime(penaltyFactor*v.getType().getVehicleCostParams().perTimeUnit) + .setFixedCost(fixed) + .build(); + PenaltyVehicleType penType = new PenaltyVehicleType(t,penaltyFactor); + String vehicleId = "penaltyVehicle_" + v.getLocationId() + "_" + t.getTypeId(); + Vehicle penVehicle = VehicleImpl.Builder.newInstance(vehicleId).setEarliestStart(v.getEarliestDeparture()) + .setLatestArrival(v.getLatestArrival()).setLocationCoord(v.getCoord()).setLocationId(v.getLocationId()) + .setReturnToDepot(v.isReturnToDepot()).setType(penType).build(); + addVehicle(penVehicle); + } + } + public Builder addLocation(String id, Coordinate coord) { coordinates.put(id, coord); return this; @@ -304,7 +407,7 @@ public class VehicleRoutingProblem { * Adds a collection of jobs. * * @param jobs which is a collection of jobs that subclasses Job - * @return + * @return this builder */ public Builder addAllJobs(Collection jobs) { for(Job j : jobs){ @@ -317,7 +420,7 @@ public class VehicleRoutingProblem { * Adds a collection of vehicles. * * @param vehicles - * @return + * @return this builder */ public Builder addAllVehicles(Collection vehicles) { for(Vehicle v : vehicles){ @@ -335,17 +438,61 @@ public class VehicleRoutingProblem { return Collections.unmodifiableCollection(vehicles); } + /** + * Gets an unmodifiable collection of already added vehicle-types. + * + * @returns collection of vehicle-types + */ + public Collection getAddedVehicleTypes(){ + return Collections.unmodifiableCollection(vehicleTypes); + } + /** * Adds constraint to problem. * * @param constraint - * @return + * @return this builder */ public Builder addConstraint(jsprit.core.problem.constraint.Constraint constraint){ constraints.add(constraint); return this; } + /** + * Adds penaltyVehicles, i.e. for every unique vehicle-location and type combination a penalty-vehicle is constructed having penaltyFactor times higher fixed and variable costs + * (see .addPenaltyVehicles(double penaltyFactor, double penaltyFixedCosts) if fixed costs = 0.0). + * + *

This only makes sense for FleetSize.FINITE. Thus, penaltyVehicles are only added if is FleetSize.FINITE. + *

The id of penaltyVehicles is constructed as follows vehicleId = "penaltyVehicle" + "_" + {locationId} + "_" + {typeId}. + *

By default: no penalty-vehicles are added + * + * @param penaltyFactor + * @return this builder + */ + public Builder addPenaltyVehicles(double penaltyFactor){ + this.addPenaltyVehicles = true; + this.penaltyFactor = penaltyFactor; + return this; + } + + /** + * Adds penaltyVehicles, i.e. for every unique vehicle-location and type combination a penalty-vehicle is constructed having penaltyFactor times higher fixed and variable costs. + *

This method takes penaltyFixedCosts as absolute value in contrary to the method without penaltyFixedCosts where fixedCosts is the product of penaltyFactor and typeFixedCosts. + *

This only makes sense for FleetSize.FINITE. Thus, penaltyVehicles are only added if is FleetSize.FINITE. + *

The id of penaltyVehicles is constructed as follows vehicleId = "penaltyVehicle" + "_" + {locationId} + "_" + {typeId}. + *

By default: no penalty-vehicles are added + * + * @param penaltyFactor + * @param penaltyFixedCosts which is an absolute penaltyValue (in contrary to penaltyFactor) + * @return this builder + */ + public Builder addPenaltyVehicles(double penaltyFactor, double penaltyFixedCosts){ + this.addPenaltyVehicles = true; + this.penaltyFactor = penaltyFactor; + this.penaltyFixedCosts = penaltyFixedCosts; + return this; + } + /** * Returns an unmodifiable collection of already added jobs. * diff --git a/jsprit-core/src/main/java/jsprit/core/problem/vehicle/FiniteFleetManagerFactory.java b/jsprit-core/src/main/java/jsprit/core/problem/vehicle/FiniteFleetManagerFactory.java index 51a783a0..6fa3e180 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/vehicle/FiniteFleetManagerFactory.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/vehicle/FiniteFleetManagerFactory.java @@ -27,7 +27,6 @@ public class FiniteFleetManagerFactory implements VehicleFleetManagerFactory{ private Collection vehicles; - /** * Constucts the factory. * @@ -40,9 +39,14 @@ public class FiniteFleetManagerFactory implements VehicleFleetManagerFactory{ /** * Creates the finite fleetmanager. + * + * @return VehicleFleetManager + * @throws IllegalStateManager if vehicles == null or vehicles.isEmpty() */ @Override public VehicleFleetManager createFleetManager() { + if(vehicles == null) throw new IllegalStateException("vehicles is null. this must not be."); + if(vehicles.isEmpty()) throw new IllegalStateException("vehicle-collection is empty. this must not be"); return new VehicleFleetManagerImpl(vehicles); } diff --git a/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleImpl.java b/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleImpl.java index 2692a24d..3f40b3f1 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleImpl.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleImpl.java @@ -94,12 +94,14 @@ public class VehicleImpl implements Vehicle { } /** - * Sets the {@link VehicleType}. + * Sets the {@link VehicleType}.
* * @param type + * @throws IllegalStateException if type is null * @return this builder */ public Builder setType(VehicleType type){ + if(type==null) throw new IllegalStateException("type cannot be null."); this.type = type; return this; } @@ -166,6 +168,9 @@ public class VehicleImpl implements Vehicle { /** * Builds and returns the vehicle. * + *

if {@link VehicleType} is not set, default vehicle-type is set with id="default" and + * capacity=0 + * * @return vehicle * @throw IllegalStateException if both locationId and locationCoord is not set */ @@ -189,6 +194,8 @@ public class VehicleImpl implements Vehicle { /** * Returns empty/noVehicle which is a vehicle having no capacity, no type and no reasonable id. * + *

NoVehicle has id="noVehicle" and extends {@link VehicleImpl} + * * @return emptyVehicle */ public static NoVehicle createNoVehicle(){ @@ -219,9 +226,14 @@ public class VehicleImpl implements Vehicle { returnToDepot = builder.returnToDepot; } + /** + * Returns String with attributes of this vehicle + * + *

String has the following format [attr1=val1][attr2=val2]...[attrn=valn] + */ @Override public String toString() { - return "[id="+id+"][type="+type+"][locationId="+locationId+"][coord=" + coord + "]"; + return "[id="+id+"][type="+type+"][locationId="+locationId+"][coord=" + coord + "][isReturnToDepot=" + isReturnToDepot() + "]"; } public Coordinate getCoord() { diff --git a/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleType.java b/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleType.java index efd03674..f2464aaf 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleType.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleType.java @@ -19,17 +19,49 @@ package jsprit.core.problem.vehicle; import jsprit.core.problem.Capacity; import jsprit.core.problem.vehicle.VehicleTypeImpl.VehicleCostParams; - +/** + * Basic interface for vehicle-type-data. + * + * @author schroeder + * + */ public interface VehicleType { + /** + * Returns typeId. + * + * @return typeId + */ public String getTypeId(); + /** + * Returns capacity. + * + *

In future versions there will be a capacity-object with an arbitrary number of capacity dimensions. (stefan,11.01.14) + * + * @return cap + */ public int getCapacity(); + /** + * Returns capacity dimensions. + * + * @return {@link Capacity} + */ public Capacity getCapacityDimensions(); + /** + * Returns maximum velocity of this vehicle-type. + * + * @return max velocity + */ public double getMaxVelocity(); + /** + * Return the cost-parameter of this vehicle-type. + * + * @return parameter + */ public VehicleCostParams getVehicleCostParams(); } diff --git a/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleTypeImpl.java b/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleTypeImpl.java index 8103a8ac..a1e1bda2 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleTypeImpl.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleTypeImpl.java @@ -16,17 +16,31 @@ ******************************************************************************/ package jsprit.core.problem.vehicle; + import jsprit.core.problem.Capacity; - +/** + * Implementation of {@link VehicleType}. + * + *

Two vehicle-types are equal if they have the same typeId. + * + * @author schroeder + * + */ public class VehicleTypeImpl implements VehicleType { + /** + * CostParameter consisting of fixed cost parameter, time-based cost parameter and distance-based cost parameter. + * + * @author schroeder + * + */ public static class VehicleCostParams { public static VehicleTypeImpl.VehicleCostParams newInstance(double fix, double perTimeUnit,double perDistanceUnit){ return new VehicleCostParams(fix, perTimeUnit, perDistanceUnit); } - + public final double fix; public final double perTimeUnit; public final double perDistanceUnit; @@ -44,10 +58,28 @@ public class VehicleTypeImpl implements VehicleType { } } - + /** + * Builder that builds the vehicle-type. + * + * @author schroeder + * + */ public static class Builder{ + /** + * Returns a new instance. + * + *

Input parameters are id and capacity. Note that two vehicle-types are equal + * if they have the same vehicleId. + * + * @param id + * @param capacity + * @return the vehicleType builder + * @throws IllegalStateException if capacity is smaller than zero or id is null + */ public static VehicleTypeImpl.Builder newInstance(String id, int capacity){ + if(capacity < 0) throw new IllegalStateException("capacity cannot be smaller than zero"); + if(id == null) throw new IllegalStateException("typeId must be null"); Builder builder = new Builder(id,capacity); builder.addCapacityDimension(0, capacity); return builder; @@ -72,7 +104,13 @@ public class VehicleTypeImpl implements VehicleType { private Capacity capacityDimensions; - public Builder(String id, int capacity) { + /** + * Constructs the builder. + * + * @param id + * @param capacity + */ + private Builder(String id, int capacity) { super(); this.id = id; this.capacity = capacity; @@ -82,14 +120,68 @@ public class VehicleTypeImpl implements VehicleType { this.id = id; } - public VehicleTypeImpl.Builder setMaxVelocity(double inMeterPerSeconds){ this.maxVelo = inMeterPerSeconds; return this; } + /** + * Sets the maximum velocity this vehicle-type can go [in meter per seconds]. + * + * @param inMeterPerSeconds + * @return this builder + * @throws IllegalStateException if velocity is smaller than zero + */ + public VehicleTypeImpl.Builder setMaxVelocity(double inMeterPerSeconds){ + if(inMeterPerSeconds < 0.0) throw new IllegalStateException("velocity cannot be smaller than zero"); + this.maxVelo = inMeterPerSeconds; return this; + } - public VehicleTypeImpl.Builder setFixedCost(double fixedCost) { this.fixedCost = fixedCost; return this; } + /** + * Sets the fixed costs of the vehicle-type. + * + *

by default it is 0. + * + * @param fixedCost + * @return this builder + * @throws IllegalStateException if fixedCost is smaller than zero + */ + public VehicleTypeImpl.Builder setFixedCost(double fixedCost) { + if(fixedCost < 0.0) throw new IllegalStateException("fixed costs cannot be smaller than zero"); + this.fixedCost = fixedCost; + return this; + } - public VehicleTypeImpl.Builder setCostPerDistance(double perDistance){ this.perDistance = perDistance; return this; } + /** + * Sets the cost per distance unit, for instance € per meter. + * + *

by default it is 1.0 + * + * @param perDistance + * @return this builder + * @throws IllegalStateException if perDistance is smaller than zero + */ + public VehicleTypeImpl.Builder setCostPerDistance(double perDistance){ + if(perDistance < 0.0) throw new IllegalStateException("cost per distance must not be smaller than zero"); + this.perDistance = perDistance; + return this; + } - public VehicleTypeImpl.Builder setCostPerTime(double perTime){ this.perTime = perTime; return this; } + /** + * Sets cost per time unit, for instance € per second. + * + *

by default it is 0.0 + * + * @param perTime + * @return this builder + * @throws IllegalStateException if costPerTime is smaller than zero + */ + public VehicleTypeImpl.Builder setCostPerTime(double perTime){ + if(perTime < 0.0) throw new IllegalStateException(); + this.perTime = perTime; + return this; + } + /** + * Builds the vehicle-type. + * + * @return VehicleTypeImpl + */ public VehicleTypeImpl build(){ capacityDimensions = capacityBuilder.build(); return new VehicleTypeImpl(this); @@ -112,6 +204,9 @@ public class VehicleTypeImpl implements VehicleType { return result; } + /** + * Two vehicle-types are equal if they have the same vehicleId. + */ @Override public boolean equals(Object obj) { if (this == obj) @@ -135,9 +230,10 @@ public class VehicleTypeImpl implements VehicleType { private final VehicleTypeImpl.VehicleCostParams vehicleCostParams; - private double maxVelocity; - - private Capacity capacityDimensions; + private final Capacity capacityDimensions; + + private final double maxVelocity; + /** * @deprecated use builder instead @@ -147,6 +243,11 @@ public class VehicleTypeImpl implements VehicleType { return new VehicleTypeImpl(typeId, capacity, para); } + /** + * priv constructor constructing vehicle-type + * + * @param builder + */ private VehicleTypeImpl(VehicleTypeImpl.Builder builder){ typeId = builder.id; capacity = builder.capacity; @@ -155,13 +256,21 @@ public class VehicleTypeImpl implements VehicleType { capacityDimensions = builder.capacityDimensions; } + /** + * @deprecated use Builder.newInstance(...) instead. + * + * @param typeId + * @param capacity + * @param vehicleCostParams + */ + @Deprecated public VehicleTypeImpl(String typeId, int capacity,VehicleTypeImpl.VehicleCostParams vehicleCostParams) { super(); this.typeId = typeId; this.capacity = capacity; this.vehicleCostParams = vehicleCostParams; - capacityDimensions = Capacity.Builder.newInstance().addDimension(0, capacity).build(); - + this.capacityDimensions = Capacity.Builder.newInstance().addDimension(0, capacity).build(); + this.maxVelocity = Double.MAX_VALUE; } /* (non-Javadoc) diff --git a/jsprit-core/src/test/java/jsprit/core/problem/VehicleRoutingProblemTest.java b/jsprit-core/src/test/java/jsprit/core/problem/VehicleRoutingProblemTest.java index f2038953..fb2ce5b2 100644 --- a/jsprit-core/src/test/java/jsprit/core/problem/VehicleRoutingProblemTest.java +++ b/jsprit-core/src/test/java/jsprit/core/problem/VehicleRoutingProblemTest.java @@ -17,6 +17,8 @@ package jsprit.core.problem; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -36,6 +38,7 @@ import jsprit.core.problem.job.Shipment; import jsprit.core.problem.solution.route.activity.TourActivity; import jsprit.core.problem.vehicle.Vehicle; import jsprit.core.problem.vehicle.VehicleImpl; +import jsprit.core.problem.vehicle.VehicleType; import jsprit.core.problem.vehicle.VehicleTypeImpl; import org.junit.Test; @@ -278,5 +281,194 @@ public class VehicleRoutingProblemTest { VehicleRoutingProblem problem = builder.build(); assertEquals(4.0,problem.getTransportCosts().getTransportCost("", "", 0.0, null, null),0.01); } + + @Test + public void whenAddingAVehicle_getAddedVehicleTypesShouldReturnItsType(){ + VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); + VehicleType type = VehicleTypeImpl.Builder.newInstance("type", 0).build(); + Vehicle vehicle = VehicleImpl.Builder.newInstance("v").setLocationId("loc").setType(type).build(); + builder.addVehicle(vehicle); + + assertEquals(1,builder.getAddedVehicleTypes().size()); + assertEquals(type,builder.getAddedVehicleTypes().iterator().next()); + + } + + @Test + public void whenAddingTwoVehicleWithSameType_getAddedVehicleTypesShouldReturnOnlyOneType(){ + VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); + VehicleType type = VehicleTypeImpl.Builder.newInstance("type", 0).build(); + Vehicle vehicle = VehicleImpl.Builder.newInstance("v").setLocationId("loc").setType(type).build(); + Vehicle vehicle2 = VehicleImpl.Builder.newInstance("v").setLocationId("loc").setType(type).build(); + + builder.addVehicle(vehicle); + builder.addVehicle(vehicle2); + + assertEquals(1,builder.getAddedVehicleTypes().size()); + assertEquals(type,builder.getAddedVehicleTypes().iterator().next()); + } + @Test + public void whenAddingTwoVehicleWithDiffType_getAddedVehicleTypesShouldReturnTheseType(){ + VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); + VehicleType type = VehicleTypeImpl.Builder.newInstance("type", 0).build(); + VehicleType type2 = VehicleTypeImpl.Builder.newInstance("type2", 0).build(); + + Vehicle vehicle = VehicleImpl.Builder.newInstance("v").setLocationId("loc").setType(type).build(); + Vehicle vehicle2 = VehicleImpl.Builder.newInstance("v").setLocationId("loc").setType(type2).build(); + + builder.addVehicle(vehicle); + builder.addVehicle(vehicle2); + + assertEquals(2,builder.getAddedVehicleTypes().size()); + + } + + @Test + public void whenSettingAddPenaltyVehicleOptions_itShouldAddPenaltyVehicle(){ + VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); + VehicleType type = VehicleTypeImpl.Builder.newInstance("type", 0).build(); + Vehicle vehicle = VehicleImpl.Builder.newInstance("v").setLocationId("loc").setType(type).build(); + + builder.addVehicle(vehicle); + builder.setFleetSize(FleetSize.FINITE); + builder.addPenaltyVehicles(3.0); + + VehicleRoutingProblem vrp = builder.build(); + + assertEquals(2,vrp.getVehicles().size()); + + boolean penaltyVehicleInCollection = false; + for(Vehicle v : vrp.getVehicles()){ + if(v.getId().equals("penaltyVehicle_loc_type")) penaltyVehicleInCollection = true; + } + assertTrue(penaltyVehicleInCollection); + + } + + @Test + public void whenSettingAddPenaltyVehicleOptionsAndFleetSizeIsInfinite_noPenaltyVehicleIsAdded(){ + VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); + VehicleType type = VehicleTypeImpl.Builder.newInstance("type", 0).build(); + Vehicle vehicle = VehicleImpl.Builder.newInstance("v").setLocationId("loc").setType(type).build(); + + builder.addVehicle(vehicle); + builder.addPenaltyVehicles(3.0); + + VehicleRoutingProblem vrp = builder.build(); + + assertEquals(1,vrp.getVehicles().size()); + + boolean penaltyVehicleInCollection = false; + for(Vehicle v : vrp.getVehicles()){ + if(v.getId().equals("penaltyVehicle_loc_type")) penaltyVehicleInCollection = true; + } + assertFalse(penaltyVehicleInCollection); + + } + + @Test + public void whenSettingAddPenaltyVehicleOptionsAndTwoVehiclesWithSameLocationAndType_onlyOnePenaltyVehicleIsAdded(){ + VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); + VehicleType type = VehicleTypeImpl.Builder.newInstance("type", 0).build(); + Vehicle vehicle = VehicleImpl.Builder.newInstance("v").setLocationId("loc").setType(type).build(); + Vehicle vehicle2 = VehicleImpl.Builder.newInstance("v2").setLocationId("loc").setType(type).build(); + + builder.addVehicle(vehicle); + builder.addVehicle(vehicle2); + builder.setFleetSize(FleetSize.FINITE); + builder.addPenaltyVehicles(3.0); + + VehicleRoutingProblem vrp = builder.build(); + + assertEquals(3,vrp.getVehicles().size()); + + boolean penaltyVehicleInCollection = false; + for(Vehicle v : vrp.getVehicles()){ + if(v.getId().equals("penaltyVehicle_loc_type")) penaltyVehicleInCollection = true; + } + assertTrue(penaltyVehicleInCollection); + + } + + @Test + public void whenSettingAddPenaltyVehicleOptionsWithAbsoluteFixedCostsAndTwoVehiclesWithSameLocationAndType_onePenaltyVehicleIsAddedWithTheCorrectPenaltyFixedCosts(){ + VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); + VehicleType type = VehicleTypeImpl.Builder.newInstance("type", 0).build(); + Vehicle vehicle = VehicleImpl.Builder.newInstance("v").setLocationId("loc").setType(type).build(); + Vehicle vehicle2 = VehicleImpl.Builder.newInstance("v2").setLocationId("loc").setType(type).build(); + + builder.addVehicle(vehicle); + builder.addVehicle(vehicle2); + builder.setFleetSize(FleetSize.FINITE); + builder.addPenaltyVehicles(3.0,10000); + + VehicleRoutingProblem vrp = builder.build(); + + assertEquals(3,vrp.getVehicles().size()); + + double fix = 0.0; + for(Vehicle v : vrp.getVehicles()){ + if(v.getId().equals("penaltyVehicle_loc_type")) { + fix = v.getType().getVehicleCostParams().fix; + } + } + assertEquals(10000,fix,0.01); + + } + + @Test + public void whenSettingAddPenaltyVehicleOptionsAndTwoVehiclesWithDiffLocationAndType_twoPenaltyVehicleIsAdded(){ + VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); + VehicleType type = VehicleTypeImpl.Builder.newInstance("type", 0).build(); + Vehicle vehicle = VehicleImpl.Builder.newInstance("v").setLocationId("loc").setType(type).build(); + Vehicle vehicle2 = VehicleImpl.Builder.newInstance("v2").setLocationId("loc2").setType(type).build(); + + builder.addVehicle(vehicle); + builder.addVehicle(vehicle2); + builder.setFleetSize(FleetSize.FINITE); + builder.addPenaltyVehicles(3.0); + + VehicleRoutingProblem vrp = builder.build(); + + assertEquals(4,vrp.getVehicles().size()); + + boolean penaltyVehicleInCollection = false; + boolean anotherPenVehInCollection = false; + for(Vehicle v : vrp.getVehicles()){ + if(v.getId().equals("penaltyVehicle_loc_type")) penaltyVehicleInCollection = true; + if(v.getId().equals("penaltyVehicle_loc2_type")) anotherPenVehInCollection = true; + } + assertTrue(penaltyVehicleInCollection); + assertTrue(anotherPenVehInCollection); + + } + + @Test + public void whenSettingAddPenaltyVehicleOptionsAndTwoVehiclesWithSameLocationButDiffType_twoPenaltyVehicleIsAdded(){ + VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); + VehicleType type = VehicleTypeImpl.Builder.newInstance("type", 0).build(); + VehicleType type2 = VehicleTypeImpl.Builder.newInstance("type2", 0).build(); + Vehicle vehicle = VehicleImpl.Builder.newInstance("v").setLocationId("loc").setType(type).build(); + Vehicle vehicle2 = VehicleImpl.Builder.newInstance("v2").setLocationId("loc").setType(type2).build(); + + builder.addVehicle(vehicle); + builder.addVehicle(vehicle2); + builder.setFleetSize(FleetSize.FINITE); + builder.addPenaltyVehicles(3.0); + + VehicleRoutingProblem vrp = builder.build(); + + assertEquals(4,vrp.getVehicles().size()); + + boolean penaltyVehicleInCollection = false; + boolean anotherPenVehInCollection = false; + for(Vehicle v : vrp.getVehicles()){ + if(v.getId().equals("penaltyVehicle_loc_type")) penaltyVehicleInCollection = true; + if(v.getId().equals("penaltyVehicle_loc_type2")) anotherPenVehInCollection = true; + } + assertTrue(penaltyVehicleInCollection); + assertTrue(anotherPenVehInCollection); + + } } diff --git a/jsprit-core/src/test/java/jsprit/core/problem/vehicle/FiniteVehicleFleetManagerFactoryTest.java b/jsprit-core/src/test/java/jsprit/core/problem/vehicle/FiniteVehicleFleetManagerFactoryTest.java new file mode 100644 index 00000000..bc81c950 --- /dev/null +++ b/jsprit-core/src/test/java/jsprit/core/problem/vehicle/FiniteVehicleFleetManagerFactoryTest.java @@ -0,0 +1,13 @@ +package jsprit.core.problem.vehicle; + +import org.junit.Test; + +public class FiniteVehicleFleetManagerFactoryTest { + + @Test + public void whenFiniteVehicleManagerIsCreated_itShouldReturnCorrectManager(){ +// VehicleFleetManager vfm = new FiniteFleetManagerFactory(Arrays.asList(mock(Vehicle.class))).createFleetManager(); + + } + +} diff --git a/jsprit-core/src/test/java/jsprit/core/problem/vehicle/TestVehicleFleetManager.java b/jsprit-core/src/test/java/jsprit/core/problem/vehicle/TestVehicleFleetManagerImpl.java similarity index 98% rename from jsprit-core/src/test/java/jsprit/core/problem/vehicle/TestVehicleFleetManager.java rename to jsprit-core/src/test/java/jsprit/core/problem/vehicle/TestVehicleFleetManagerImpl.java index 52b636b3..6833be64 100644 --- a/jsprit-core/src/test/java/jsprit/core/problem/vehicle/TestVehicleFleetManager.java +++ b/jsprit-core/src/test/java/jsprit/core/problem/vehicle/TestVehicleFleetManagerImpl.java @@ -28,7 +28,7 @@ import jsprit.core.problem.vehicle.VehicleImpl; import jsprit.core.problem.vehicle.VehicleTypeImpl; import junit.framework.TestCase; -public class TestVehicleFleetManager extends TestCase{ +public class TestVehicleFleetManagerImpl extends TestCase{ VehicleFleetManager fleetManager; diff --git a/jsprit-core/src/test/java/jsprit/core/problem/vehicle/VehicleImplTest.java b/jsprit-core/src/test/java/jsprit/core/problem/vehicle/VehicleImplTest.java index 8c741407..2876946a 100644 --- a/jsprit-core/src/test/java/jsprit/core/problem/vehicle/VehicleImplTest.java +++ b/jsprit-core/src/test/java/jsprit/core/problem/vehicle/VehicleImplTest.java @@ -1,7 +1,102 @@ package jsprit.core.problem.vehicle; +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; +import jsprit.core.problem.vehicle.VehicleImpl.NoVehicle; +import jsprit.core.util.Coordinate; + +import org.junit.Test; + + public class VehicleImplTest { + @Test + public void whenSettingTypeWithBuilder_typeShouldBeSet(){ + VehicleType type = mock(VehicleType.class); + Vehicle v = VehicleImpl.Builder.newInstance("v").setLocationId("loc").setType(type).build(); + assertEquals(type,v.getType()); + } + @Test(expected=IllegalStateException.class) + public void whenTypeIsNull_itThrowsIllegalStateException(){ + @SuppressWarnings("unused") + Vehicle v = VehicleImpl.Builder.newInstance("v").setLocationId("loc").setType(null).build(); + } + + @Test + public void whenTypeIsNotSet_defaultTypeIsSet(){ + Vehicle v = VehicleImpl.Builder.newInstance("v").setLocationId("loc").build(); + assertEquals("default",v.getType().getTypeId()); + assertEquals(0,v.getType().getCapacity()); + } + + @Test(expected=IllegalStateException.class) + public void whenVehicleIsBuiltWithoutSettingNeitherLocationNorCoord_itThrowsAnIllegalStateException(){ + @SuppressWarnings("unused") + Vehicle v = VehicleImpl.Builder.newInstance("v").build(); + } + + @Test + public void whenVehicleIsBuiltAndReturnToDepotFlagIsNotSet_itShouldReturnToDepot(){ + Vehicle v = VehicleImpl.Builder.newInstance("v").setLocationId("loc").build(); + assertTrue(v.isReturnToDepot()); + } + + @Test + public void whenVehicleIsBuiltToReturnToDepot_itShouldReturnToDepot(){ + Vehicle v = VehicleImpl.Builder.newInstance("v").setReturnToDepot(true).setLocationId("loc").build(); + assertTrue(v.isReturnToDepot()); + } + + @Test + public void whenVehicleIsBuiltToNotReturnToDepot_itShouldNotReturnToDepot(){ + Vehicle v = VehicleImpl.Builder.newInstance("v").setReturnToDepot(false).setLocationId("loc").build(); + assertFalse(v.isReturnToDepot()); + } + + @Test + public void whenVehicleIsBuiltWithLocation_itShouldHvTheCorrectLocation(){ + Vehicle v = VehicleImpl.Builder.newInstance("v").setLocationId("loc").build(); + assertEquals("loc",v.getLocationId()); + } + + @Test + public void whenVehicleIsBuiltWithCoord_itShouldHvTheCorrectCoord(){ + Vehicle v = VehicleImpl.Builder.newInstance("v").setLocationCoord(Coordinate.newInstance(1, 2)).build(); + assertEquals(1.0,v.getCoord().getX(),0.01); + assertEquals(2.0,v.getCoord().getY(),0.01); + } + + @Test + public void whenVehicleIsBuiltAndEarliestStartIsNotSet_itShouldSetTheDefaultOfZero(){ + Vehicle v = VehicleImpl.Builder.newInstance("v").setLocationCoord(Coordinate.newInstance(1, 2)).build(); + assertEquals(0.0,v.getEarliestDeparture(),0.01); + } + + @Test + public void whenVehicleIsBuiltAndEarliestStartSet_itShouldBeSetCorrectly(){ + Vehicle v = VehicleImpl.Builder.newInstance("v").setEarliestStart(10.0).setLocationCoord(Coordinate.newInstance(1, 2)).build(); + assertEquals(10.0,v.getEarliestDeparture(),0.01); + } + + @Test + public void whenVehicleIsBuiltAndLatestArrivalIsNotSet_itShouldSetDefaultOfDoubleMaxValue(){ + Vehicle v = VehicleImpl.Builder.newInstance("v").setLocationCoord(Coordinate.newInstance(1, 2)).build(); + assertEquals(Double.MAX_VALUE,v.getLatestArrival(),0.01); + } + + @Test + public void whenVehicleIsBuiltAndLatestArrivalIsSet_itShouldBeSetCorrectly(){ + Vehicle v = VehicleImpl.Builder.newInstance("v").setLatestArrival(30.0).setLocationCoord(Coordinate.newInstance(1, 2)).build(); + assertEquals(30.0,v.getLatestArrival(),0.01); + } + + @Test + public void whenNoVehicleIsCreate_itShouldHvTheCorrectId(){ + Vehicle v = VehicleImpl.createNoVehicle(); + assertTrue(v instanceof NoVehicle); + assertEquals("noVehicle",v.getId()); + } + } diff --git a/jsprit-core/src/test/java/jsprit/core/problem/vehicle/VehicleTypeImplTest.java b/jsprit-core/src/test/java/jsprit/core/problem/vehicle/VehicleTypeImplTest.java index 43d7bc1c..5bb562d0 100644 --- a/jsprit-core/src/test/java/jsprit/core/problem/vehicle/VehicleTypeImplTest.java +++ b/jsprit-core/src/test/java/jsprit/core/problem/vehicle/VehicleTypeImplTest.java @@ -6,6 +6,7 @@ import org.junit.Test; public class VehicleTypeImplTest { + @Test(expected=IllegalStateException.class) public void whenTypeHasNegativeCapacityVal_throwIllegalStateExpception(){ @SuppressWarnings("unused") @@ -50,4 +51,80 @@ public class VehicleTypeImplTest { assertEquals(20,type.getCapacityDimensions().get(0)); } + @Test + public void whenCallingStaticNewBuilderInstance_itShouldReturnNewBuilderInstance(){ + VehicleTypeImpl.Builder builder = VehicleTypeImpl.Builder.newInstance("foo", 0); + assertNotNull(builder); + } + + @Test + public void whenBuildingTypeJustByCallingNewInstance_typeIdMustBeCorrect(){ + VehicleTypeImpl type = VehicleTypeImpl.Builder.newInstance("foo", 0).build(); + assertEquals("foo",type.getTypeId()); + } + + @Test + public void whenBuildingTypeJustByCallingNewInstance_capMustBeCorrect(){ + VehicleTypeImpl type = VehicleTypeImpl.Builder.newInstance("foo", 0).build(); + assertEquals(0,type.getCapacity()); + } + + @Test(expected=IllegalStateException.class) + public void whenBuildingTypeWithCapSmallerThanZero_throwIllegalStateException(){ + @SuppressWarnings("unused") + VehicleTypeImpl type = VehicleTypeImpl.Builder.newInstance("foo", -10).build(); + } + + @Test(expected=IllegalStateException.class) + public void whenBuildingTypeWithNullId_throwIllegalStateException(){ + @SuppressWarnings("unused") + VehicleTypeImpl type = VehicleTypeImpl.Builder.newInstance(null, 10).build(); + } + + @Test + public void whenSettingMaxVelocity_itShouldBeSetCorrectly(){ + VehicleTypeImpl type = VehicleTypeImpl.Builder.newInstance("type", 10).setMaxVelocity(10).build(); + assertEquals(10,type.getMaxVelocity(),0.0); + } + + @Test(expected=IllegalStateException.class) + public void whenMaxVelocitySmallerThanZero_itShouldThrowException(){ + @SuppressWarnings("unused") + VehicleTypeImpl type = VehicleTypeImpl.Builder.newInstance("type", 10).setMaxVelocity(-10).build(); + } + + @Test(expected=IllegalStateException.class) + public void whenFixedCostsSmallerThanZero_itShouldThrowException(){ + @SuppressWarnings("unused") + VehicleTypeImpl type = VehicleTypeImpl.Builder.newInstance("type", 10).setFixedCost(-10).build(); + } + + public void whenSettingFixedCosts_itShouldBeSetCorrectly(){ + VehicleTypeImpl type = VehicleTypeImpl.Builder.newInstance("type", 10).setFixedCost(10).build(); + assertEquals(10.0, type.getVehicleCostParams().fix,0.0); + } + + @Test(expected=IllegalStateException.class) + public void whenPerDistanceCostsSmallerThanZero_itShouldThrowException(){ + @SuppressWarnings("unused") + VehicleTypeImpl type = VehicleTypeImpl.Builder.newInstance("type", 10).setCostPerDistance(-10).build(); + } + + public void whenSettingPerDistanceCosts_itShouldBeSetCorrectly(){ + VehicleTypeImpl type = VehicleTypeImpl.Builder.newInstance("type", 10).setCostPerDistance(10).build(); + assertEquals(10.0, type.getVehicleCostParams().perDistanceUnit,0.0); + } + + @Test(expected=IllegalStateException.class) + public void whenPerTimeCostsSmallerThanZero_itShouldThrowException(){ + @SuppressWarnings("unused") + VehicleTypeImpl type = VehicleTypeImpl.Builder.newInstance("type", 10).setCostPerTime(-10).build(); + } + + public void whenSettingPerTimeCosts_itShouldBeSetCorrectly(){ + VehicleTypeImpl type = VehicleTypeImpl.Builder.newInstance("type", 10).setCostPerTime(10).build(); + assertEquals(10.0, type.getVehicleCostParams().perDistanceUnit,0.0); + } + + } diff --git a/jsprit-examples/input/algorithmConfigWithSchrimpfAcceptance.xml b/jsprit-examples/input/algorithmConfigWithSchrimpfAcceptance.xml new file mode 100755 index 00000000..5b3d9969 --- /dev/null +++ b/jsprit-examples/input/algorithmConfigWithSchrimpfAcceptance.xml @@ -0,0 +1,73 @@ + + + + + 2000 + + + + + + + 1 + + + + + 0.05 + 20 + + + + + + 0.5 + + + + + + 0.5 + + + + + + + + + + 0.3 + + + + + + 0.5 + + + + + + + diff --git a/jsprit-examples/input/algorithmConfig_considerFixedCosts.xml b/jsprit-examples/input/algorithmConfig_considerFixedCosts.xml new file mode 100755 index 00000000..a6684739 --- /dev/null +++ b/jsprit-examples/input/algorithmConfig_considerFixedCosts.xml @@ -0,0 +1,75 @@ + + + + + 2000 + + + + true + + + + + 1 + + + + + 0.05 + 20 + + + + + + 0.5 + + + + + + 0.5 + + + + + + + + + + 0.3 + + + + + + 0.5 + + + + + + + diff --git a/jsprit-examples/input/algorithmConfig_considerFixedCosts_routeLevel.xml b/jsprit-examples/input/algorithmConfig_considerFixedCosts_routeLevel.xml new file mode 100755 index 00000000..aa87322e --- /dev/null +++ b/jsprit-examples/input/algorithmConfig_considerFixedCosts_routeLevel.xml @@ -0,0 +1,76 @@ + + + + + 2000 + + + + route + true + + + + + 1 + + + + + 0.05 + 20 + + + + + + 0.5 + + + + + + 0.5 + + + + + + + + + + 0.3 + + + + + + 0.5 + + + + + + + diff --git a/jsprit-examples/input/cn_14mix.txt b/jsprit-examples/input/cn_14mix.txt new file mode 100644 index 00000000..a0689d17 --- /dev/null +++ b/jsprit-examples/input/cn_14mix.txt @@ -0,0 +1,67 @@ +50 + 0 40 40 0 + 1 22 22 18 + 2 36 26 26 + 3 21 45 11 + 4 45 35 30 + 5 55 20 21 + 6 33 34 19 + 7 50 50 15 + 8 55 45 16 + 9 26 59 29 + 10 40 66 26 + 11 55 65 37 + 12 35 51 16 + 13 62 35 12 + 14 62 57 31 + 15 62 24 8 + 16 21 36 19 + 17 33 44 20 + 18 9 56 13 + 19 62 48 15 + 20 66 14 22 + 21 44 13 28 + 22 26 13 12 + 23 11 28 6 + 24 7 43 27 + 25 17 64 14 + 26 41 46 18 + 27 55 34 17 + 28 35 16 29 + 29 52 26 13 + 30 43 26 22 + 31 31 76 25 + 32 22 53 28 + 33 26 29 27 + 34 50 40 19 + 35 55 50 10 + 36 54 10 12 + 37 60 15 14 + 38 47 66 24 + 39 30 60 16 + 40 30 50 33 + 41 12 17 15 + 42 15 14 11 + 43 16 19 18 + 44 21 48 17 + 45 50 30 21 + 46 51 42 27 + 47 50 15 19 + 48 48 21 20 + 49 12 38 5 + 50 15 56 22 +//Vehicles characteristics: volume, fixed cost, variable cost, number available +v 1 120 1000 1.0 4 +v 2 160 1500 1.1 2 +v 3 300 3500 1.4 1 + +160 +8 300 0 10000 625.679906 + 7*1000 + 1500 = + 7 26 7 35 19 8 46 34 10530637 + 4 10 38 11 14 10794953 + 8 33 1 43 42 41 23 49 16 10916479 + 6 48 47 36 21 28 22 10931709 + 7 27 13 15 20 37 5 29 10832981 + 6 44 32 50 18 24 3 10862722 + 5 6 2 30 45 4 10469680 + 7 12 39 31 25 9 40 17 15917639 diff --git a/jsprit-examples/src/main/java/jsprit/examples/BicycleMessenger.java b/jsprit-examples/src/main/java/jsprit/examples/BicycleMessenger.java index beeefaa5..14b67a24 100644 --- a/jsprit-examples/src/main/java/jsprit/examples/BicycleMessenger.java +++ b/jsprit-examples/src/main/java/jsprit/examples/BicycleMessenger.java @@ -228,6 +228,8 @@ public class BicycleMessenger { problemBuilder.addConstraint(new ThreeTimesLessThanBestDirectRouteConstraint(nearestMessengers, routingCosts, stateManager)); problemBuilder.addConstraint(new IgnoreMessengerThatCanNeverMeetTimeRequirements(nearestMessengers, routingCosts)); + problemBuilder.addPenaltyVehicles(10.0,50000); + //finally build the problem VehicleRoutingProblem bicycleMessengerProblem = problemBuilder.build(); @@ -347,8 +349,8 @@ public class BicycleMessenger { * * it is important to give it the same typeId as the type you want to shadow */ - VehicleType penaltyType = VehicleTypeImpl.Builder.newInstance("messengerType", 15).setFixedCost(50000).setCostPerDistance(4).build(); - PenaltyVehicleType penaltyVehicleType = new PenaltyVehicleType(penaltyType,4); +// VehicleType penaltyType = VehicleTypeImpl.Builder.newInstance("messengerType", 15).setFixedCost(50000).setCostPerDistance(4).build(); +// PenaltyVehicleType penaltyVehicleType = new PenaltyVehicleType(penaltyType,4); while((line = reader.readLine()) != null){ if(firstLine) { firstLine = false; continue; } @@ -358,9 +360,9 @@ public class BicycleMessenger { .setReturnToDepot(false).setType(messengerType).build(); problemBuilder.addVehicle(vehicle); //build the penalty vehicle - Vehicle penaltyVehicle = VehicleImpl.Builder.newInstance(tokens[1]+"_penalty").setLocationCoord(Coordinate.newInstance(Double.parseDouble(tokens[2]), Double.parseDouble(tokens[3]))) - .setReturnToDepot(false).setType(penaltyVehicleType).build(); - problemBuilder.addVehicle(penaltyVehicle); +// Vehicle penaltyVehicle = VehicleImpl.Builder.newInstance(tokens[1]+"_penalty").setLocationCoord(Coordinate.newInstance(Double.parseDouble(tokens[2]), Double.parseDouble(tokens[3]))) +// .setReturnToDepot(false).setType(penaltyVehicleType).build(); +// problemBuilder.addVehicle(penaltyVehicle); } reader.close(); } diff --git a/jsprit-examples/src/main/java/jsprit/examples/CVRPExample.java b/jsprit-examples/src/main/java/jsprit/examples/CVRPExample.java deleted file mode 100644 index d6bd6444..00000000 --- a/jsprit-examples/src/main/java/jsprit/examples/CVRPExample.java +++ /dev/null @@ -1,32 +0,0 @@ -/******************************************************************************* - * Copyright (C) 2013 Stefan Schroeder - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - ******************************************************************************/ -package jsprit.examples; - -import jsprit.core.problem.VehicleRoutingProblem; -import jsprit.core.problem.io.VrpXMLWriter; -import jsprit.instance.reader.ChristofidesReader; - -public class CVRPExample { - - public static void main(String[] args) { - VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); - new ChristofidesReader(builder).read("input/vrpnc1.txt"); - VehicleRoutingProblem vrp = builder.build(); - new VrpXMLWriter(vrp).write("input/vrpnc1-jsprit.xml"); - } - -} diff --git a/jsprit-examples/src/main/java/jsprit/examples/HVRPBenchmarkExample.java b/jsprit-examples/src/main/java/jsprit/examples/HVRPBenchmarkExample.java new file mode 100644 index 00000000..d0c9e2b8 --- /dev/null +++ b/jsprit-examples/src/main/java/jsprit/examples/HVRPBenchmarkExample.java @@ -0,0 +1,63 @@ +package jsprit.examples; + +import java.util.Collection; + +import jsprit.analysis.toolbox.AlgorithmSearchProgressChartListener; +import jsprit.analysis.toolbox.GraphStreamViewer; +import jsprit.analysis.toolbox.Plotter; +import jsprit.analysis.toolbox.SolutionPrinter; +import jsprit.analysis.toolbox.SolutionPrinter.Print; +import jsprit.core.algorithm.VehicleRoutingAlgorithm; +import jsprit.core.algorithm.io.VehicleRoutingAlgorithms; +import jsprit.core.problem.VehicleRoutingProblem; +import jsprit.core.problem.solution.VehicleRoutingProblemSolution; +import jsprit.core.util.Solutions; +import jsprit.instance.reader.VrphGoldenReader; +import jsprit.instance.reader.VrphGoldenReader.VrphType; +import jsprit.util.Examples; + +/** + * Shows how to benchmark the algorithm on different classical HVRP and FSM instances. + * + *

These instances are from Golden and Taillard and copied from + * . + * + *

You can find best results of different problems, instances and authors here: + *
http://www2.ic.uff.br/~satoru/conteudo/artigos/PAPER%20PUCA-JHeuristics-2011.pdf + *
http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.100.2331&rep=rep1&type=pdf + * + * @author schroeder + * + */ +public class HVRPBenchmarkExample { + + public static void main(String[] args) { + Examples.createOutputFolder(); + VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance(); + //read modified Golden-instance, you can find all relevant instances in jsprit-instances/instances/vrph + //you can build various problems, see VrphType doc for more details + new VrphGoldenReader(vrpBuilder, VrphType.HVRPFD).read("input/cn_14mix.txt"); + vrpBuilder.addPenaltyVehicles(10.0); + VehicleRoutingProblem vrp = vrpBuilder.build(); + + //try also input//jsprit-examples/input/algorithmConfig_considerFixedCosts_routeLevel.xml + //results might even be a bit better, but it is slower, since it checks insertion on routeLevel + //rather than on local level + VehicleRoutingAlgorithm vra = VehicleRoutingAlgorithms.readAndCreateAlgorithm(vrp, "input/algorithmConfig_considerFixedCosts.xml"); + vra.setNuOfIterations(10000); +// vra.setPrematureAlgorithmTermination(new IterationWithoutImprovementTermination(500)); + vra.addListener(new AlgorithmSearchProgressChartListener("output/progress.png")); + Collection solutions = vra.searchSolutions(); + + VehicleRoutingProblemSolution best = Solutions.bestOf(solutions); + + SolutionPrinter.print(vrp, best, Print.VERBOSE); + + + Plotter plotter = new Plotter(vrp,best); + plotter.plot("output/cn14.png", "cn14"); + + new GraphStreamViewer(vrp, best).setRenderDelay(100).display(); + } + +} diff --git a/jsprit-examples/src/main/java/jsprit/examples/HVRPExample.java b/jsprit-examples/src/main/java/jsprit/examples/HVRPExample.java new file mode 100644 index 00000000..3702d2be --- /dev/null +++ b/jsprit-examples/src/main/java/jsprit/examples/HVRPExample.java @@ -0,0 +1,117 @@ +package jsprit.examples; + +import java.util.Collection; + +import jsprit.analysis.toolbox.GraphStreamViewer; +import jsprit.analysis.toolbox.SolutionPrinter; +import jsprit.analysis.toolbox.SolutionPrinter.Print; +import jsprit.core.algorithm.VehicleRoutingAlgorithm; +import jsprit.core.algorithm.io.VehicleRoutingAlgorithms; +import jsprit.core.problem.VehicleRoutingProblem; +import jsprit.core.problem.VehicleRoutingProblem.FleetSize; +import jsprit.core.problem.job.Service; +import jsprit.core.problem.solution.VehicleRoutingProblemSolution; +import jsprit.core.problem.vehicle.VehicleImpl; +import jsprit.core.problem.vehicle.VehicleType; +import jsprit.core.problem.vehicle.VehicleTypeImpl; +import jsprit.core.util.Coordinate; +import jsprit.core.util.Solutions; + +/** + * customers (id,x,y,demand) + * 1 22 22 18 + * 2 36 26 26 + * 3 21 45 11 + * 4 45 35 30 + * 5 55 20 21 + * 6 33 34 19 + * 7 50 50 15 + * 8 55 45 16 + * 9 26 59 29 + * 10 40 66 26 + * 11 55 65 37 + * 12 35 51 16 + * 13 62 35 12 + * 14 62 57 31 + * 15 62 24 8 + * 16 21 36 19 + * 17 33 44 20 + * 18 9 56 13 + * 19 62 48 15 + * 20 66 14 22 + * + * vehicles (id,cap,fixed costs, perDistance, #vehicles) at location (40,40) + * 1 120 1000 1.0 2 + * 2 160 1500 1.1 1 + * 3 300 3500 1.4 1 + * + * @author schroeder + * + */ +public class HVRPExample { + + + public static void main(String[] args) { + + VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance(); + + //add customers + vrpBuilder.addJob(Service.Builder.newInstance("1", 18).setCoord(Coordinate.newInstance(22, 22)).build()); + vrpBuilder.addJob(Service.Builder.newInstance("2", 26).setCoord(Coordinate.newInstance(36, 26)).build()); + vrpBuilder.addJob(Service.Builder.newInstance("3", 11).setCoord(Coordinate.newInstance(21, 45)).build()); + vrpBuilder.addJob(Service.Builder.newInstance("4", 30).setCoord(Coordinate.newInstance(45, 35)).build()); + vrpBuilder.addJob(Service.Builder.newInstance("5", 21).setCoord(Coordinate.newInstance(55, 20)).build()); + vrpBuilder.addJob(Service.Builder.newInstance("6", 19).setCoord(Coordinate.newInstance(33, 34)).build()); + vrpBuilder.addJob(Service.Builder.newInstance("7", 15).setCoord(Coordinate.newInstance(50, 50)).build()); + vrpBuilder.addJob(Service.Builder.newInstance("8", 16).setCoord(Coordinate.newInstance(55, 45)).build()); + vrpBuilder.addJob(Service.Builder.newInstance("9", 29).setCoord(Coordinate.newInstance(26, 59)).build()); + vrpBuilder.addJob(Service.Builder.newInstance("10", 26).setCoord(Coordinate.newInstance(40, 66)).build()); + vrpBuilder.addJob(Service.Builder.newInstance("11", 37).setCoord(Coordinate.newInstance(55, 56)).build()); + vrpBuilder.addJob(Service.Builder.newInstance("12", 16).setCoord(Coordinate.newInstance(35, 51)).build()); + vrpBuilder.addJob(Service.Builder.newInstance("13", 12).setCoord(Coordinate.newInstance(62, 35)).build()); + vrpBuilder.addJob(Service.Builder.newInstance("14", 31).setCoord(Coordinate.newInstance(62, 57)).build()); + vrpBuilder.addJob(Service.Builder.newInstance("15", 8).setCoord(Coordinate.newInstance(62, 24)).build()); + vrpBuilder.addJob(Service.Builder.newInstance("16", 19).setCoord(Coordinate.newInstance(21, 36)).build()); + vrpBuilder.addJob(Service.Builder.newInstance("17", 20).setCoord(Coordinate.newInstance(33, 44)).build()); + vrpBuilder.addJob(Service.Builder.newInstance("18", 13).setCoord(Coordinate.newInstance(9, 56)).build()); + vrpBuilder.addJob(Service.Builder.newInstance("19", 15).setCoord(Coordinate.newInstance(62, 48)).build()); + vrpBuilder.addJob(Service.Builder.newInstance("20", 22).setCoord(Coordinate.newInstance(66, 14)).build()); + + + //add vehicle - finite fleet + //2xtype1 + VehicleType type1 = VehicleTypeImpl.Builder.newInstance("type_1", 120).setCostPerDistance(1.0).build(); + VehicleImpl vehicle1_1 = VehicleImpl.Builder.newInstance("1_1").setLocationCoord(Coordinate.newInstance(40, 40)).setType(type1).build(); + vrpBuilder.addVehicle(vehicle1_1); + VehicleImpl vehicle1_2 = VehicleImpl.Builder.newInstance("1_2").setLocationCoord(Coordinate.newInstance(40, 40)).setType(type1).build(); + vrpBuilder.addVehicle(vehicle1_2); + //1xtype2 + VehicleType type2 = VehicleTypeImpl.Builder.newInstance("type_2", 160).setCostPerDistance(1.1).build(); + VehicleImpl vehicle2_1 = VehicleImpl.Builder.newInstance("2_1").setLocationCoord(Coordinate.newInstance(40, 40)).setType(type2).build(); + vrpBuilder.addVehicle(vehicle2_1); + //1xtype3 + VehicleType type3 = VehicleTypeImpl.Builder.newInstance("type_3", 300).setCostPerDistance(1.3).build(); + VehicleImpl vehicle3_1 = VehicleImpl.Builder.newInstance("3_1").setLocationCoord(Coordinate.newInstance(40, 40)).setType(type3).build(); + vrpBuilder.addVehicle(vehicle3_1); + + //add penaltyVehicles to allow invalid solutions temporarily + vrpBuilder.addPenaltyVehicles(5, 1000); + + //set fleetsize finite + vrpBuilder.setFleetSize(FleetSize.FINITE); + + //build problem + VehicleRoutingProblem vrp = vrpBuilder.build(); + + VehicleRoutingAlgorithm vra = VehicleRoutingAlgorithms.readAndCreateAlgorithm(vrp, "input/algorithmConfigWithSchrimpfAcceptance.xml"); + Collection solutions = vra.searchSolutions(); + + VehicleRoutingProblemSolution best = Solutions.bestOf(solutions); + + SolutionPrinter.print(vrp, best, Print.VERBOSE); + + new GraphStreamViewer(vrp, best).setRenderDelay(100).display(); + + } + +} diff --git a/jsprit-examples/src/main/java/jsprit/util/Examples.java b/jsprit-examples/src/main/java/jsprit/util/Examples.java new file mode 100644 index 00000000..37a4463a --- /dev/null +++ b/jsprit-examples/src/main/java/jsprit/util/Examples.java @@ -0,0 +1,17 @@ +package jsprit.util; + +import java.io.File; + +public class Examples { + + public static void createOutputFolder(){ + File dir = new File("output"); + // if the directory does not exist, create it + if (!dir.exists()){ + System.out.println("creating directory ./output"); + boolean result = dir.mkdir(); + if(result) System.out.println("./output created"); + } + } + +} diff --git a/jsprit-instances/instances/vrph/README b/jsprit-instances/instances/vrph/README new file mode 100644 index 00000000..c8e85a3e --- /dev/null +++ b/jsprit-instances/instances/vrph/README @@ -0,0 +1 @@ +use VrpGolderReader to read these files \ No newline at end of file diff --git a/jsprit-instances/instances/vrph/c20_3mix.txt b/jsprit-instances/instances/vrph/c20_3mix.txt new file mode 100644 index 00000000..9003a6d2 --- /dev/null +++ b/jsprit-instances/instances/vrph/c20_3mix.txt @@ -0,0 +1,29 @@ +20 + 0 30 40 0 + 1 37 52 7 + 2 49 49 30 + 3 52 64 16 + 4 20 26 9 + 5 40 30 21 + 6 21 47 15 + 7 17 63 19 + 8 31 62 23 + 9 52 33 11 + 10 51 21 5 + 11 42 41 19 + 12 31 32 29 + 13 5 25 23 + 14 12 42 21 + 15 36 16 10 + 16 52 41 15 + 17 27 23 3 + 18 17 33 41 + 19 13 13 9 + 20 57 58 28 +//Vehicles characteristics: type, volume, fixed cost +5 +v 1 20 20 +v 2 30 35 +v 3 40 50 +v 4 70 120 +v 5 120 225 diff --git a/jsprit-instances/instances/vrph/c20_4mix.txt b/jsprit-instances/instances/vrph/c20_4mix.txt new file mode 100644 index 00000000..f7dd9eaa --- /dev/null +++ b/jsprit-instances/instances/vrph/c20_4mix.txt @@ -0,0 +1,27 @@ +20 + 0 30 40 0 + 1 37 52 7 + 2 49 49 30 + 3 52 64 16 + 4 20 26 9 + 5 40 30 21 + 6 21 47 15 + 7 17 63 19 + 8 31 62 23 + 9 52 33 11 + 10 51 21 5 + 11 42 41 19 + 12 31 32 29 + 13 5 25 23 + 14 12 42 21 + 15 36 16 10 + 16 52 41 15 + 17 27 23 3 + 18 17 33 41 + 19 13 13 9 + 20 57 58 28 +//Vehicles characteristics: type, volume, fixed cost +3 +v 1 60 1000 +v 2 80 1500 +v 3 150 3000 diff --git a/jsprit-instances/instances/vrph/c20_5mix.txt b/jsprit-instances/instances/vrph/c20_5mix.txt new file mode 100644 index 00000000..5a9c33e7 --- /dev/null +++ b/jsprit-instances/instances/vrph/c20_5mix.txt @@ -0,0 +1,29 @@ +20 + 0 30 40 0 + 1 37 52 7 + 2 49 49 30 + 3 52 64 16 + 4 20 26 9 + 5 40 30 21 + 6 21 47 15 + 7 17 63 19 + 8 31 62 23 + 9 52 33 11 + 10 51 21 5 + 11 42 41 19 + 12 31 32 29 + 13 5 25 23 + 14 12 42 21 + 15 36 16 10 + 16 52 41 15 + 17 27 23 3 + 18 17 33 41 + 19 13 13 9 + 20 57 58 28 +//Vehicles characteristics: type, volume, fixed cost +5 +v 1 20 20 +v 2 30 35 +v 3 40 50 +v 4 70 120 +v 5 120 225 \ No newline at end of file diff --git a/jsprit-instances/instances/vrph/c20_6mix.txt b/jsprit-instances/instances/vrph/c20_6mix.txt new file mode 100644 index 00000000..f7dd9eaa --- /dev/null +++ b/jsprit-instances/instances/vrph/c20_6mix.txt @@ -0,0 +1,27 @@ +20 + 0 30 40 0 + 1 37 52 7 + 2 49 49 30 + 3 52 64 16 + 4 20 26 9 + 5 40 30 21 + 6 21 47 15 + 7 17 63 19 + 8 31 62 23 + 9 52 33 11 + 10 51 21 5 + 11 42 41 19 + 12 31 32 29 + 13 5 25 23 + 14 12 42 21 + 15 36 16 10 + 16 52 41 15 + 17 27 23 3 + 18 17 33 41 + 19 13 13 9 + 20 57 58 28 +//Vehicles characteristics: type, volume, fixed cost +3 +v 1 60 1000 +v 2 80 1500 +v 3 150 3000 diff --git a/jsprit-instances/instances/vrph/cn_13mix.txt b/jsprit-instances/instances/vrph/cn_13mix.txt new file mode 100644 index 00000000..9e58fa13 --- /dev/null +++ b/jsprit-instances/instances/vrph/cn_13mix.txt @@ -0,0 +1,73 @@ +50 + 0 40 40 0 + 1 22 22 18 + 2 36 26 26 + 3 21 45 11 + 4 45 35 30 + 5 55 20 21 + 6 33 34 19 + 7 50 50 15 + 8 55 45 16 + 9 26 59 29 + 10 40 66 26 + 11 55 65 37 + 12 35 51 16 + 13 62 35 12 + 14 62 57 31 + 15 62 24 8 + 16 21 36 19 + 17 33 44 20 + 18 9 56 13 + 19 62 48 15 + 20 66 14 22 + 21 44 13 28 + 22 26 13 12 + 23 11 28 6 + 24 7 43 27 + 25 17 64 14 + 26 41 46 18 + 27 55 34 17 + 28 35 16 29 + 29 52 26 13 + 30 43 26 22 + 31 31 76 25 + 32 22 53 28 + 33 26 29 27 + 34 50 40 19 + 35 55 50 10 + 36 54 10 12 + 37 60 15 14 + 38 47 66 24 + 39 30 60 16 + 40 30 50 33 + 41 12 17 15 + 42 15 14 11 + 43 16 19 18 + 44 21 48 17 + 45 50 30 21 + 46 51 42 27 + 47 50 15 19 + 48 48 21 20 + 49 12 38 5 + 50 15 56 22 +//Vehicles characteristics: type, volume, fixed cost, variable cost, number available +6 +v 1 20 20 1.0 4 +v 2 30 35 1.1 2 +v 3 40 50 1.2 4 +v 4 70 120 1.7 4 +v 5 120 225 2.5 2 +v 6 200 400 3.2 1 + + +best solution with fixed costs: 588.784723 + 20 + 3*35 + 2*50 + 4*400 = 2413.78 + 2 27 13 807876 + 1 26 321656 + 2 17 12 774254 + 2 34 8 828825 + 1 46 573606 + 1 4 491422 + 9 39 31 10 38 11 14 19 35 7 5129601 + 11 2 28 22 1 43 42 41 23 16 33 6 5102713 + 10 40 32 9 25 50 18 24 49 3 44 5096803 + 11 30 48 21 47 36 37 20 15 5 29 45 5011089 diff --git a/jsprit-instances/instances/vrph/cn_14mix.txt b/jsprit-instances/instances/vrph/cn_14mix.txt new file mode 100644 index 00000000..a0689d17 --- /dev/null +++ b/jsprit-instances/instances/vrph/cn_14mix.txt @@ -0,0 +1,67 @@ +50 + 0 40 40 0 + 1 22 22 18 + 2 36 26 26 + 3 21 45 11 + 4 45 35 30 + 5 55 20 21 + 6 33 34 19 + 7 50 50 15 + 8 55 45 16 + 9 26 59 29 + 10 40 66 26 + 11 55 65 37 + 12 35 51 16 + 13 62 35 12 + 14 62 57 31 + 15 62 24 8 + 16 21 36 19 + 17 33 44 20 + 18 9 56 13 + 19 62 48 15 + 20 66 14 22 + 21 44 13 28 + 22 26 13 12 + 23 11 28 6 + 24 7 43 27 + 25 17 64 14 + 26 41 46 18 + 27 55 34 17 + 28 35 16 29 + 29 52 26 13 + 30 43 26 22 + 31 31 76 25 + 32 22 53 28 + 33 26 29 27 + 34 50 40 19 + 35 55 50 10 + 36 54 10 12 + 37 60 15 14 + 38 47 66 24 + 39 30 60 16 + 40 30 50 33 + 41 12 17 15 + 42 15 14 11 + 43 16 19 18 + 44 21 48 17 + 45 50 30 21 + 46 51 42 27 + 47 50 15 19 + 48 48 21 20 + 49 12 38 5 + 50 15 56 22 +//Vehicles characteristics: volume, fixed cost, variable cost, number available +v 1 120 1000 1.0 4 +v 2 160 1500 1.1 2 +v 3 300 3500 1.4 1 + +160 +8 300 0 10000 625.679906 + 7*1000 + 1500 = + 7 26 7 35 19 8 46 34 10530637 + 4 10 38 11 14 10794953 + 8 33 1 43 42 41 23 49 16 10916479 + 6 48 47 36 21 28 22 10931709 + 7 27 13 15 20 37 5 29 10832981 + 6 44 32 50 18 24 3 10862722 + 5 6 2 30 45 4 10469680 + 7 12 39 31 25 9 40 17 15917639 diff --git a/jsprit-instances/instances/vrph/cn_15mix.txt b/jsprit-instances/instances/vrph/cn_15mix.txt new file mode 100644 index 00000000..bdd1a2e5 --- /dev/null +++ b/jsprit-instances/instances/vrph/cn_15mix.txt @@ -0,0 +1,73 @@ +50 + 0 30 40 0 + 1 37 52 7 + 2 49 49 30 + 3 52 64 16 + 4 20 26 9 + 5 40 30 21 + 6 21 47 15 + 7 17 63 19 + 8 31 62 23 + 9 52 33 11 + 10 51 21 5 + 11 42 41 19 + 12 31 32 29 + 13 5 25 23 + 14 12 42 21 + 15 36 16 10 + 16 52 41 15 + 17 27 23 3 + 18 17 33 41 + 19 13 13 9 + 20 57 58 28 + 21 62 42 8 + 22 42 57 8 + 23 16 57 16 + 24 8 52 10 + 25 7 38 28 + 26 27 68 7 + 27 30 48 15 + 28 43 67 14 + 29 58 48 6 + 30 58 27 19 + 31 37 69 11 + 32 38 46 12 + 33 46 10 23 + 34 61 33 26 + 35 62 63 17 + 36 63 69 6 + 37 32 22 9 + 38 45 35 15 + 39 59 15 14 + 40 5 6 7 + 41 10 17 27 + 42 21 10 13 + 43 5 64 11 + 44 30 15 16 + 45 39 10 10 + 46 32 39 5 + 47 25 32 25 + 48 25 55 17 + 49 48 28 18 + 50 56 37 10 +//Vehicles characteristics: volume, fixed cost, variable cost, number available +//See E. D. Taillard, "A heuristic column generation method for the heterogeneous fleet vrp" +//RAIRO Rech. Op�r. 33 (1) 1999, pp 1-14) +//see http://ina2.eivd.ch/collaborateurs/etd/articles.dir/vrphen.pdf +v 1 50 100 1.0 4 +v 2 100 250 1.6 3 +v 3 160 450 2.0 2 + +12 160 0 9999999 798.063541 + 8*100 + 4*250 = 2598.06 + 4 24 43 7 26 1888114 + 3 11 16 38 1470725 + 2 25 14 1476007 + 3 6 23 48 1476130 + 3 28 31 8 1675334 + 3 1 2 32 1476635 + 2 4 18 1395853 + 2 47 27 1341971 + 7 12 37 15 45 33 39 10 3412795 + 7 13 41 40 19 42 44 17 3559482 + 6 5 49 30 34 9 46 3212631 + 8 22 3 36 35 20 29 21 50 3594959 diff --git a/jsprit-instances/instances/vrph/cn_16mix.txt b/jsprit-instances/instances/vrph/cn_16mix.txt new file mode 100644 index 00000000..44d1104c --- /dev/null +++ b/jsprit-instances/instances/vrph/cn_16mix.txt @@ -0,0 +1,70 @@ +50 + 0 30 40 0 + 1 37 52 7 + 2 49 49 30 + 3 52 64 16 + 4 20 26 9 + 5 40 30 21 + 6 21 47 15 + 7 17 63 19 + 8 31 62 23 + 9 52 33 11 + 10 51 21 5 + 11 42 41 19 + 12 31 32 29 + 13 5 25 23 + 14 12 42 21 + 15 36 16 10 + 16 52 41 15 + 17 27 23 3 + 18 17 33 41 + 19 13 13 9 + 20 57 58 28 + 21 62 42 8 + 22 42 57 8 + 23 16 57 16 + 24 8 52 10 + 25 7 38 28 + 26 27 68 7 + 27 30 48 15 + 28 43 67 14 + 29 58 48 6 + 30 58 27 19 + 31 37 69 11 + 32 38 46 12 + 33 46 10 23 + 34 61 33 26 + 35 62 63 17 + 36 63 69 6 + 37 32 22 9 + 38 45 35 15 + 39 59 15 14 + 40 5 6 7 + 41 10 17 27 + 42 21 10 13 + 43 5 64 11 + 44 30 15 16 + 45 39 10 10 + 46 32 39 5 + 47 25 32 25 + 48 25 55 17 + 49 48 28 18 + 50 56 37 10 + +v 1 40 100 1.0 2 +v 2 80 200 1.6 4 +v 3 140 400 2.1 3 + +10 140 0 9999999 741.499345 + 10*200 = 2741.50 + 3 18 4 47 2396248 + 6 15 45 33 39 10 49 2916243 + 5 12 17 44 37 5 2591911 + 4 38 16 2 11 2562466 + 5 24 43 7 23 48 2805845 + 6 29 20 35 36 3 1 2975090 + 5 13 41 40 19 42 3011668 + 6 50 21 34 30 9 46 2813483 + 6 8 26 31 28 22 32 2773629 + 4 27 6 14 25 2568409 + + diff --git a/jsprit-instances/instances/vrph/cn_17mix.txt b/jsprit-instances/instances/vrph/cn_17mix.txt new file mode 100644 index 00000000..c137802e --- /dev/null +++ b/jsprit-instances/instances/vrph/cn_17mix.txt @@ -0,0 +1,94 @@ +75 + 0 40 40 0 + 1 22 22 18 + 2 36 26 26 + 3 21 45 11 + 4 45 35 30 + 5 55 20 21 + 6 33 34 19 + 7 50 50 15 + 8 55 45 16 + 9 26 59 29 + 10 40 66 26 + 11 55 65 37 + 12 35 51 16 + 13 62 35 12 + 14 62 57 31 + 15 62 24 8 + 16 21 36 19 + 17 33 44 20 + 18 9 56 13 + 19 62 48 15 + 20 66 14 22 + 21 44 13 28 + 22 26 13 12 + 23 11 28 6 + 24 7 43 27 + 25 17 64 14 + 26 41 46 18 + 27 55 34 17 + 28 35 16 29 + 29 52 26 13 + 30 43 26 22 + 31 31 76 25 + 32 22 53 28 + 33 26 29 27 + 34 50 40 19 + 35 55 50 10 + 36 54 10 12 + 37 60 15 14 + 38 47 66 24 + 39 30 60 16 + 40 30 50 33 + 41 12 17 15 + 42 15 14 11 + 43 16 19 18 + 44 21 48 17 + 45 50 30 21 + 46 51 42 27 + 47 50 15 19 + 48 48 21 20 + 49 12 38 5 + 50 15 56 22 + 51 29 39 12 + 52 54 38 19 + 53 55 57 22 + 54 67 41 16 + 55 10 70 7 + 56 6 25 26 + 57 65 27 14 + 58 40 60 21 + 59 70 64 24 + 60 64 4 13 + 61 36 6 15 + 62 30 20 18 + 63 20 30 11 + 64 15 5 28 + 65 50 70 9 + 66 57 72 37 + 67 45 42 30 + 68 38 33 10 + 69 50 4 8 + 70 66 8 11 + 71 59 5 3 + 72 35 60 1 + 73 27 24 6 + 74 40 20 10 + 75 40 37 20 +//Vehicles characteristics: volume, fixed cost, variable cost, number available +//See E. D. Taillard, "A heuristic column generation method for the heterogeneous fleet vrp" +//RAIRO Rech. Op�r. 33 (1) 1999, pp 1-14) +//see http://ina2.eivd.ch/collaborateurs/etd/articles.dir/vrphen.pdf50 25 1.0 4 +v 1 120 80 1.2 4 +v 2 200 150 1.5 2 +v 3 350 320 1.8 1 + +7 350 0 1000000 703.124497 + 7 * 150 = 1753.12 + 14 27 57 15 37 20 70 60 71 69 36 47 5 29 45 2685412 + 8 7 53 14 59 11 66 65 38 2518938 + 11 51 16 49 24 18 50 25 55 31 10 58 2837925 + 10 26 12 72 39 9 32 44 3 40 17 2223923 + 12 6 33 63 23 56 41 43 42 64 22 1 73 2669773 + 10 67 34 46 8 35 19 54 13 52 4 2218010 + 10 68 2 62 28 61 21 74 48 30 75 2377261 + diff --git a/jsprit-instances/instances/vrph/cn_18mix.txt b/jsprit-instances/instances/vrph/cn_18mix.txt new file mode 100644 index 00000000..b2bc5cfe --- /dev/null +++ b/jsprit-instances/instances/vrph/cn_18mix.txt @@ -0,0 +1,124 @@ +75 + 0 40 40 0 + 1 22 22 18 + 2 36 26 26 + 3 21 45 11 + 4 45 35 30 + 5 55 20 21 + 6 33 34 19 + 7 50 50 15 + 8 55 45 16 + 9 26 59 29 + 10 40 66 26 + 11 55 65 37 + 12 35 51 16 + 13 62 35 12 + 14 62 57 31 + 15 62 24 8 + 16 21 36 19 + 17 33 44 20 + 18 9 56 13 + 19 62 48 15 + 20 66 14 22 + 21 44 13 28 + 22 26 13 12 + 23 11 28 6 + 24 7 43 27 + 25 17 64 14 + 26 41 46 18 + 27 55 34 17 + 28 35 16 29 + 29 52 26 13 + 30 43 26 22 + 31 31 76 25 + 32 22 53 28 + 33 26 29 27 + 34 50 40 19 + 35 55 50 10 + 36 54 10 12 + 37 60 15 14 + 38 47 66 24 + 39 30 60 16 + 40 30 50 33 + 41 12 17 15 + 42 15 14 11 + 43 16 19 18 + 44 21 48 17 + 45 50 30 21 + 46 51 42 27 + 47 50 15 19 + 48 48 21 20 + 49 12 38 5 + 50 15 56 22 + 51 29 39 12 + 52 54 38 19 + 53 55 57 22 + 54 67 41 16 + 55 10 70 7 + 56 6 25 26 + 57 65 27 14 + 58 40 60 21 + 59 70 64 24 + 60 64 4 13 + 61 36 6 15 + 62 30 20 18 + 63 20 30 11 + 64 15 5 28 + 65 50 70 9 + 66 57 72 37 + 67 45 42 30 + 68 38 33 10 + 69 50 4 8 + 70 66 8 11 + 71 59 5 3 + 72 35 60 1 + 73 27 24 6 + 74 40 20 10 + 75 40 37 20 +//Vehicles characteristics: volume, fixed cost, variable cost, number available +//See E. D. Taillard, "A heuristic column generation method for the heterogeneous fleet vrp" +//RAIRO Rech. Op�r. 33 (1) 1999, pp 1-14) +//see http://ina2.eivd.ch/collaborateurs/etd/articles.dir/vrphen.pdf +v 1 20 10 1.0 4 +v 2 50 35 1.3 4 +v 3 100 100 1.9 2 +v 4 150 180 2.4 2 +v 5 250 400 2.9 1 +v 6 400 800 3.2 1 + + +16 400 0 1000000 + 2 4 75 504563 + 2 40 12 663241 + 2 34 46 584164 + 2 6 33 706263 + 2 26 67 521249 + 4 59 66 65 38 1928889 + 5 30 48 47 21 74 1621004 + 8 36 69 71 60 70 20 37 29 2030669 + 6 8 35 14 19 54 13 1786844 + 6 32 25 55 18 50 3 1957187 + 6 45 5 15 57 27 52 1680991 + 6 17 44 24 49 16 51 1714575 + 5 9 39 31 10 72 1856344 + 4 58 11 53 7 1665558 + 5 2 28 61 22 62 1772896 + 10 63 23 56 41 64 42 43 1 73 68 2874657 + + 2 40 12 663241 + 2 2 30 708780 + 2 34 46 584164 + 2 6 33 706263 + 2 26 67 521249 + 4 59 66 65 38 1928889 + 8 61 69 36 71 60 70 20 37 2163283 + 6 8 35 14 19 54 13 1786844 + 7 63 23 56 41 43 1 73 1845922 + 6 32 25 55 18 50 3 1957187 + 6 45 5 15 57 27 52 1680991 + 6 17 44 24 49 16 51 1714575 + 5 9 39 31 10 72 1856344 + 4 58 11 53 7 1665558 + 5 28 22 64 42 62 1951198 + 2 4 75 504563 + 6 68 74 21 47 48 29 1659867 diff --git a/jsprit-instances/instances/vrph/cn_19mix.txt b/jsprit-instances/instances/vrph/cn_19mix.txt new file mode 100644 index 00000000..3eea2cb8 --- /dev/null +++ b/jsprit-instances/instances/vrph/cn_19mix.txt @@ -0,0 +1,126 @@ + 100 + 0 35 35 0 + 1 41 49 10 + 2 35 17 7 + 3 55 45 13 + 4 55 20 19 + 5 15 30 26 + 6 25 30 3 + 7 20 50 5 + 8 10 43 9 + 9 55 60 16 + 10 30 60 16 + 11 20 65 12 + 12 50 35 19 + 13 30 25 23 + 14 15 10 20 + 15 30 5 8 + 16 10 20 19 + 17 5 30 2 + 18 20 40 12 + 19 15 60 17 + 20 45 65 9 + 21 45 20 11 + 22 45 10 18 + 23 55 5 29 + 24 65 35 3 + 25 65 20 6 + 26 45 30 17 + 27 35 40 16 + 28 41 37 16 + 29 64 42 9 + 30 40 60 21 + 31 31 52 27 + 32 35 69 23 + 33 53 52 11 + 34 65 55 14 + 35 63 65 8 + 36 2 60 5 + 37 20 20 8 + 38 5 5 16 + 39 60 12 31 + 40 40 25 9 + 41 42 7 5 + 42 24 12 5 + 43 23 3 7 + 44 11 14 18 + 45 6 38 16 + 46 2 48 1 + 47 8 56 27 + 48 13 52 36 + 49 6 68 30 + 50 47 47 13 + 51 49 58 10 + 52 27 43 9 + 53 37 31 14 + 54 57 29 18 + 55 63 23 2 + 56 53 12 6 + 57 32 12 7 + 58 36 26 18 + 59 21 24 28 + 60 17 34 3 + 61 12 24 13 + 62 24 58 19 + 63 27 69 10 + 64 15 77 9 + 65 62 77 20 + 66 49 73 25 + 67 67 5 25 + 68 56 39 36 + 69 37 47 6 + 70 37 56 5 + 71 57 68 15 + 72 47 16 25 + 73 44 17 9 + 74 46 13 8 + 75 49 11 18 + 76 49 42 13 + 77 53 43 14 + 78 61 52 3 + 79 57 48 23 + 80 56 37 6 + 81 55 54 26 + 82 15 47 16 + 83 14 37 11 + 84 11 31 7 + 85 16 22 41 + 86 4 18 35 + 87 28 18 26 + 88 26 52 9 + 89 26 35 15 + 90 31 67 3 + 91 15 19 1 + 92 22 22 2 + 93 18 24 22 + 94 26 27 27 + 95 25 24 20 + 96 22 27 11 + 97 25 21 12 + 98 19 21 10 + 99 20 26 9 + 100 18 18 17 +//Vehicles characteristics: volume, fixed cost, variable cost, number available +//See E. D. Taillard, "A heuristic column generation method for the heterogeneous fleet vrp" +//RAIRO Rech. Op�r. 33 (1) 1999, pp 1-14) +//see http://ina2.eivd.ch/collaborateurs/etd/articles.dir/vrphen.pdf +v 1 100 500 1.0 4 +v 2 200 1200 1.4 3 +v 3 300 2100 1.7 3 + +15 200 0 1000000 + 5 12 80 68 76 28 546700 + 6 77 3 79 81 33 50 560066 + 7 1 30 20 66 32 70 69 591171 + 9 51 9 71 65 35 34 78 29 24 626544 + 6 26 54 4 72 21 40 564109 + 8 53 73 74 75 22 41 2 58 566885 + 6 56 23 67 39 25 55 601888 + 4 59 85 93 99 546338 + 7 88 62 11 63 90 10 31 578753 + 7 8 46 47 36 49 64 19 623582 + 6 27 52 7 48 82 18 560521 + 4 94 95 87 13 540372 + 9 57 15 43 42 14 38 44 100 92 610131 + 9 89 60 83 45 17 84 5 96 6 571667 + 7 61 86 16 91 98 37 97 575109 diff --git a/jsprit-instances/instances/vrph/cn_20mix.txt b/jsprit-instances/instances/vrph/cn_20mix.txt new file mode 100644 index 00000000..28c6f1c2 --- /dev/null +++ b/jsprit-instances/instances/vrph/cn_20mix.txt @@ -0,0 +1,128 @@ + 100 + 0 35 35 0 + 1 41 49 10 + 2 35 17 7 + 3 55 45 13 + 4 55 20 19 + 5 15 30 26 + 6 25 30 3 + 7 20 50 5 + 8 10 43 9 + 9 55 60 16 + 10 30 60 16 + 11 20 65 12 + 12 50 35 19 + 13 30 25 23 + 14 15 10 20 + 15 30 5 8 + 16 10 20 19 + 17 5 30 2 + 18 20 40 12 + 19 15 60 17 + 20 45 65 9 + 21 45 20 11 + 22 45 10 18 + 23 55 5 29 + 24 65 35 3 + 25 65 20 6 + 26 45 30 17 + 27 35 40 16 + 28 41 37 16 + 29 64 42 9 + 30 40 60 21 + 31 31 52 27 + 32 35 69 23 + 33 53 52 11 + 34 65 55 14 + 35 63 65 8 + 36 2 60 5 + 37 20 20 8 + 38 5 5 16 + 39 60 12 31 + 40 40 25 9 + 41 42 7 5 + 42 24 12 5 + 43 23 3 7 + 44 11 14 18 + 45 6 38 16 + 46 2 48 1 + 47 8 56 27 + 48 13 52 36 + 49 6 68 30 + 50 47 47 13 + 51 49 58 10 + 52 27 43 9 + 53 37 31 14 + 54 57 29 18 + 55 63 23 2 + 56 53 12 6 + 57 32 12 7 + 58 36 26 18 + 59 21 24 28 + 60 17 34 3 + 61 12 24 13 + 62 24 58 19 + 63 27 69 10 + 64 15 77 9 + 65 62 77 20 + 66 49 73 25 + 67 67 5 25 + 68 56 39 36 + 69 37 47 6 + 70 37 56 5 + 71 57 68 15 + 72 47 16 25 + 73 44 17 9 + 74 46 13 8 + 75 49 11 18 + 76 49 42 13 + 77 53 43 14 + 78 61 52 3 + 79 57 48 23 + 80 56 37 6 + 81 55 54 26 + 82 15 47 16 + 83 14 37 11 + 84 11 31 7 + 85 16 22 41 + 86 4 18 35 + 87 28 18 26 + 88 26 52 9 + 89 26 35 15 + 90 31 67 3 + 91 15 19 1 + 92 22 22 2 + 93 18 24 22 + 94 26 27 27 + 95 25 24 20 + 96 22 27 11 + 97 25 21 12 + 98 19 21 10 + 99 20 26 9 + 100 18 18 17 +//Vehicles characteristics: volume, fixed cost, variable cost, number available +//See E. D. Taillard, "A heuristic column generation method for the heterogeneous fleet vrp" +//RAIRO Rech. Op�r. 33 (1) 1999, pp 1-14) +//see http://ina2.eivd.ch/collaborateurs/etd/articles.dir/vrphen.pdf +v 1 60 100 1.0 6 +v 2 140 300 1.7 4 +v 3 200 500 2.0 3 + +17 200 0 100000 1190.858809 + 11*100 + 6*300 = 4090.86 + 2 12 68 143589 + 4 76 3 77 28 144929 + 6 79 78 34 29 24 80 186635 + 7 18 83 8 45 17 84 60 175014 + 4 26 72 73 40 148608 + 5 21 74 75 22 41 165933 + 3 87 97 95 140494 + 3 13 58 53 126834 + 4 50 33 81 1 157707 + 6 42 14 43 15 57 2 183736 + 3 27 89 94 135338 + 8 52 7 48 47 19 11 62 88 383651 + 10 31 10 32 90 63 64 49 36 46 82 429222 + 10 51 9 35 71 65 66 20 30 70 69 415471 + 9 5 61 16 86 38 44 91 98 92 394398 + 8 59 37 100 85 93 99 96 6 352542 + 8 4 56 23 67 39 25 55 54 406754 diff --git a/jsprit-instances/src/main/java/jsprit/instance/reader/VrphGoldenReader.java b/jsprit-instances/src/main/java/jsprit/instance/reader/VrphGoldenReader.java new file mode 100644 index 00000000..d4e793c8 --- /dev/null +++ b/jsprit-instances/src/main/java/jsprit/instance/reader/VrphGoldenReader.java @@ -0,0 +1,176 @@ +package jsprit.instance.reader; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; + +import jsprit.core.problem.VehicleRoutingProblem; +import jsprit.core.problem.VehicleRoutingProblem.Builder; +import jsprit.core.problem.VehicleRoutingProblem.FleetSize; +import jsprit.core.problem.io.VrpXMLWriter; +import jsprit.core.problem.job.Service; +import jsprit.core.problem.vehicle.Vehicle; +import jsprit.core.problem.vehicle.VehicleImpl; +import jsprit.core.problem.vehicle.VehicleTypeImpl; +import jsprit.core.util.Coordinate; + +/** + * Reads modified files from Taillard's website + * http://mistic.heig-vd.ch/taillard/problemes.dir/vrp.dir/vrp.html. You can find the modified version here: + * jsprit-instances/instances/vrph. + * + *

See {@link VrphType} what kind of problems can be generated + * + *

Note that c20_3-c20_6 do not have variable costs and a limited nuVehicle, thus they can only be used for FSMF. + * + * @author schroeder + * + */ +public class VrphGoldenReader { + + /** + * + * FSMD - Fleet Size and Mix with Dependent costs + *

FSMF - Fleet Size and Mix with Fixed costs + *

FSMFD - Fleet Size and Mix with Fixed and Dependent costs + *

HVRPD - Heterogeneous Vehicle Routing Problem with Dependent costs and finite (limited) fleet + *

HVRPFD - Heterogeneous Vehicle Routing Problem with Fixed and Dependent costs and finite (limited) fleet + * + * @author schroeder + * + */ + public enum VrphType { + FSMD, + HVRPD, + FSMF, + FSMFD, + HVRPFD + } + + private final VehicleRoutingProblem.Builder vrpBuilder; + + private final VrphType vrphType; + + public VrphGoldenReader(Builder vrpBuilder, VrphType vrphType) { + super(); + this.vrpBuilder = vrpBuilder; + this.vrphType = vrphType; + } + + public void read(String filename){ + BufferedReader reader = getReader(filename); + String line = null; + boolean firstline = true; + Coordinate depotCoord = null; + int customerCount=0; + Integer nuOfCustomer = 0; + while((line=readLine(reader))!=null){ + String trimedLine = line.trim(); + if(trimedLine.startsWith("//")) continue; + String[] tokens = trimedLine.split("\\s+"); + if(firstline){ + nuOfCustomer=Integer.parseInt(tokens[0]); + customerCount=0; + firstline=false; + } + else if(customerCount<=nuOfCustomer) { + if(customerCount == 0){ + depotCoord = Coordinate.newInstance(Double.parseDouble(tokens[1]), Double.parseDouble(tokens[2])); + } + else{ + Service.Builder serviceBuilder = Service.Builder.newInstance(tokens[0], Integer.parseInt(tokens[3])); + serviceBuilder.setCoord(Coordinate.newInstance(Double.parseDouble(tokens[1]), Double.parseDouble(tokens[2]))); + vrpBuilder.addJob(serviceBuilder.build()); + } + customerCount++; + } + else if(trimedLine.startsWith("v")){ + VehicleTypeImpl.Builder typeBuilder = VehicleTypeImpl.Builder.newInstance("type_"+tokens[1], Integer.parseInt(tokens[2])); + int nuOfVehicles = 1; + if(vrphType.equals(VrphType.FSMF)){ + typeBuilder.setFixedCost(Double.parseDouble(tokens[3])); + } + else if(vrphType.equals(VrphType.FSMFD)){ + typeBuilder.setFixedCost(Double.parseDouble(tokens[3])); + if(tokens.length > 4){ + typeBuilder.setCostPerDistance(Double.parseDouble(tokens[4])); + } + else throw new IllegalStateException("option " + vrphType + " cannot be applied with this instance"); + } + else if(vrphType.equals(VrphType.FSMD)){ + if(tokens.length > 4){ + typeBuilder.setCostPerDistance(Double.parseDouble(tokens[4])); + } + else throw new IllegalStateException("option " + vrphType + " cannot be applied with this instance"); + } + else if(vrphType.equals(VrphType.HVRPD)){ + if(tokens.length > 4){ + typeBuilder.setCostPerDistance(Double.parseDouble(tokens[4])); + nuOfVehicles = Integer.parseInt(tokens[5]); + vrpBuilder.setFleetSize(FleetSize.FINITE); + } + else throw new IllegalStateException("option " + vrphType + " cannot be applied with this instance"); + } + else if (vrphType.equals(VrphType.HVRPFD)){ + if(tokens.length > 4){ + typeBuilder.setFixedCost(Double.parseDouble(tokens[3])); + typeBuilder.setCostPerDistance(Double.parseDouble(tokens[4])); + nuOfVehicles = Integer.parseInt(tokens[5]); + vrpBuilder.setFleetSize(FleetSize.FINITE); + } + else throw new IllegalStateException("option " + vrphType + " cannot be applied with this instance"); + } + for(int i=0;i