Job relations in same route not working for multiple jobs using hard constraints

I have 4 jobs and all jobs must be done in same route. I cant use soft activity as I am not sure how much penalty/rewards will be useful for that.
I have used below objective function:

      stateManager.addStateUpdater(new UpdateJobRouteAssignment(stateManager));
        HardActivityConstraint sameRouteServicesConstraint = new HardActivityConstraint() {
            @Override
            public ConstraintsStatus fulfilled(JobInsertionContext iFacts, TourActivity prevAct, TourActivity newAct,
                                               TourActivity nextAct, double prevActDepTime) {
                Collection<Job> jobs =  iFacts.getRoute().getTourActivities().getJobs();
                List<String> jobNames = new ArrayList<String>();
                for (Job j : jobs){
                    jobNames.add(j.getId());
                }
                if(newAct instanceof TourActivity.JobActivity) {
                    jobNames.add(((TourActivity.JobActivity) newAct).getJob().getId());
                }
                if(nextAct instanceof TourActivity.JobActivity) {
                    jobNames.add(((TourActivity.JobActivity) nextAct).getJob().getId());
                }
                if(prevAct instanceof TourActivity.JobActivity) {
                    jobNames.add(((TourActivity.JobActivity) prevAct).getJob().getId());
                }
                Set set = new HashSet(jobNames);
                jobNames = new ArrayList(set);
                if(jobNames.size() > 1) {
                    if (jobNames.containsAll(inSameRoute)) {
                        return ConstraintsStatus.FULFILLED;
                    } else {
                        boolean isDisjoint = Collections.disjoint(jobNames,inSameRoute);
                        if(isDisjoint){
                            return ConstraintsStatus.FULFILLED;
                        } else {
                            List<String> common = new ArrayList<String>(jobNames);
                            common.retainAll(inSameRoute);
                            if(common.size() == inSameRoute.size()){
                                return ConstraintsStatus.FULFILLED;
                            } else {
                                return ConstraintsStatus.NOT_FULFILLED;
                            }
                        }
                    }
                } else {
                    return ConstraintsStatus.FULFILLED;
                }
            }
        };
        constraintManager.addConstraint(sameRouteServicesConstraint, ConstraintManager.Priority.HIGH);
    }

I have used memorizer here:

static class UpdateJobRouteAssignment implements StateUpdater,JobInsertedListener,InsertionStartsListener {

    StateManager stateManager;
    UpdateJobRouteAssignment(StateManager stateManager) {
        this.stateManager = stateManager;
    }
    @Override
    public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime) {
        stateManager.putProblemState(stateManager.createStateId(job2insert.getId()), VehicleRoute.class, inRoute);
    }
    @Override
    public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs) {
        for(VehicleRoute r : vehicleRoutes){
            for(Job j : r.getTourActivities().getJobs()){
                informJobInserted(j,r,0.,0.);
            }
        }
    }
}

The problem I am facing is:
It gives 4 different routes for the 4 jobs in same route.

1 Like

If your goal is to assign 4 jobs to the same route, you need to use HardRouteConstraint and do the following:
if job to be inserted (job i) into route r is one of the 4 jobs:

  1. check whether one of the other 3 is already assigned,
    1.1 if not, one can assign job i to route r
    1.2 if so, you are only allowed to assign it to route r, if one of the other 3 is assigned to route r

Thus, you always need to know the route where at least one of the 4 jobs has been inserted to. Thus, memorize the route.

Thanks Stefan.

But can you tell me how to :

check whether one of the other 3 is already assigned,

Your logic is okay. But how to implement that. As I can have only

JobInsertionContext iFacts

information in hard route constraints not having information about the other routes.

Hi @sutirtha_kayal,

You might want to try using the state updater like in this example.

Best regards,
He

Hi @sutirtha_kayal
It works for me. I followed the suggestion of Stefan.
You can use:

key = stateManager.createStateId(“job”);
routeOfKey = stateManager.getProblemState(key, VehicleRoute.class);

to find the route of the job belongs to. If you already assigned the job in a route it gives you the route. Otherwise it will return NULL. From that you can assume if the other 3 jobs are assigned or not.

Hi @Stefan,
Thanks for the logic you explain here for same route. I got your suggestion here also
https://groups.google.com/forum/#!searchin/jsprit-mailing-list/in$20direct$20sequence%7Csort:relevance/jsprit-mailing-list/oRByPY7obHU/DtVgne4LCQAJ
But here in this forum you explained the logic very beautifully.
Can you do the similar suggestion for the other two relationships?

  1. in same sequence
  2. in direct sequence

Thanks in advance.

Thanks @ame_Ke. This is what I wanted to know. Same route is working for me now.
I also having the same thought with you about the other relationships.