VRP ortools how to exclude certain routing set from a specific vehicle - or-tools

Each vehicle has specific "distaste" of certain delivery routes.
We would like to exclude these specific nodes combinations from specific vehicles.
Let's say we have vehicles A and nodes to visit X, Y, Z
And if vehicle A does not want [X, Y] and [X] routes we don't want to have these solutions:
Not OK:
Vehicle A: [X, Y]
Vehicle A: [Y, X] (any order)
Vehicle A: [X]
These are OK:
Vehicle A: [Y] ie. subset is fine
Vehicle A: [X, Y, Z] ie. addition of another node is fine
Vehicle A: [Z, Y, X]
Vehicle A: [Z, A] and so on.
I understand there are
if nodes[node_index] according to criteria:
routing.SetAllowedVehiclesForIndex(list(allowed_vehicle_list)), node_index)
Or
routing.VehicleVar(index).SetValues([-1, 2,3,4])
But these completely exclude that vehicle visiting the node.
Any idea how to exclude only certain "solution" for a number of vehicles?

You can theoretically achieve that using an extra dimension, similar to how a capacity dimension works.
If we take the example of the [X, Y] constraint, You can create a dimension with UnaryTransitCallback in which nodes X, Y, and the end nodes of all vehicles have a value of 1, start nodes have a value of 0, and the rest have a value of -1. All vehicles but the constrained vehicle have a capacity of 4, while the latter has a capacity of 3. In addition to that, all vehicles start already "loaded" with a value of 1. This way a route Start->X->Y->End yields a total value of 4, which is above the constrained vehicle's capacity. adding any additional node at any point of the route or abandoning either X or Y yields a total capacity of 3 or less. It is important to set allow_slack=true for the dimension in this case to prevent the values from going below zero.
(making the vehicles start with a value of 1 is for the edge case of a route Start->some_random_node->X->Y->End, the -1 of the random node won't have any effect if the vehicles start with a value of 0)

Related

Creating a graph using maple

What is the (maple) code for the following graph: The vertices are the elements of M_2(\mathbb{Z}_2) and two vertices A and B are adjacent if and only if AB = I.
If you know the code or any references, please let me know.
Start step by step. Think what you need. You need to define your set of vertices and then set of edges. First with the set of vertices. You want all matrices of size 2 by 2 with binary entries, it means a finite set of 16 elements. Matrices are defined in Maple. You can define a matrix with entries (1,1), (1,2), (2,1) and (2,2) beign a, b, c and d respectively in one of the following two ways.
M := Matrix([ [a, b], [c, d] ]);
which means row-wise, or column-wise as in below.
M := < < a, b > | < c, d > >;
Now, I want to put them in an ordered collection, so I choose list data structure. You can make an empty list and then add the matrices one by one with for-loops to it, but since lists are immutable data structures, I would use Array instead and then convert it to a list in the end. Another way is to use list-comprehension using seq. Here is how I do it.
V := [ seq( seq( seq( seq( Matrix([ [a, b], [c, d] ]), d = 0..1 ), c = 0..1 ), b = 0..1 ), a = 0..1 ) ];
And you will see a beautiful list with all 16 matrices that you expect.
Now for the set of edges. Your set is small, so going for a command to find the inverse is not really necessary, just have a nested for-loop to actually multiply matrices A and B and then compare if the result is the identity matrix or not. Remember that in Maple = is not a mathematical equality comparison. To check whether two matrices are equal, use the Equal command in the LinearAlgebra package. So here is how I do it.
E := Array([]); # empty 1-dimensional array
for A in V do
for B in V do
if LinearAlgebra:-Equal( ( A . B mod 2 ) , Matrix([ [1, 0], [0, 1] ]) ) then
ArrayTools:-Append( E, [A, B] ): # modifying E itself instead of defining new one.
end if:
end do:
end do:
Now if you ask to see E, you will see 6 ordered pairs of matrices that their product is the the identity matrix. Note the use of mod to have remain in GF(2) (binary field). If you do the multiplications and additions in Z and then take mod 2, the result will be the same as if you were doing the multiplications and additions in GF(2) from the beginning.
Technically you already have your graph and if you don't want to do anything further, that is the end. The ordered pair (V, E) is the graph itself. But Maple has a package dedicated to Graph theory called GraphTheory. If you want to have a Graph object that you can apply the commands of this package on it, then you need to convert the array of edges to a set. Remember that having the edges stored as ordered pairs (list of length 2) will tell Maple that your edges are directed. If you want undirected edges, then use set of length 2. The following line define the graph object for this example.
E := convert( E, set );
G := GraphTheory:-Graph( V, E );
However, you will get an error message. That is because the elements in your vertices set must be integers or strings or something else, but not matrices, it seems the developers didn't support matrices as label of vertices or something like that. So now instead of saving nodes of the graph as matrices, I pick up the integer indices of them as members of V. For example the identity matrix is the 10th element of V (if you have used the same loop code that I used to generate V above). So instead of asking Maple to have [1 0\\ 0 1] as a vertex of G, I will ask it to have 10 as this vertec, and the edge connecting this node to itself, will be [10, 10]. So I redefine E and V for G.
E := Array([]);
for i from 1 by 1 to 16 do
for j from 1 by 1 to 16 do
if LinearAlgebra:-Equal( ( V[i] . V[j] mod 2 ) , Matrix([ [1, 0], [0, 1] ]) ) then
ArrayTools:-Append( E, [i, j] ):
end if:
end do:
end do:
E := convert( E, set );
G := GraphTheory:-Graph( [ seq(i, i = 1..16) ], E );
No error message this time :)
Now what can we do with this G? The first thing you may want to try is to draw it. Here is how you can do it using GraphTheory's predefined commands.
GraphTheory:-DrawGraph( G );
Here is the picture you get from Maple.
Note that in this case direction was not very important as every edge is two-sided, but in general matrix-multiplication is not commutative so in a different case (if your edge definition is different) you may want to keep the direction and also that is why I did not simplify the nested-loops for E to a n(n-1)/2 cases and kept the whole n^2 cases.

