Minizinc Model pickup and delivery in a problem similar to Vehicle Route Problem - constraint-programming

I am new to Minizinc and I want to adjust a VRM problem that I have found here.
I have to add a couple of functionalities but the one with which I am really struggling is dependencies between pickup and deliveries services. Some nodes (the delivery nodes) have to be visited only after some other nodes were visited previously (the pick up nodes).
I was thinking to add an input for the precendence like this:
array[1..n_orders div 2, 1..2] of int: precedences = [| 1, 3 | 2, 4 | 5, 10 | 7, 8 | 6, 9 |];
Basically, it says that node 3 has to be visit after node 1, node 4 after node 2 and so on...
Any idea how to do this?

It seems that the basic precedence can be established by constraining
constraint forall(i in index_set1of2(precedences)) (
DepartureTimes[precedences[i,1]] < DepartureTimes[precedences[i,2]]
)

Related

Capacity Constraint Check only at node level in OR-Tools

We have combined the pickup delivery module with capacity constraint. Here, we keep on picking up and dropping the items on the route (there can be pickup and drop on the same node). Hence, a person will be able to take more orders even though his capacity is less, because, at next node he will be dropping it.
E.g:
Let's assume:
Vehicle capacity is 10 kg.
Total nodes = 11 (0 to 10)
Pickup Nodes: 1, 3, 8, 10
Drop Nodes: 5, 2, 4
we have maintained two arrays " data['pickup_demand'] " is for demands at pickup nodes and " data['delivery_demand'] " demand at drop nods. We are also subtracting it as to get the final data ( i.e: " data['demands'] = data['pickup_demand'] - data['delivery_demand'] ").
data['pickup_demand'] = [0, 8, 0, 2, 0, 0, 0, 0, 5, 0, 6]
data['delivery_demand'] = [0, 0, 6, 10, 0, 5, 0, 0, 0, 0, 0]
Expected Routing:-
0(0) -> 1(8) -> 3(2) -> 5(5) -> 8(5) -> 2(6) -> 10(6) -> 3(10) -> 0(0)
| | | | | | | | |
Depot Pickup Pickup Drop Pickup Drop Pickup Drop Depot
Here, if we see, the same vehicle is able to this total task even though it's max. weight is 10 kg.
We do not want to consider what is it's total weight (ie. adding all the pickups here, it is 21 kg) it has carried for all the orders. But, the check should be only on node basis, which, should not be greater than 10 kg. In this way the vehicle does more task.
Even though the routing is not like the shown above, but, our requirement is to consider max. weight check on the node only.
I think, I need to modify this?
routing.AddDimensionWithVehicleCapacity(
demand_callback_index,
0, # null capacity slack
data['vehicle_capacities'], # vehicle maximum capacities
True, # start cumul to zero
'Capacity')

OR-Tools VRP: Constrain locations to be served by same vehicle

