OR-Tools: compare lists in solver maximize - or-tools

Lets say I have 2 lists: list_1 and list_2 of the same size containing Bool variables
list_1 = [ model.NewBoolVar('var1'), ..., model.NewBoolVar('var9')]
list_2 = [ model.NewBoolVar('var10'), ..., model.NewBoolVar('var19') ]
I then add other constraints and I finally want to maximize so that to 2 lists should be the most alike. I have though of doing of sum of the XNor result between each elements of both lists but I do not know how to do this? What should I do?

You can use enforced linear constraints.
bi => xi == yi
bi.not() => xi != yi
Then sum of bi

Related

Double Summation expression in MATLAB

I have a Parameter matrix, C of size 2x2. It looks like this.
C= [2 4; 6 8]
I have a decision variable, X of size 2x2. It looks like this
[ X('S1', 'D1') X('S1', 'D2') ]
[ X('S2', 'D1') X('S2', 'D2') ]
I want to formulate my Objective Function as a series of double expression (Please refer the attachment),
Which shall look like the following after the expansion.
Z = 2*X('S1', 'D1') + 4*X('S1', 'D2') + 6*X('S2', 'D1') + 8*X('S2', 'D2')
I try the following.
Z = sum(C.*X,1);
But it creates An optimizationExpression of size 1x3, which is not desired.
What am I doing wrong? Is there any easier way to do so without using for loop. I have just started learning "Problem-Based Optimization" in MATLAB today. Any help will be greatly appreciated.
As C and X are 2x2 matrices, so C.*X gives a 2x2 matrix. With sum(C.*X,1);, summation is done along the first dimension (i.e. rows are added). But you want to sum all the elements. So if you convert your matrices into a vector and then multiply element-wise and then apply sum, it will add all the elements i.e.
Z = sum(C(:).*X(:));
Alternatively, you can first multiply and then convert the result into a vector before applying sum.
CX = C.*X;
Z = sum(CX(:));
or sum along all the dimensions one by one. But I'd go with the solution suggested in the beginning.

Table functions/interpolation in Netlogo

I am combining and rewriting some system dynamics models (i.e. stock-and-flow models) with agent based models in Netlogo.
System dynamics models often include table functions for describing non-linear relationships. If we have two continuous variables x and y, and we know that an approximate relationship is (x = 0, y = 100; x = 1, y = 50; x = 2, y = 45, x = 3, y = 40; x = 4, y = 35), we can use interpolation to find the value of y for any value of x. In R, for instance, you can use the appoxfun() function.
Is there a way of addressing these relationships in Netlogo, in absence of actually knowing the causal mechanisms and coding them in the model? I have searched around on internet resources, but haven't been able to find much.
Thanks for your help!
There is not an existing function. However, it is straightforward to construct an interpolation function that you can call. This version does linear interpolation and handles values outside the specified range of x values by reporting the appropriate end y value. Someone who is better than me at list functions (eg reduce) might find a more elegant method.
to-report calc-piecewise [#xval #xList #yList]
if not (length #xList = length #ylist)
[ report "ERROR: mismatched points"
]
if #xval <= first #xList [ report first #yList ]
if #xval >= last #xList [ report last #yList ]
; iterate through x values to find first that is larger than input x
let ii 0
while [item ii #xlist <= #xval] [ set ii ii + 1 ]
; get the xy values bracketing the input x
let xlow item (ii - 1) #xlist
let xhigh item ii #xlist
let ylow item (ii - 1) #ylist
let yhigh item ii #ylist
; interpolate
report ylow + ( (#xval - xlow) / (xhigh - xlow) ) * ( yhigh - ylow )
end
to testme
let xs [0 1 2 3 4]
let ys [100 50 30 20 15]
print calc-piecewise 1.5 xs ys
end
This version requires you to specify the x-value list and y-value list (as well as the x value for interpolation) each time you use it. If you are always going to use the same points, they can be specified inside the function.

In matlab how to sum rows of a matrix according to specified bins/subscripts in a non-iteration manner?

This question generalizes the previous one Any way for matlab to sum an array according to specified bins NOT by for iteration? Best if there is buildin function for this. I am not sure, but I tried and the answers in previous post seem not to work with matrices.
For example, if
A = [7,8,1,1,2,2,2]; % the bins or subscripts
B = [2,1; ...
1,1; ...
1,1; ...
2,0; ...
3,1; ...
0,2; ...
2,4]; % the matrix
then the desired function "binsum" has two outputs, one is the bins, and the other is the accumulated row vectors. It is adding rows in B according to subscripts in A. For example, for 2, the sum is [3,1] + [0,2] + [2,4] = [5,6], for 1 it is [1,1] + [2,0] = [3,1].
[bins, sums] = binsum(A,B);
bins = [1,2,7,8]
sums = [2,1;
1,1;
3,1;
5,6]
The first method accumarray says its "val" argument can only be a scalar or vector. The second method spare seems not to accept a vector as the value "v" for each tuple (i,j) neither. So I have to post for help again, and it is still not desired to use iterations to go over the columns of B to do this.
I am using 2017a. Many thanks again!
A way to do that is using matrix multiplication:
bins = unique(A);
sums = (A==bins.')*B;
The above is memory-expensive, as it builds an intermediate logical matrix of size M×N, where M is the the number of bins and N is the length of A. Alternatively, you can build that matrix as sparse logical to save memory:
[bins, ~, labels] = unique(A);
sums = sparse(labels, 1:numel(A), true)*B;
A method base on sort and cumsum:
[s,I]=sort(A);
c=cumsum(B(I,:));
k= [s(1:end-1)~=s(2:end) true];
sums = diff([zeros(1,size(B,2)); c(k,:)])
bins=s(k)

Windowed subtraction of vectors that are not same size and then finding the mean of results

Good day,
I have a question what I want to achieve without the loop if possible. As title says I need to do windowed subtraction of vectors that are not same size and then finding the mean of results.
As example, let say that we have vector a = [2 3 4 5 6] and vector b = [1 2].
Program will have to move window with smaller numbers of elements (in this example vector b) over bigger one (vector a) and make operations on that way so it starts in first two elements in vector a and make subtraction with vector b and then sum results and find mean.
In this example it will just make calculation of subtraction 2-1 = 1, 3-2 = 1, summing results 1+1=2 and divide them with 2 (because vector b is that size). Final result is 1.
Then we move window on second elements of vector a (value 3 and 4 there, or index 2 and 3) and repeat process to the last elements of vector a.
For final result we need to get vector c who consist of elements [1 2 3 4] for this example.
Is this possible to do without looping because I have data sets over 10k of size. Thanks in advance
I can solve it with only one loop, iterating through "b" (two loops in your example).
Declare vectors (as columns! This is needed for matlabs computations to work)
a = [2 3 4 5 6]';
b = [1 2]';
Declare matrix for computed results. Each column represents subtractions of elements in "a" with one of the elements in "b".
c = zeros(length(a)-length(b)+1,length(b));
for k = 1:length(b)
c(:,k) = a(k:length(a)-length(b)+k)-b(k);
end
Now just sum the elements in "c" row wise and divide by length of "b" to get the mean
result = sum(c,2)/length(b);
You can simplify this for your exact example, but this is a generic solution for any vetors "a" and "b", where "b" is the smaller vector.

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);