Shuffle a list in Minizinc - minizinc

array[1..6] of var 0..1: Path;
include "alldifferent.mzn";
constraint
forall(j in 1..6)(
alldifferent(i in 1..6)(Path[i])
)
Iam trying to shuffle a list into minizinc but i want different results every time like with a for all . how can i do it?
print this:
Path = array1d(1..6, [5, 4, 3, 2, 1, 0]);

There are - at least - two approaches for generating a random matrix depending on if you want to generate all possible variables (the first model below using decision values), or if you just want a "random" random matrix (the second model using built-in random generator). (A third approach would be that you write your own random generator, but this is left as an exercise :-)).
Here is a simple MiniZinc model that generates all the possible 6x6 matrices of {0,1} as decision variables.
int: n = 6;
array[1..n,1..n] of var 0..1: x;
solve :: int_search(array1d(x), first_fail, indomain_random) satisfy;
constraint
true
;
output
[
if j = 1 then "\n" else " " endif ++
show(x[i,j])
| i,j in 1..n
];
Note: The indomain_random heuristic generates the solutions in a more "random-like" order.
There is another way of doing this, using the bernoulli(0.5) function, which generates randomly 0 or 1 during the creation of the model, i.e. it's not decision variables:
int: n = 6;
array[1..n,1..n] of int: x = array2d(1..n,1..n,[ bernoulli(0.5) | i,j in 1..n]);
solve satisfy;
constraint
true
;
output
[
if j = 1 then "\n" else " " endif ++
show(x[i,j])
| i,j in 1..n
];
Which happens to generate the following matrix:
1 1 1 0 0 0
1 0 1 1 0 0
0 0 0 0 1 1
0 1 0 0 1 0
1 1 1 1 0 1
0 1 1 1 1 1
The drawback of this is that you then have to manually seed the random generator for generating different matrices. This is (according to https://www.minizinc.org/doc-2.5.1/en/command_line.html?highlight=random#cmdoption-r ) done with the --random-seed i flag (or -r i) but this don't work right now on my MiniZinc version.
MiniZinc has quite a few random generators, see more here: https://www.minizinc.org/doc-2.5.1/en/lib-stdlib.html?highlight=random#random-number-generator-builtins .

Related

How to deal with indexing involving three vectors?

I have the following three vectors:
trans_now=[1 2 4]; data2send=[1 0 0 1]; datasent=[0 0 0 0];
I want to set datasent to 1 for those nodes that are members of tran_now and whose data2send status is 1. e.g 4 is a member of trans_now and data2send(4) is 1 therefore datasent(4) should be set to 1.
I can do it using for loop and if statement as shown in the code below.
for i=1:length(trans_now)
if data2send(trans_now(i))==1
datasent(trans_now(i))=1;
end
end
However I want one liner code for this. The one liner code that I tried is
req_sent(req2send(trans_now)==1)=1;
But it doesn't work.
The output should set datasent vector to [1 0 0 1].
you could solve this in 2 ways:
1.
data_sent(trans_now) = data2send(trans_now)
the output is:
data_sent =
1 0 0 1
In this solution I assumed that all the initial values of data_sent are starting as 0 and that you need to assign it once.
2.
datasent(intersect(find(data2send == 1), trans_now)) = 1
output is:
data_sent =
1 0 0 1
In this solution no assumption is used and you assign only indices where data2send == 1 and also appear in trans_now

Output a matrix size n x m, 1 when the sum of the indices is even, 0 otherwise

I'm attempting the following as a hobby, not as homework. In Computer Programming with MATLAB: J. Michael Fitpatrick and Akos Ledeczi, there is a practice problem that asks this:
Write a function called alternate that takes two positive integers, n and m, as input arguments (the function does not have to check the format of the input) and returns one matrix as an output argument. Each element of the n-by-m output matrix for which the sum of its indices is even is 1.
All other elements are zero.
A previous problem was similar, and I wrote a very simple function that does what it asks:
function A = alternate(n,m)
A(1:n,1:m)=0;
A(2:2:n,2:2:m)=1;
A(1:2:n,1:2:m)=1;
end
Now my question is, is that good enough? It outputs exactly what it asks for, but it's not checking for the sum. So far we haven't discussed nested if statements or anything of that sort, we just started going over very basic functions. I feel like giving it more functionality would allow it to be recycled better for future use.
Great to see you're learning, step 1 in learning any programming language should be to ensure you always add relevant comments! This helps you, and anyone reading your code. So the first improvement would be this:
function A = alternate(n,m)
% Function to return an n*m matrix, which is 1 when the sum of the indices is even
A(1:n,1:m)=0; % Create the n*m array of zeros
A(2:2:n,2:2:m)=1; % All elements with even row and col indices: even+even=even
A(1:2:n,1:2:m)=1; % All elements with odd row and col indicies: odd+odd=even
end
You can, however, make this more concise (discounting comments), and perhaps more clearly relate to the brief:
function A = alternate(n,m)
% Function to return an n*m matrix, which is 1 when the sum of the indices is even
% Sum of row and col indices. Uses implicit expansion (R2016b+) to form
% a matrix from a row and column array
idx = (1:n).' + (1:m);
% We want 1 when x is even, 0 when odd. mod(x,2) is the opposite, so 1-mod(x,2) works:
A = 1 - mod( idx, 2 );
end
Both functions do the same thing, and it's personal preference (and performance related for large problems) which you should use.
I'd argue that, even without comments, the alternative I've written more clearly does what it says on the tin. You don't have to know the brief to understand you're looking for the even index sums, since I've done the sum and tested if even. Your code requires interpretation.
It can also be written as a one-liner, whereas the indexing approach can't be (as you've done it).
A = 1 - mod( (1:n).' + (1:m), 2 ); % 1 when row + column index is even
Your function works fine and output the desired result, let me propose you an alternative:
function A = alternate(n,m)
A = zeros( n , m ) ; % pre-allocate result (all elements at 0)
[x,y] = meshgrid(1:m,1:n) ; % define a grid of indices
A(mod(x+y,2)==0) = 1 ; % modify elements of "A" whose indices verify the condition
end
Which returns:
>> alternate(4,5)
ans =
1 0 1 0 1
0 1 0 1 0
1 0 1 0 1
0 1 0 1 0
initialisation:
The first line is the equivalent to your first line, but it is the cannonical MATLAB way of creating a new matrix.
It uses the function zeros(n,m).
Note that MATLAB has similar functions to create and preallocate matrices for different types, for examples:
ones(n,m) Create
a matrix of double, size [n,m] with all elements set to 1
nan(n,m) Create a
matrix of double, size [n,m] with all elements set to NaN
false(n,m) Create a
matrix of boolean size [n,m] with all elements set to false
There are several other matrix construction predefined function, some more specialised (like eye), so before trying hard to generate your initial matrix, you can look in the documentation if a specialised function exist for your case.
indices
The second line generate 2 matrices x and y which will be the indices of A. It uses the function meshgrid. For example in the case shown above, x and y look like:
| x = | y = |
| 1 2 3 4 5 | 1 1 1 1 1 |
| 1 2 3 4 5 | 2 2 2 2 2 |
| 1 2 3 4 5 | 3 3 3 3 3 |
| 1 2 3 4 5 | 4 4 4 4 4 |
odd/even indices
To calculate the sum of the indices, it is now trivial in MATLAB, as easy as:
>> x+y
ans =
2 3 4 5 6
3 4 5 6 7
4 5 6 7 8
5 6 7 8 9
Now we just need to know which ones are even. For this we'll use the modulo operator (mod) on this summed matrix:
>> mod(x+y,2)==0
ans =
1 0 1 0 1
0 1 0 1 0
1 0 1 0 1
0 1 0 1 0
This result logical matrix is the same size as A and contain 1 where the sum of the indices is even, and 0 otherwise. We can use this logical matrix to modify only the elements of A which satisfied the condition:
>> A(mod(x+y,2)==0) = 1
A =
1 0 1 0 1
0 1 0 1 0
1 0 1 0 1
0 1 0 1 0
Note that in this case the logical matrix found in the previous step would have been ok since the value to assign to the special indices is 1, which is the same as the numeric representation of true for MATLAB. In case you wanted to assign a different value, but the same indices condition, simply replace the last assignment:
A(mod(x+y,2)==0) = your_target_value ;
I don't like spoiling the learning. So let me just give you some hints.
Matlab is very efficient if you do operations on vectors, not on individual elements. So, why not creating two matrices (e.g. N, M) that holds all the indices? Have a look at the meshgrid() function.
Than you might be able find all positions with an even sum of indices in one line.
Second hint is that the outputs of a logic operation, e.g. B = A==4, yields a logic matrix. You can convert this to a matrix of zeros by using B = double(B).
Have fun!

How to separate rows of cells in a matrix using logical indexing?

l2 = [{'walk', 'water', 'warm', 'cheer', 'word', 'happy', 'whim', 'womb', 'wear', 'well'};
{'hello', 'here', 'hat', 'that', 'happy', 'hide', 'awesome', 'there', 'howl', 'harry'};
{'look', 'listen', 'lyer', 'hateful', 'lost', 'hatred', 'plot', 'player', 'plow', 'lay'};
{'goat', 'meat', 'hope', 'house', 'love', 'wall', 'down', 'up', 'sky', 'mount'};
{'go', 'golf', 'loser', 'gyrus', 'terrible', 'gallore', 'tug', 'thor', 'gear', 'leg'}];
So I have this data above, and I want to be able to separate each row in terms of it being either positive or negative.
As you can see above: My first row has 2 positive targets amongst neutral words and the third row has 2 negative targets amongst neutral words.
Now if I was running this where the participant saw each word in a sequence per row, how can I get an accuracy for their response to a row with positive targets vs negative target?
Any ideas?
Please help, I just cant figure it out
So far I was thinking of using logical indexing to separate positive targets and negative target, but how do I do that with cell rows?
I have this:
positive_t = [1 1; 1 1; 0 0; 1 1; 0 0]
This above denotes all the positive targets as 1 and negative targets as 0 but how would I be able to separate them properly row by row? Also. Then if I want to find how many time the participants got the answer for positive row vs negative row. How can I save the accuracy of that?
I assume 1) you want to test a person's ability to pick out positive or negative words and 2) you already have a standard answer ( as your test standard ) that you're going to compare testee's answer against.
I don't know what your definition of positive is, so I'm also being tested by you in a sense, but let's assume that you have this standard answer :
std_answer = logical([ 0 0 0 0 0 1 0 0 0 1;... % 'happy' and 'well'
0 0 0 0 1 0 1 0 0 0;... % 'happy' and 'awesome'
0 0 0 1 0 1 0 0 0 0;... % 'hateful' and 'hatred'
0 0 1 0 1 0 0 0 0 0;... % 'hope' and 'love'
0 0 1 0 1 0 0 0 0 0 ]); % 'loser' and 'terrible'
The std_answer here is an logical array that has the same number of elements as your l2. It has value of 1 wherever your answer is ( which of course, as a tester you already know. Here I'm just taking some guess and assume the standard answer to make an example) and 0 otherwise.
You can apply this mask to your l2 and the result will be your answers
answers = l2(std_answer);
If you really wish to do it row by row, of course you can do this:
for ii = 1:size(l2, 1)
sublist = l2(ii, :);
submask = std_answer(ii, :);
answer = sublist(submask);
end
At the end of the test, you'll have a testee response ( let's say you named it test_response) that's also a 5*10 logical array. You can compare the testee response to standard answer by using logical operation:
score = test_response & std_answer ;
score will also be a logical array whose 1 indicate a match between testee response and standard answer.

