Assigning a job to a specific vehicle only

Hi,

I’m trying to implement a constraint where a job can only be assigned to a specific vehicle/driver. If there are no vehicles assigned to a job, then anyone can can be assigned that job.

My idea was to use a hard activity constraint.

This I’m guessing is similar to skills, but I’m finding issues using skills where vehicles are assigned to jobs even if they don’t match a skill - using the default hard skill constraint here.

What I have implemented works only sometimes.

The other constraints I have in the mix is priority, and that is working fine every time.

Happy to share what I have done re: specific vehicle/driver assignment and priority for those that want it.

Dave

Hello,

Indeed, a hard activity constraint looks inappropriate here, because this is not a strict assignment, you want your job to be served in any case.
A soft activity constraint looks much more appropriate. With some penalties dependent on the assigned vehicle it should have good results.

Hi Braktar,

My reasoning on a hard activity constraint is that if the driver/vehicle who should be allocated the job can’t be, then no one else is allocated it. If there is no preferred vehicle, then any one can take it. Fulfill if there is no preferred vehicle or if current vehicle equals preferred vehicle, else not_fulfilled_break.

How would a soft activity constraint work here? Can you enlighten me?

In most instances (75%) the code below seems to work, but for some problems I fire at it, I end up getting vehicle B having vehicle A’s preferred jobs. Setting the constraint priority makes no difference to the final outcome - LOW, HIGH, CRITICAL. I DO NOT run the specific vehicle constraint with the skills constraint at the same time. Interestingly, when I assign the vehicle id as a skill to a job, and don’t use the specific vehicle constraint, I get the same results.

HardActivityConstraint specificVehicle = new HardActivityConstraint() {

	@Override
	public ConstraintsStatus fulfilled(JobInsertionContext iFacts,
		TourActivity prevAct, TourActivity newAct, TourActivity nextAct,
		double prevActDepTime) {
					
		String vehId = iFacts.getNewVehicle().getId();
		String jobId = iFacts.getJob().getId();
	
		//no difference using this code			
		//if (newAct != null) {
		//	if (newAct instanceof JobActivity) {
		//		JobActivity ja = ((JobActivity) newAct);
		//		jobId = ja.getJob().getId();
		//	}
		//}			
			
		//jobVehicleMap is a hash map <job id><vehicle id> as strings				
		if (jobVehicleMap.containsKey(jobId)) {
			//check that the driver can do this job
			String vehicleToCompare = jobVehicleMap.get(jobId);

			if (StringUtils.isNotBlank(vehicleToCompare)) {
				if (!vehicleToCompare.equalsIgnoreCase(vehId)) {
					//logger.debug("not fulfilled --break");
					return ConstraintsStatus.NOT_FULFILLED_BREAK;
				}
			}
		}
		return ConstraintsStatus.FULFILLED;					
	}
};
  
constraintManager.addConstraint(specificVehicle, Priority.LOW); //HIGH, CRITICAL etc, no difference

Thanks

Hi @Dave_Hepworth,

I still don’t quite get your problem, but as far as I see, you should use a Route Constraint instead of an Activity Constraint, since the position of the insertion does not matter.

It seems to me that you can still use skill constraint, but need a pre-processing, that is, you firstly check if there is a preferred vehicle, then, if yes, assign skill to the job and that vehicle, and, if not, do not use skill.

Did I understand your problem correctly?

Best regards,
He

Didn’t get it yesterday, but yes, a Route Constraint will fit much better. Your purpose seems well fitted to the described behavior. But I’m not sure too if it is the goal here.

A soft route constraint will work as follows :
Once a new a activity is tested for an insertion in a route the constraint will give the cost of the insertion.
This cost will be by default a quite high penalty, and much the vehicle is fitted less this penalty is high.

@braktar Yep, thanks, I can see that it is all about the cost of an activity and might apply that. Do I need to set up a solution cost calculator somewhere or it is ok to keep the insertion costs only in the SoftActivity?

@jie31best It’s a problem similar to assigning skills to a job and vehicle…

Have implemented the following:

HardRouteConstraint specificVehicle = new HardRouteConstraint() {
    	
    	@Override
    	public boolean fulfilled(JobInsertionContext insertionContext) {
    		
    		String jid = insertionContext.getJob().getId();
    		String vid = insertionContext.getNewVehicle().getId();
    		
    		String prefer = jobVehicleMap.get(jid);
    		if (StringUtils.isNotBlank(prefer)) {
    			if (!vid.equalsIgnoreCase(prefer)) {
    				return false;
    			}
    		}
    		
    		return true;
    	}
    };

This works. And is similar to the hard skill constraint. But the hard skill constraint has an extra check to see if there are skills that are needed elsewhere in the route. Is that for efficiency in processing?

So in a nutshell - use a route constraint if order of insertion is not important, and use an activity constraint if the order is important. Is that correct?

So:
priority based constraint - activity, relies on correct insertion order
maximum job count constraint - route

The scenario which I was testing last night which was failing was as follows:
7 drivers available (for simplicity, A->G)
1 delivery - assigned to driver A
1 pickup/delivery - driver B
1 delivery - driver C
1 pickup/delivery - no preferred driver

Was getting a the wrong drivers assigned for 50% of the jobs and since I was using a HardActivityConstraint, even through it may not fulfill for a specific driver, some other constraint (say priority) has fulfilled, hence the job was allocated incorrectly.

Dave

I think I worked out my problem.

Vehicle switching was allowed in the algorithm. So if I run the algo time and time again, I get a different set of results which quickly return between 3 and 4 solutions consistently (slightly different costs, but they are distinct solutions).

With switching off, I get one solution everytime I run my query - which is the expected solution.

I am using a hard route constraint for specific vehicle and a hard activity constraint for priority. Using a soft activity constraint for priority results in the same solution with the same solution cost.

Still need to verify this, but I’m closer than yesterday!

Happy to assist any one with queries/code for priority and specific vehicle.

Dave

Hi @Dave_Hepworth,

I think another way you can try is that (this also answers one of your questions in your earlier post), similar to the hard skill constraint, in your hard route constraint, you add a check to see if the vid of insertionContext is equal to the preferred vid of the route, if any. To do this, again, similar to the hard skill constraint, you need a state to record the preferred vid of the route.

Best regards,
He

Hi Dave

I am wanting to do the “assign a vehicle to a job” thing
Per your offer could you please share the details on how you did that ?

kind regards
Grant