Need help to impose job order on multiple jobs

Hi guys!
I try to build a model for waste collection vehicle routing problem. To make this model, i used ‘Pickup’ and ‘Delivery’ to make vehicles collect wastes at ‘Pickup’ nodes and trash it at ‘Delivery’ nodes. And i found something strange in my model while i was running the model. Vehicles went to ‘Delivery’ node before they visited ‘Pickup’ node. They trashed wastes which didn’t exist. To solve this problem i applied Stackoverflow_RelatedJobs_13_and_21_inSameRoute_21_first.java example… (
This example makes an job order - node ‘1’ (‘Pickup’ node) after node ‘2’ (‘Delivery’ node)

However it only works only one ‘Pickup’ and ‘Delivery’ node. i want to impose job order on all the Pickup’ and ‘Delivery’ node.

Here is my code.

static class CustomConstraint implements SoftRouteConstraint{
private StateManager stateManager;
private final String START_NODE;
private final String END_NODE;
private final String START_NODE2;
private final String END_NODE2;
private final String START_NODE3;
private final String END_NODE3;

  	public CustomConstraint(StateManager stateManager,int startNode, int endNode,int startNode2, int endNode2,int startNode3, int endNode3){
  		this.stateManager = stateManager;
  		this.START_NODE = Integer.toString(startNode);
  		this.END_NODE = Integer.toString(endNode);
  		this.START_NODE2 = Integer.toString(startNode2);
  		this.END_NODE2 = Integer.toString(endNode2);
  		this.START_NODE3 = Integer.toString(startNode3);
  		this.END_NODE3 = Integer.toString(endNode3);
  	}
  	
  	@Override
  	public double getCosts(JobInsertionContext insertionContext) {
  		if(insertionContext.getJob().getId().equals(this.START_NODE)){
  			VehicleRoute route = stateManager.getProblemState(StateFactory.createId(this.END_NODE,VEHICLE_ROUTHING_ALGORITHM_ID_INDEX), VehicleRoute.class);
  			if(route==null){
  				return 0.;
  			}
  			if(route!=null){
  				if(route==insertionContext.getRoute()){
  					return -100.;
  				}
  				else return 0.;
  			}
  		}
  		
  		if(insertionContext.getJob().getId().equals(this.START_NODE2)){
  			VehicleRoute route = stateManager.getProblemState(StateFactory.createId(this.END_NODE2,VEHICLE_ROUTHING_ALGORITHM_ID_INDEX), VehicleRoute.class);
  			if(route==null){
  				return 0.;
  			}
  			if(route!=null){
  				if(route==insertionContext.getRoute()){
  					return -100.;
  				}
  				else return 0.;
  			}
  		}
  		if(insertionContext.getJob().getId().equals(this.START_NODE3)){
  			VehicleRoute route = stateManager.getProblemState(StateFactory.createId(this.END_NODE3,VEHICLE_ROUTHING_ALGORITHM_ID_INDEX), VehicleRoute.class);
  			if(route==null){
  				return 0.;
  			}
  			if(route!=null){
  				if(route==insertionContext.getRoute()){
  					return -100.;
  				}
  				else return 0.;
  			}
  		}
  		return 0;
  	}
  	
  }
  
  static class CustomRewardAndPenaltiesThroughSoftConstraints{
  	private VehicleRoutingProblem vrp;
  	private final String START_NODE;
  	private final String END_NODE;
  	private final String START_NODE2;
  	private final String END_NODE2;
  	private final String START_NODE3;
  	private final String END_NODE3;
  	public CustomRewardAndPenaltiesThroughSoftConstraints(VehicleRoutingProblem vrp,int startNode, int endNode,int startNode2, int endNode2,int startNode3, int endNode3) {
  		this.vrp = vrp;
  		this.START_NODE = Integer.toString(startNode);
  		this.END_NODE = Integer.toString(endNode);
  		this.START_NODE2 = Integer.toString(startNode2);
  		this.END_NODE2 = Integer.toString(endNode2);
  		this.START_NODE3 = Integer.toString(startNode3);
  		this.END_NODE3 = Integer.toString(endNode3);
  	}
  	
  	public double getCosts(VehicleRoute route) {
  		boolean serves2 = route.getTourActivities().servesJob(getJob(END_NODE));
  		boolean serves1 = route.getTourActivities().servesJob(getJob(START_NODE));
  		if(serves2 && serves1) {
  			boolean first2 = false;
  			for(TourActivity act : route.getActivities()){
  				if(act instanceof JobActivity){
  					if(((JobActivity) act).getJob().getId().equals(START_NODE) && !first2){
  						return -100.;
  					}
  					if(((JobActivity) act).getJob().getId().equals(END_NODE)){
  						first2=true;
  					}
  				}
  			}
  			return 0.;
  		}
  		boolean serves4 = route.getTourActivities().servesJob(getJob(END_NODE2));
  		boolean serves3 = route.getTourActivities().servesJob(getJob(START_NODE2));
  		if(serves4 && serves3) {
  			boolean first4 = false;
  			for(TourActivity act : route.getActivities()){
  				if(act instanceof JobActivity){
  					if(((JobActivity) act).getJob().getId().equals(START_NODE2) && !first4){
  						return -100.;
  					}
  					if(((JobActivity) act).getJob().getId().equals(END_NODE2)){
  						first4=true;
  					}
  				}
  			}
  			return 0.;
  		}
  		boolean serves6 = route.getTourActivities().servesJob(getJob(END_NODE3));
  		boolean serves5 = route.getTourActivities().servesJob(getJob(START_NODE3));
  		if(serves6 && serves5) {
  			boolean first6 = false;
  			for(TourActivity act : route.getActivities()){
  				if(act instanceof JobActivity){
  					if(((JobActivity) act).getJob().getId().equals(START_NODE3) && !first6){
  						return -100.;
  					}
  					if(((JobActivity) act).getJob().getId().equals(END_NODE3)){
  						first6=true;
  					}
  				}
  			}
  			return 0.;
  		}
  		return 0;
  	}
  	
  	private Job getJob(String string) {
  		return vrp.getJobs().get(string);
  	}
  }

Thank you!

For one waste collection/trash job, did you model it as one Shipment or as one Pickup + one Delivery?

If you model it as a Shipment, then it should impose that the pickup is done before its delivery. So I suggest you go this way.

But if it is the latter, then it is actually modeled as two separate jobs, and yes you will need an activity constraint to impose the sequence for each such pair. Moreover, I would suggest you use hard constraints instead of soft ones, because your case require hard ones.

2 Likes

Thank you for your help!