change a value by a probability value in matlab

I want to change a variable by probability value,
as a example I have [ 0 0 1 1 1 1 0 1 ] in matlab and with probability = 0.01 change any elemet of it , how can I achive this in matlab?
(I want use this in GA and with p =0.01 do mutation of Gen of choromosome )
appreciate any help
First, identify all the elements you want to change
array = [0 0 1 1 1 1 0 1];
sizArray = size(array);
probability = 0.01;
toChangeIdx = rand(sizArray) < probability;
Then, you can flip zeros and ones where needed
array(toChangeIdx) = 1-array(toChangeIdx);
The relevant condition for your code is
if rand() < probability
% Flip your bit here, e.g.
% bitToFlip = randi(length(genome));
% genome(bitToFlip) = 1 - genome(bitToFlip);
end
This will run the code inside the if statement with a probability of exactly probability.

MATLAB - Efficient methods for populating matrices using information in other (sparse) matrices?

Apologies for the awkward title, here is a more specific description of the problem. I have a large (e.g. 10^6 x 10^6) sparse symmetric matrix which defines bonds between nodes.
e.g. The matrix A = [0 1 0 0 0; 1 0 0 2 3; 0 0 0 4 0; 0 2 4 0 5; 0 3 0 5 0] would describe a 5-node system, such that nodes 1 and 2 are connected by bond number A(1,2) = 1, nodes 3 and 4 are connected by bond number A(3,4) = 4, etc.
I want to form two new matrices. The first, B, would list the nodes connected to each node (i.e. each row i of B has elements given by find(A(i,:)), and padded with zeros at the end if necessary) and the second, C, would list the bonds connected to that node (i.e. each row i of C has elements given by nonzeros(A(i,:)), again padded if necessary).
e.g. for the matrix A above, I would want to form B = [2 0 0; 1 4 5; 4 0 0; 2 3 5; 2 4 0] and C = [1 0 0; 1 2 3; 4 0 0; 2 4 5; 3 5 0]
The current code is:
B=zeros(length(A), max(sum(spones(A))))
C=zeros(length(A), max(sum(spones(A))))
for i=1:length(A)
B(i,1:length(find(A(i,:)))) = find(A(i,:));
C(i,1:length(nonzeros(A(i,:)))) = nonzeros(A(i,:));
end
which works, but is slow for large length(A). I have tried other formulations, but they all include for loops and don't give much improvement.
How do I do this without looping through the rows?
Hmm. Not sure how to vectorize (find returns linear indices when given a matrix, which is not what you want), but have you tried this:
B=zeros(length(A), 0);
C=zeros(length(A), 0);
for i=1:length(A)
Bi = find(A(i,:));
B(i,1:length(Bi)) = Bi;
Ci = nonzeros(A(i,:));
C(i,1:length(Ci)) = Ci;
end
I made two changes:
removed call to spones (seems unnecessary; the performance hit needed to expand the # of columns in B and C is probably minimal)
cached result of find() and nonzeros() so they're not called twice
I know it's hard to read, but that code is a vectorized version of your code:
[ i j k ] = find(A);
A2=(A~=0);
j2=nonzeros(cumsum(A2,2).*A2);
C2=accumarray([i,j2],k)
k2=nonzeros(bsxfun(#times,1:size(A,2),A2));
B2=accumarray([i,j2],k2);
Try it and tell me if it works for you.