How to make an indicator function or handle for glmfit?

I have a question about creating a handle or indicator function. I have a X matrix that contains 4 explanatory variables and one column (the last one, column 5) of ones and twos that indicates if the observation belongs to group 1 by 1 or group 2 by 2. I want to perform 2 glmfit. One for the observations belonging to group 1, and one for the observations belonging to group 2. I thus need some kind of indicator function so that the glmfit will only calculate the observations of the specific group. Can somebody help me how I can so this? I make use of the following glmfit:
[B1, dev, stats1] = glmfit(X(:,1:4), Y, 'binomial', 'link', 'logit');
Does the following do the job?
indicator = X(:, 5)
[B1, dev, stats1] = glmfit(X(indicator==1,1:4), Y, 'binomial', 'link', 'logit');
[B2, dev, stats2] = glmfit(X(indicator==2,1:4), Y, 'binomial', 'link', 'logit');
In the above, X(indicator==1, 1:4) employs what is called logical indexing, see also here. It provides a submatrix of X, consisting of only the rows where indicator has an entry of 1.

calculate conservative interpolation of two vectors in matlab

G'day
Firstly, apologies for poor wording - I'm at a bit of a loss of how to describe this problem. I'm trying to calculate the conservative interpolation between two different vertical coordinate systems.
I have a vector of ocean transport values Ts, that describe the amount of transport at different depth values S. These depths are unevenly spaced (and size(S) is equal to size(Ts)+1 as the values in S are the depths at the top and bottom over which the transport value applies). I want to interpolate(/project?) this onto a vector of regularly spaced depths Z, where each new transport value Tz is formed from the values of Ts but weighted by the amount of overlap.
I've drawn a picture of what I mean (sorry for the bad quality webcam picture) I want to go from Ts1,Ts2.Ts3...TsN (bottom lines) to Tz1,Tz2,...TzN (top lines). The locations in the x direction for these are s0,s1,s2,...sN and z0,z1,z2,...zN. An example of the 'weighted overlap' would be:
Tz1 = a/(s1-s0) Ts1 + b/(s2-s1) Ts2 + c/(s3-s2) Ts3
where a, b and c are shown in the image as the length of overlap.
Some more details:
Example of z and s follow:
z = 0:5:720;
s = [222.69;...
223.74
225.67
228.53
232.39
237.35
243.56
251.17
260.41
271.5
284.73
300.42
318.9
340.54
365.69
394.69
427.78
465.11
506.62
551.98
600.54
651.2];
Note that I'm free to define z, but not s. Typically, z will be bigger than s (i.e. the smallest value in z will be smaller than in s, while the largest value in z will be larger than in s).
Help or tips greatly appreciated. Cheers,
Dave
I don't think there is an easy solution, as stated in the comments. I'll give it a go though :
One hypothesis first : We assume z0>s0 in order for your problem to be defined.
The idea (for your example) would be to get to the array below :
1 (s1-z0) s1-s0 Ts1
1 (s2-s1) s2-s1 Ts2
1 (z1-s2) s3-s2 Ts3
2 (s3-z1) s3-s2 Ts3
2 (z2-s3) s4-s3 Ts4
3 (z3-z2) s4-s3 Ts4
......
Then we would be able to compute, for each row : column1*column3/column2 and then use accumarray to sum the results with respect to the indexes in the first column.
Now the hardest part is to get this array :
Suppose you have :
A Nx1 vectors Ts
2 (N+1)x1 vectors s and z, with z(1)>s(1).
Vectsz=sort([s(2:end);z]); % Sorted vector of s and z values
In your case this vector should look like :
z0
s1
s2
z1
s3
z2
z3
...
The first column will serve as a subscript to apply accumarray, so we'll want it to increase each time there is a z value in our vector Vectsz
First=interp1(z,1:length(z),Vectsz,'previous');
Second=[diff(Vectsz);0]; % Padded with a 0 to keep the right size
Temp=diff(s);
Third=interp1(s(1:end-1),Temp,Vectsz,'previous');
This will just repeat the diff value everytime you have a z value in your vector Vectsz.
The last column is built exactly like the third one
Fourth=interp1(s(1:end-1),Ts,Vectsz,'previous');
Now that the array is built, a call to accumarray is enough to get the final result :
Res=accumarray(First,Second.*Fourth./Third);
EDIT : There is actually no need for the use of interp1 with the previous option :
Vectsz=sort([s(2:end);z]);
First=cumsum(ismember(Vectsz,z));
Second=[diff(Vectsz);0];
idx=cumsum(ismember(Vectsz,s(2:end)))+1;
Diffs=[diff(s);0];
Third=Diffs(idx);
Fourth=Ts(idx);
Res=accumarray(First,Second.*Fourth./Third);

