diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/ServiceInsertionCalculator.java b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/ServiceInsertionCalculator.java index baced979..8d8b4a11 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/ServiceInsertionCalculator.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/ServiceInsertionCalculator.java @@ -35,31 +35,32 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.util.Collection; +import java.util.Iterator; /** * Calculator that calculates the best insertion position for a {@link Service}. - * + * * @author schroeder * */ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator{ - + private static final Logger logger = LogManager.getLogger(ServiceInsertionCalculator.class); private HardRouteConstraint hardRouteLevelConstraint; - + private HardActivityConstraint hardActivityLevelConstraint; - + private SoftRouteConstraint softRouteConstraint; - + private SoftActivityConstraint softActivityConstraint; - + private VehicleRoutingTransportCosts transportCosts; - + private ActivityInsertionCostsCalculator additionalTransportCostsCalculator; - + private JobActivityFactory activityFactory; - + private AdditionalAccessEgressCalculator additionalAccessEgressCalculator; public ServiceInsertionCalculator(VehicleRoutingTransportCosts routingCosts, ActivityInsertionCostsCalculator additionalTransportCostsCalculator, ConstraintManager constraintManager) { @@ -77,16 +78,16 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator{ public void setJobActivityFactory(JobActivityFactory jobActivityFactory){ this.activityFactory = jobActivityFactory; } - + @Override public String toString() { return "[name=calculatesServiceInsertion]"; } - + /** * Calculates the marginal cost of inserting job i locally. This is based on the * assumption that cost changes can entirely covered by only looking at the predecessor i-1 and its successor i+1. - * + * */ @Override public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle newVehicle, double newVehicleDepartureTime, final Driver newDriver, final double bestKnownCosts) { @@ -119,18 +120,25 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator{ Start start = new Start(newVehicle.getStartLocation(), newVehicle.getEarliestDeparture(), Double.MAX_VALUE); start.setEndTime(newVehicleDepartureTime); End end = new End(newVehicle.getEndLocation(), 0.0, newVehicle.getLatestArrival()); - + TourActivity prevAct = start; double prevActStartTime = newVehicleDepartureTime; int actIndex = 0; - boolean loopBroken = false; - for(TourActivity nextAct : currentRoute.getTourActivities().getActivities()){ + Iterator activityIterator = currentRoute.getActivities().iterator(); + boolean tourEnd = false; + while(!tourEnd){ + TourActivity nextAct; + if(activityIterator.hasNext()) nextAct = activityIterator.next(); + else{ + nextAct = end; + tourEnd = true; + } double actArrTime = prevActStartTime + transportCosts.getTransportTime(prevAct.getLocation(),deliveryAct2Insert.getLocation(),prevActStartTime,newDriver,newVehicle); Collection timeWindows = service.getTimeWindows(actArrTime); boolean not_fulfilled_break = true; for(TimeWindow timeWindow : timeWindows) { - deliveryAct2Insert.setTheoreticalEarliestStart(timeWindow.getStart()); - deliveryAct2Insert.setTheoreticalLatestStart(timeWindow.getEnd()); + deliveryAct2Insert.setTheoreticalEarliestOperationStartTime(timeWindow.getStart()); + deliveryAct2Insert.setTheoreticalLatestOperationStartTime(timeWindow.getEnd()); ConstraintsStatus status = hardActivityLevelConstraint.fulfilled(insertionContext, prevAct, deliveryAct2Insert, nextAct, prevActStartTime); if (status.equals(ConstraintsStatus.FULFILLED)) { //from job2insert induced costs at activity level @@ -146,34 +154,18 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator{ not_fulfilled_break = false; } } - if(not_fulfilled_break){ - loopBroken = true; - break; - } + if(not_fulfilled_break) break; double nextActArrTime = prevActStartTime + transportCosts.getTransportTime(prevAct.getLocation(), nextAct.getLocation(), prevActStartTime, newDriver, newVehicle); prevActStartTime = CalculationUtils.getActivityEndTime(nextActArrTime, nextAct); prevAct = nextAct; actIndex++; } - if(!loopBroken){ - Collection timeWindows = service.getTimeWindows(actArrTime); - for(TimeWindow timeWindow : timeWindows) { - - } - ConstraintsStatus status = hardActivityLevelConstraint.fulfilled(insertionContext, prevAct, deliveryAct2Insert, end, prevActStartTime); - if(status.equals(ConstraintsStatus.FULFILLED)){ - double additionalICostsAtActLevel = softActivityConstraint.getCosts(insertionContext, prevAct, deliveryAct2Insert, end, prevActStartTime); - double additionalTransportationCosts = additionalTransportCostsCalculator.getCosts(insertionContext, prevAct, end, deliveryAct2Insert, prevActStartTime); - if(additionalICostsAtRouteLevel + additionalICostsAtActLevel + additionalTransportationCosts < bestCost){ - bestCost = additionalICostsAtRouteLevel + additionalICostsAtActLevel + additionalTransportationCosts; - insertionIndex = actIndex; - } - } - } if(insertionIndex == InsertionData.NO_INDEX) { return InsertionData.createEmptyInsertionData(); } InsertionData insertionData = new InsertionData(bestCost, InsertionData.NO_INDEX, insertionIndex, newVehicle, newDriver); + deliveryAct2Insert.setTheoreticalEarliestOperationStartTime(bestTimeWindow.getStart()); + deliveryAct2Insert.setTheoreticalLatestOperationStartTime(bestTimeWindow.getEnd()); insertionData.getEvents().add(new InsertActivity(currentRoute,newVehicle,deliveryAct2Insert,insertionIndex)); insertionData.getEvents().add(new SwitchVehicle(currentRoute,newVehicle,newVehicleDepartureTime)); insertionData.setVehicleDepartureTime(newVehicleDepartureTime); diff --git a/jsprit-core/src/main/java/jsprit/core/problem/job/Service.java b/jsprit-core/src/main/java/jsprit/core/problem/job/Service.java index 723972e3..32851f86 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/job/Service.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/job/Service.java @@ -22,6 +22,7 @@ import jsprit.core.problem.Location; import jsprit.core.problem.Skills; import jsprit.core.problem.solution.route.activity.TimeWindow; import jsprit.core.problem.solution.route.activity.TimeWindows; +import jsprit.core.problem.solution.route.activity.TimeWindowsImpl; import jsprit.core.util.Coordinate; import java.util.Collection; @@ -86,10 +87,14 @@ public class Service extends AbstractJob { protected Location location; - protected TimeWindows timeWindows; + protected TimeWindows timeWindows = new TimeWindowsImpl(); + + private boolean twAdded = false; Builder(String id){ this.id = id; + timeWindows = new TimeWindowsImpl(); + ((TimeWindowsImpl)timeWindows).add(timeWindow); } /** @@ -163,8 +168,32 @@ public class Service extends AbstractJob { public Builder setTimeWindow(TimeWindow tw){ if(tw == null) throw new IllegalArgumentException("time-window arg must not be null"); this.timeWindow = tw; + this.timeWindows = new TimeWindowsImpl(); + ((TimeWindowsImpl) timeWindows).add(tw); return this; } + + public Builder addTimeWindow(TimeWindow timeWindow) { + if(timeWindow == null) throw new IllegalArgumentException("time-window arg must not be null"); + if(!twAdded){ + timeWindows = new TimeWindowsImpl(); + twAdded = true; + } + for(TimeWindow tw : ((TimeWindowsImpl)timeWindows).getTimeWindows()){ + if(timeWindow.getStart() > tw.getStart() && timeWindow.getStart() < tw.getEnd()){ + throw new IllegalStateException("time-windows cannot overlap each other. overlap: " + tw + ", " + timeWindow); + } + if(timeWindow.getEnd() > tw.getStart() && timeWindow.getEnd() < tw.getEnd()){ + throw new IllegalStateException("time-windows cannot overlap each other. overlap: " + tw + ", " + timeWindow); + } + } + ((TimeWindowsImpl) timeWindows).add(timeWindow); + return this; + } + + public Builder addTimeWindow(double earliest, double latest) { + return addTimeWindow(TimeWindow.newInstance(earliest, latest)); + } /** * Builds the service. @@ -189,7 +218,10 @@ public class Service extends AbstractJob { this.name = name; return this; } - } + + + + } private final String id; @@ -222,8 +254,8 @@ public class Service extends AbstractJob { timeWindowManager = builder.timeWindows; } - public Collection getTimeWindows(double time){ - return timeWindowManager.getTimeWindows(time); + public Collection getTimeWindows(double arrTime){ + return timeWindowManager.getTimeWindows(arrTime); } @Override diff --git a/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/DeliverService.java b/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/DeliverService.java index 3d133291..f4ccb563 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/DeliverService.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/DeliverService.java @@ -30,6 +30,10 @@ public final class DeliverService extends AbstractActivity implements DeliveryAc private double arrTime; private double endTime; + + private double theoreticalEarliest; + + private double theoreticalLatest; public DeliverService(Delivery delivery) { super(); @@ -41,10 +45,22 @@ public final class DeliverService extends AbstractActivity implements DeliveryAc this.delivery=deliveryActivity.getJob(); this.arrTime=deliveryActivity.getArrTime(); this.endTime=deliveryActivity.getEndTime(); + this.theoreticalEarliest = deliveryActivity.getTheoreticalEarliestOperationStartTime(); + this.theoreticalLatest = deliveryActivity.getTheoreticalLatestOperationStartTime(); capacity = deliveryActivity.getSize(); setIndex(deliveryActivity.getIndex()); } + @Override + public void setTheoreticalEarliestOperationStartTime(double earliest) { + theoreticalEarliest = earliest; + } + + @Override + public void setTheoreticalLatestOperationStartTime(double latest) { + theoreticalLatest = latest; + } + @Override public String getName() { return delivery.getType(); @@ -62,12 +78,12 @@ public final class DeliverService extends AbstractActivity implements DeliveryAc @Override public double getTheoreticalEarliestOperationStartTime() { - return delivery.getTimeWindow().getStart(); + return theoreticalEarliest; } @Override public double getTheoreticalLatestOperationStartTime() { - return delivery.getTimeWindow().getEnd(); + return theoreticalLatest; } @Override diff --git a/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/DeliverShipment.java b/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/DeliverShipment.java index bcf5c290..70df55d6 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/DeliverShipment.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/DeliverShipment.java @@ -52,6 +52,16 @@ public final class DeliverShipment extends AbstractActivity implements DeliveryA return shipment; } + @Override + public void setTheoreticalEarliestOperationStartTime(double earliest) { + + } + + @Override + public void setTheoreticalLatestOperationStartTime(double latest) { + + } + @Override public String getName() { return "deliverShipment"; diff --git a/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/End.java b/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/End.java index 5d35cc2b..ee4325d9 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/End.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/End.java @@ -146,7 +146,8 @@ public final class End extends AbstractActivity implements TourActivity { + "][twStart=" + Activities.round(theoretical_earliestOperationStartTime) + "][twEnd=" + Activities.round(theoretical_latestOperationStartTime) + "]"; } - + + @Override public String getName() { return "end"; diff --git a/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/PickupService.java b/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/PickupService.java index 8c02211a..4ea58546 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/PickupService.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/PickupService.java @@ -29,6 +29,10 @@ public final class PickupService extends AbstractActivity implements PickupActiv private double arrTime; private double depTime; + + private double theoreticalEarliest; + + private double theoreticalLatest; public PickupService(Pickup pickup) { super(); @@ -43,9 +47,21 @@ public final class PickupService extends AbstractActivity implements PickupActiv this.pickup=pickupActivity.getJob(); this.arrTime=pickupActivity.getArrTime(); this.depTime=pickupActivity.getEndTime(); + this.theoreticalEarliest = pickupActivity.getTheoreticalEarliestOperationStartTime(); + this.theoreticalLatest = pickupActivity.getTheoreticalLatestOperationStartTime(); setIndex(pickupActivity.getIndex()); } + @Override + public void setTheoreticalEarliestOperationStartTime(double earliest) { + this.theoreticalEarliest = earliest; + } + + @Override + public void setTheoreticalLatestOperationStartTime(double latest) { + this.theoreticalLatest = latest; + } + @Override public String getName() { return pickup.getType(); @@ -63,12 +79,12 @@ public final class PickupService extends AbstractActivity implements PickupActiv @Override public double getTheoreticalEarliestOperationStartTime() { - return pickup.getTimeWindow().getStart(); + return theoreticalEarliest; } @Override public double getTheoreticalLatestOperationStartTime() { - return pickup.getTimeWindow().getEnd(); + return theoreticalLatest; } @Override diff --git a/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/PickupShipment.java b/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/PickupShipment.java index b5628f7b..8d667c8e 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/PickupShipment.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/PickupShipment.java @@ -48,6 +48,16 @@ public final class PickupShipment extends AbstractActivity implements PickupActi return shipment; } + @Override + public void setTheoreticalEarliestOperationStartTime(double earliest) { + + } + + @Override + public void setTheoreticalLatestOperationStartTime(double latest) { + + } + @Override public String getName() { return "pickupShipment"; diff --git a/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/ServiceActivity.java b/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/ServiceActivity.java index c917f20b..ee4b7920 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/ServiceActivity.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/ServiceActivity.java @@ -24,12 +24,16 @@ import jsprit.core.problem.solution.route.activity.TourActivity.JobActivity; public class ServiceActivity extends AbstractActivity implements JobActivity{ + @Deprecated public static int counter = 0; public double arrTime; public double endTime; - + + private double theoreticalEarliest; + + private double theoreticalLatest; /** * @return the arrTime */ @@ -115,11 +119,11 @@ public class ServiceActivity extends AbstractActivity implements JobActivity{ } public double getTheoreticalEarliestOperationStartTime() { - return service.getTimeWindow().getStart(); + return theoreticalEarliest; } public double getTheoreticalLatestOperationStartTime() { - return service.getTimeWindow().getEnd(); + return theoreticalLatest; } @Override @@ -151,7 +155,17 @@ public class ServiceActivity extends AbstractActivity implements JobActivity{ + "][twStart=" + Activities.round(getTheoreticalEarliestOperationStartTime()) + "][twEnd=" + Activities.round(getTheoreticalLatestOperationStartTime()) + "]"; } - + + @Override + public void setTheoreticalEarliestOperationStartTime(double earliest) { + theoreticalEarliest = earliest; + } + + @Override + public void setTheoreticalLatestOperationStartTime(double latest) { + theoreticalLatest = latest; + } + @Override public String getName() { return service.getType(); diff --git a/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/Start.java b/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/Start.java index ef10f2cb..cf0d6cba 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/Start.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/Start.java @@ -92,11 +92,13 @@ public final class Start extends AbstractActivity implements TourActivity { public double getTheoreticalLatestOperationStartTime() { return theoretical_latestOperationStartTime; } - + + @Deprecated public void setTheoreticalEarliestOperationStartTime(double time) { this.theoretical_earliestOperationStartTime=time; } + @Deprecated public void setTheoreticalLatestOperationStartTime(double time) { this.theoretical_latestOperationStartTime=time; } @@ -124,7 +126,7 @@ public final class Start extends AbstractActivity implements TourActivity { + "][twStart=" + Activities.round(theoretical_earliestOperationStartTime) + "][twEnd=" + Activities.round(theoretical_latestOperationStartTime) + "]"; } - + @Override public String getName() { return "start"; diff --git a/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/TimeWindowsImpl.java b/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/TimeWindowsImpl.java new file mode 100644 index 00000000..3d2ac731 --- /dev/null +++ b/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/TimeWindowsImpl.java @@ -0,0 +1,27 @@ +package jsprit.core.problem.solution.route.activity; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; + +/** + * Created by schroeder on 26/05/15. + */ +public class TimeWindowsImpl implements TimeWindows { + + private Collection timeWindows = new ArrayList(); + + public void add(TimeWindow timeWindow){ + timeWindows.add(timeWindow); + } + + public Collection getTimeWindows() { + return Collections.unmodifiableCollection(timeWindows); + } + + @Override + public Collection getTimeWindows(double time) { + return Collections.unmodifiableCollection(timeWindows); + } + +} diff --git a/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/TourActivity.java b/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/TourActivity.java index eae62220..8800f9d8 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/TourActivity.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/TourActivity.java @@ -31,6 +31,10 @@ import jsprit.core.problem.job.Job; */ public interface TourActivity extends HasIndex { + public void setTheoreticalEarliestOperationStartTime(double earliest); + + public void setTheoreticalLatestOperationStartTime(double latest); + /** * Basic interface of job-activies. * diff --git a/jsprit-core/src/test/java/jsprit/core/algorithm/MultipleTimeWindowsTest.java b/jsprit-core/src/test/java/jsprit/core/algorithm/MultipleTimeWindowsTest.java new file mode 100644 index 00000000..369aa645 --- /dev/null +++ b/jsprit-core/src/test/java/jsprit/core/algorithm/MultipleTimeWindowsTest.java @@ -0,0 +1,79 @@ +package jsprit.core.algorithm; + +import jsprit.core.algorithm.box.Jsprit; +import jsprit.core.problem.Location; +import jsprit.core.problem.VehicleRoutingProblem; +import jsprit.core.problem.job.Service; +import jsprit.core.problem.solution.VehicleRoutingProblemSolution; +import jsprit.core.problem.vehicle.VehicleImpl; +import jsprit.core.util.Solutions; +import junit.framework.Assert; +import org.junit.Test; + +/** + * Created by schroeder on 26/05/15. + */ +public class MultipleTimeWindowsTest { + + @Test + public void service2ShouldNotBeInserted(){ + Service s = Service.Builder.newInstance("s1").setLocation(Location.newInstance(10,0)).build(); + + Service s2 = Service.Builder.newInstance("s2") + .addTimeWindow(50.,60.) + .setLocation(Location.newInstance(20, 0)).build(); + + VehicleImpl v = VehicleImpl.Builder.newInstance("v1").setStartLocation(Location.newInstance(0,0)) + .setEarliestStart(0.).setLatestArrival(40).build(); + + VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().addJob(s).addJob(s2).addVehicle(v).build(); + VehicleRoutingAlgorithm algorithm = Jsprit.createAlgorithm(vrp); + algorithm.setMaxIterations(100); + VehicleRoutingProblemSolution solution = Solutions.bestOf(algorithm.searchSolutions()); + + Assert.assertEquals(1,solution.getUnassignedJobs().size()); + } + + @Test + public void service2ShouldBeInsertedIntoNewVehicle(){ + Service s = Service.Builder.newInstance("s1").setLocation(Location.newInstance(10,0)) + .addTimeWindow(5.,15.).build(); + + Service s2 = Service.Builder.newInstance("s2") + .addTimeWindow(50.,60.) + .setLocation(Location.newInstance(20, 0)).build(); + + VehicleImpl v = VehicleImpl.Builder.newInstance("v1").setStartLocation(Location.newInstance(0,0)) + .setEarliestStart(0.).setLatestArrival(40).build(); + + VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2").setStartLocation(Location.newInstance(0,0)) + .setEarliestStart(40.).setLatestArrival(80).build(); + + VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().addJob(s).addJob(s2).addVehicle(v).addVehicle(v2).build(); + VehicleRoutingAlgorithm algorithm = Jsprit.createAlgorithm(vrp); + algorithm.setMaxIterations(100); + VehicleRoutingProblemSolution solution = Solutions.bestOf(algorithm.searchSolutions()); + + Assert.assertEquals(0,solution.getUnassignedJobs().size()); + Assert.assertEquals(2, solution.getRoutes().size()); + } + + @Test + public void service2ShouldBeInserted(){ + Service s = Service.Builder.newInstance("s1").setLocation(Location.newInstance(10,0)).build(); + + Service s2 = Service.Builder.newInstance("s2") + .addTimeWindow(50., 60.).addTimeWindow(15., 25) + .setLocation(Location.newInstance(20, 0)).build(); + + VehicleImpl v = VehicleImpl.Builder.newInstance("v1").setStartLocation(Location.newInstance(0,0)) + .setEarliestStart(0.).setLatestArrival(40).build(); + + VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().addJob(s).addJob(s2).addVehicle(v).build(); + VehicleRoutingAlgorithm algorithm = Jsprit.createAlgorithm(vrp); + algorithm.setMaxIterations(100); + VehicleRoutingProblemSolution solution = Solutions.bestOf(algorithm.searchSolutions()); + + Assert.assertEquals(0,solution.getUnassignedJobs().size()); + } +} diff --git a/jsprit-core/src/test/java/jsprit/core/problem/job/ServiceTest.java b/jsprit-core/src/test/java/jsprit/core/problem/job/ServiceTest.java index 1ab54452..91c017ac 100644 --- a/jsprit-core/src/test/java/jsprit/core/problem/job/ServiceTest.java +++ b/jsprit-core/src/test/java/jsprit/core/problem/job/ServiceTest.java @@ -184,4 +184,28 @@ public class ServiceTest { assertEquals("name",s.getName()); } + @Test + public void shouldKnowMultipleTimeWindows(){ + Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")) + .addTimeWindow(TimeWindow.newInstance(0., 10.)).addTimeWindow(TimeWindow.newInstance(20., 30.)) + .setName("name").build(); + assertEquals(2,s.getTimeWindows(0.).size()); + } + + @Test(expected = IllegalStateException.class) + public void whenMultipleTWOverlap_throwEx(){ + Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")) + .addTimeWindow(TimeWindow.newInstance(0.,10.)) + .addTimeWindow(TimeWindow.newInstance(5., 30.)) + .setName("name").build(); + } + + @Test(expected = IllegalStateException.class) + public void whenMultipleTWOverlap2_throwEx(){ + Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")) + .addTimeWindow(TimeWindow.newInstance(20., 30.)) + .addTimeWindow(TimeWindow.newInstance(0., 25.)) + .setName("name").build(); + } + }