I would like to constrain locations to be served by the same vehicle.
I used capacity-constraints for achieving this. Say we have l = [[1,2], [3,4]] which means that location 1, 2 must be served by the same vehicle and 3, 4 as well. So 1, 2 ends up on route_1 and 3, 4 on route_2
My code for achieving this is:
for idx, route_constraint in enumerate(l):
vehicle_capacities = [0] * NUM_VEHICLES
vehicle_capacities[idx] = len(route_constraint)
route_dimension_name = 'Same_Route_' + str(idx)
def callback(from_index):
from_node = manager.IndexToNode(from_index)
return 1 if from_node in route_constraint else 0
same_routes_callback_index = routing.RegisterUnaryTransitCallback(callback)
routing.AddDimensionWithVehicleCapacity(
same_routes_callback_index,
0, # null capacity slack
vehicle_capacities, # vehicle maximum capacities
True, # start cumul to zero
route_dimension_name)
The idea is that 1,2 have a capacity demand of each 1 unit (all others have zero). As only vehicle 1 has a capacity of 2 it is the only one able to serve 1,2.
This seems to work fine if len(l) == 1. If greater the solver is not able to find a solution if though I put into l pairs of locations which were on the same route without the above code (hence without the above capacity constraints.
Is there a more elegant way to model my requirement?
Why does the solver fail to find a solution?
I have also considered the possibility of dropping visits (at a high cost) to give the solver the possibility to start from a solution which drops visits such that it will find his way fro this point to a solution without any drops. I had no luck.
Thanks in advance.
Each stop has a vehicle var whose values determine what vehicle is allowed to visit the stop. If you want to have stops 1 and 2 serviced by vehicle 0 use a member constraint on the vehicle var of each stop and set it to [0]. Since you might have other constraints that make stops optional add the value -1 to the list. It is a special value that indicates that the stop is not serviced by a vehicle.
In Python:
n2x = index_manager.NodeToIndex
cpsolver = routing_model.solver()
for stop in [1,2]:
vehicle_var = routing_model.VehicleVar(n2x(stop))
values = [-1, 0]
cpsolver.Add(cpsolver.MemberCt(vehicle_var, values))

Change-making: Dynamic Programming

In a lecture earlier, we were told that using a greedy approach to solve a change making problem would not always work.
An example of this was given as follows:
We want to reach n = 14, and we have three coins of different values: d1 = 1,d2 = 7,d3 = 10.
Using the greedy approach this would lead us to do 10 + 1 + 1 + 1 + 1 (5 coins).
It was said the a dynamic problem approach would solve this accurately. I tried working it out but it came back to 5.
Assume F holds the number of coins needed to make an amount
F[14] = min {F[14 – 1] , F[14 – 7], F[14 – 10]} + 1
= F[14 – 10] + 1 = 4 + 1 = 5
This shows again that we need 5 coins, when this can clearly be done by using 2 coins (7 + 7).
What gives? Thanks.
You assumed that min {F[14 – 1] , F[14 – 7], F[14 – 10]}=F[14-10] when it is not the case. The minimum is actually F[14-7]=1 and hence the optimum is 2

Scikit Learn - Random Forest: How continuous feature is handled?

Random Forest accepts numerical data. Usually features with text data is converted to numerical categories and continuous numerical data is fed as it is without discretization. How the RF treat the continuous data for creating nodes? Will it bin the continuous numerical data internally? or treat each data as discrete level.
for example:
I want to feed a data set(ofcourse after categorizing the text features) to RF. How the continuous data is handled by the RF?
Is it advisable to discretize the continuous data(longitudes and latitudes, in this case) before feeding? Or doing so information is lost?
As far as I understand, you are asking how the threshold is chosen for continuous features. The binning occurs at values, where your class is changed. For example, consider the following 1D dataset with x as feature and y as class variable
x = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
y = [ 1, 1, 0, 0, 0, 0, 0, 1, 1, 1]
The two possible candidate cuts will be considered: (i) between 2 and 3 (will practically look like as x<2.5) and (ii) between 7 and 8 (as x<7.5).
Among these two candidates the second one will be chosen since it provides a better separation. Them the algorithm goes to the next step.
Therefore it is not advisable to discretize the data yourself. Think about this with the data above. If, for example, you discretize the data in 5 bins [1, 2 | 3, 4 | 5, 6 | 7, 8 | 9, 10], you miss the best split (since 7 and 8 will be in one bin).
You are asking about DecisionTrees. Because RandomForest is ensemble model, and by itself it don't know anything about data, it fully relies on decisons from base estimators (In this case DecisionTrees), and aggregates them.
So, how DecisionTree is treating continious features: Look at this official documentation page. DecisionTreeClassifier was fitted on continuous dataset (Fisher irises), if you will look at the picture of tree - it has threshold value in each node over some chosen feature at this node.

Need help for defining appropriate constraints

I'm very new to constraint programming and try to find some real situations to test it.
I found one i think may be solved with CP.
Here it is :
I have a group of kids that i have to assign to some activities.
These kids fill a form where they specify 3 choices in order of preference.
Activities have a max number of participant so, the idea is to find a solution where the choices are respected for the best without exceedind max.
So, in first approach, i defined vars for kids with [1,2,3] for domain (the link between the number of choice, activity and children being known somewhere else).
But then, i don't really know how to define relevant constraints so I have all the permutation (very long) and then, i have to give a note to each (adding the numbers of choices to get the min) and eliminate results with to big groups.
I think there must be a good way to do this using CP but i can't figure it out.
Does someone can help me ?
Thanks
I'm not sure that I understand everything in your description, for example "so I have all the permutation (very long)" and "i have to give a note to each (adding the numbers of choices to get the min)". That said, here is a simple encoding of what I think would be a model of your problem, or at least a starter.
It's written in MiniZinc and is shown below with a small example of 6 kids and 4 activities. The full model (including variants of some constraints) is here as well: http://hakank.org/minizinc/max_activity.mzn
Description of the variables:
"x" is an array of decision variables containing the selected activity for each kid. "scores" is the scores (1, 2, or 3 depending on which activity that was selected) for the selected activity, and "total_score" just sums the "scores" array.
include "globals.mzn";
int: num_kids;
array[1..num_kids, 1..3] of int: prefs;
int: num_activities;
array[1..num_activities] of int: activity_size;
% decision variables
array[1..num_kids] of var 1..num_activities: x; % the selected activity
array[1..num_kids] of var 1..num_activities: scores;
var int: total_score = sum(scores);
solve maximize total_score;
constraint
forall(k in 1..num_kids) (
% select one of the prefered activities
let {
var 1..3: p
} in
x[k] = prefs[k,p] /\
scores[k] = 4-p % score for the selected activity
)
/\ % ensure size of the activities
global_cardinality_low_up(x, [i | i in 1..num_activities], [0 | i in 1..num_activities], activity_size)
;
output [
"x : ", show(x), "\n",
"scores: ", show(scores), "\n",
"total_score: ", show(total_score), "\n",
];
%
% some small fake data
%
num_kids = 6;
num_activities = 4;
% Activity preferences for each kid
prefs = array2d(1..num_kids, 1..3,
[
1,2,3,
4,2,1,
2,1,4,
4,2,1,
3,2,4,
4,1,3
]);
% max size of activity
activity_size = [2,2,2,3];
The solution of this problem instance is:
x : [1, 4, 2, 4, 3, 4]
scores: [3, 3, 3, 3, 3, 3]
total_score: 18
This is a unique solution.
Using a slightly smaller activity_size ([2,2,2,2]) we get another optimal solution (total_score = 17), since there can be just 2 kids in activity #4 (kid #6 is here forced to take activity #1 instead)
x : [1, 4, 2, 4, 3, 1]
scores: [3, 3, 3, 3, 3, 2]
total_score: 17
There is two other possible selections for the second variant, namely
x : [1, 4, 2, 2, 3, 4]
scores: [3, 3, 3, 2, 3, 3]
total_score: 17
----------
x : [1, 2, 2, 4, 3, 4]
scores: [3, 2, 3, 3, 3, 3]
total_score: 17
Update: I also did a Picat model using the same principal approach: http://hakank.org/picat/max_activity.pi .
Update 2: The above model assumes that all kids get some of their preferred activities. When this assumption is not met one have then fix this somehow instead of just throwing a "UNSATISFIED" as an answer. One way is to select some other - not preferred - activity to kid which will yield a score of 0. This is done in this model: http://hakank.org/minizinc/max_activity2.mzn
The changes compared to the original model are small:
the domain of "scores" are 0..num_activities
we add a disjunction "/ scores[k] = 0" to the forall loop that selects the activity
Since this is a maximization problem a score of 0 will not be used unless it is necessary.
I also added a sanity check that there are enough activities for all kids:
constraint
assert(sum(activity_size) >= num_kids, "There is not activities enough for all kids.")
;

Resources