How to calculate indegree and outdegree for a graph in directed graph SML code?

I have a tuple like (1,2),(3,4),(4,5). Edges: 1->2, 3->4 and so on.
How calculate in degree and out degree for each vertex?
you can write a function take in a list of tuples which are the edges.
accumulate another list of tuples or (records), with format of [(node, inDgree, OutDgree),...]
records [{node=int, inDgree=int, outDgree = int},...]
fun degrees ((a,b)::(as,bs)) = ....
The out-degree of vertex v is the number of pairs (x, y) where x == v, since each such pair corresponds to an edge starting at v. Likewise, the in-degree of v is the number of pairs (x, y) where y == v.
Does that give you enough of the basic idea?

Permuting n elements by swapping each element by no more than k positions

What I have is a vector (n = 4 in the example):
x = '0123';
What I want is a vector y of the same size of x and with the same elements as in x in different order:
y = ['0123'; '0132'; '0213'; '0231'; '0312'; '0321'; '1023'; '1032'; '1203'; '1302'; '2013'; '2031'; '2103'; '2301'];
y(ceil(rand * numel(y(:, 1))), :)
i.e. a permutation such that each element in y is allowed to randomly change no more than k positions with respect to its original position in x (k = 2 in the example). The probability distribution must be uniform (i.e. each permutation must be equally likely to occur).
An obvious but inefficient way to do it is of course to find a random unconstrained permutation and check ex post whether or not this happens to respect the constraint. For small vectors you can find all the permutations, delete those that are not allowed and randomly pick among the remaining ones.
Any idea about how to do the same more efficiently, for example by actually swapping the elements?
Generating all the permutations can be done easily using constraint programming. Here is a short model using MiniZinc for the above example (note that we assume that x will contain n different values here):
include "globals.mzn";
int: k = 2;
int: n = 4;
array[1..n] of int: x = [0, 1, 2, 3];
array[1..n] of var int: y;
constraint forall(i in 1..n) (
y[i] in {x[i + offset] | offset in -min(k, i-1)..min(k, n-i)}
);
constraint all_different(y);
solve :: int_search(y, input_order, indomain_min, complete)
satisfy;
output [show(y)];
In most cases, constraint programming systems have the possibility to use a random search. However, this would not give you a uniform distribution of the results. Using CP will however generate all valid permutations more efficiently than the naive method (generate and test for validity).
If you need to generate a random permutation of your kind efficiently, I think that it would be possible to modify the standard Fisher-Yates shuffle to handle it directly. The standard algorithm uses the rest of the array to choose the next value from, and chooses the value with a probability distribution that is uniform. It should be possible to keep a list of only the currently valid choices, and to change the probability distribution of the values to match the desired output.
I don't see any approach other than the rejection method that you mention. However, instead of listing all allowed permutations and then picking one, it's more efficient to avoid that listing. Thus, you can randomly generate a permutation, check if it's valid, and repeat if it's not:
x = '0123';
k = 2;
n = numel(x);
done = 0;
while ~done
perm = randperm(n);
done = all( abs(perm-(1:n)) <= k ); %// check condition
end
y = x(perm);