MiniZinc join arrays of variables by index - arrays

I have a MiniZinc program with 3 arrays of variables of the following form:
array[NbLines] of var Domain: vars1;
array[NbLines, NbRows] of var Domain: vars2;
array[NbLines, NbRows] of var Domain: vars3;
I need to specify my search variable order in the following way, but I did not success to correctly construct my array. There is the MiniZinc like code:
varsOrder = [[vars1[i]] ++ row(vars2, i) ++ row(vars3, i) | i in NbLines]
MiniZinc indicates that arrays are not allowed in array comprehension expressions. How should I do?
Thank you for your help.

As you have noticed, you cannot concatenate arrays like this. What I can think of are two approaches, though the first is not exactly what you want.
1) use array1d(array)
You can flatten matrices (2d arrays) with "array1d" like this:
solve :: int_search(vars1 ++ array1d(vars2) ++ array1d(vars3), first_fail, indomain_min, complete) satisfy;
However, this is not exactly the same as what you write above, but it's way easier than the next approach:
2) Make a master array and insert all the elements in the proper positions.
int: totLen = ...; % the total length of all the arrays
array[1..totLen] of var Domain: all;
You have to do a loop to insert all the elements in the exact position you want in the "all" array. However, I leave this as an exercise. :-)
Then the "all" array can be used in the labeling:
solve :: int_search(all, first_fail, indomain_min, complete) satisfy;

Related

Julia: Questions about array where the dimension is not determined

I have two beginner's questions:
(1) I want to reshape an array, but dimensions come from a vector which can be a variable. For example,
A = ones(120,1)
b = [2,3,4,5]
I can write
C = reshape(A,2,3,4,5)
But in case b can vary, I want something like
C = reshape(A,b)
This code works in Matlab. Is there an analog in Julia?
(2) I want to slice a high-dimensional array, while keeping the dimensions flexible. In the example above, I fix the last dimension:
C[:,:,:,1]
C[:,:,:,2]
etc. The problem is to find an efficient way: For an array of any dimensions, I can always fix the last dimension and extract values.
Any help will be highly appreciated!
(1) C = reshape(A,b...)
(2) EllipsisNotation.jl provides a .. operator, so C[..,1] does what you want.
And there is C[ntuple(x->:, ndims(C)-1)..., 1] for (2) if you don't want to install a package.

How to convert vectors to arrays in ECLiPSe (CLP)? (or Prolog)

I have to solve Sudoku puzzles in the format of a vector containing 9 vectors (of length 9 each). Seeing as vectors are linked lists in Prolog, I figured the search would go faster if I transformed the puzzles in a 2D array format first.
Example puzzle:
puzzle(P) :- P =
[[_,_,8,7,_,_,_,_,6],
[4,_,_,_,_,9,_,_,_],
[_,_,_,5,4,6,9,_,_],
[_,_,_,_,_,3,_,5,_],
[_,_,3,_,_,7,6,_,_],
[_,_,_,_,_,_,_,8,9],
[_,7,_,4,_,2,_,_,5],
[8,_,_,9,_,5,_,2,3],
[2,_,9,3,_,8,7,6,_]].
I'm using ECLiPSe CLP to implement a solver. The best I've come up with so far is to write a domain like this:
domain(P):-
dim(P,[9,9]),
P[1..9,1..9] :: 1..9.
and a converter for the puzzle (parameter P is the given puzzle and Sudoku is the new defined grid with the 2D array). But I'm having trouble linking the values from the given initial puzzle to my 2D array.
convertVectorsToArray(Sudoku,P):-
( for(I,1,9),
param(Sudoku,P)
do
( for(J,1,9),
param(Sudoku,P,I)
do
Sudoku[I,J] is P[I,J]
)
).
Before this, I tried using array_list (http://eclipseclp.org/doc/bips/kernel/termmanip/array_list-2.html), but I kept getting type errors. How I did it before:
convertVectorsToArray(Sudoku,P):-
( for(I,1,9),
param(Sudoku,P)
do
( for(J,1,9),
param(Sudoku,P,I)
do
A is Sudoku[I],
array_list(A,P[I])
)
).
When my Sudoku finally outputs the example puzzle P in the following format:
Sudoku = []([](_Var1, _Var2, 8, 7, ..., 6), [](4, ...), ...)
then I'll be happy.
update
I tried again with the array_list; it almost works with the following code:
convertVectorsToArray(Sudoku,P):-
( for(I,1,9),
param(Sudoku,P)
do
X is Sudoku[I],
Y is P[I],
write(I),nl,
write(X),nl,
write(Y),nl,
array_list(X, Y)
).
The writes are there to see how the vectors/arrays look like. For some reason, it stops at the second iteration (instead of 9 times) and outputs the rest of the example puzzle as a vector of vectors. Only the first vector gets assigned correctly.
update2
While I'm sure the answer given by jschimpf is correct, I also figured out my own implementation:
convertVectorsToArray(Sudoku,[],_).
convertVectorsToArray(Sudoku,[Y|Rest],Count):-
X is Sudoku[Count],
array_list(X, Y),
NewCount is Count + 1,
convertVectorsToArray(Sudoku,Rest,NewCount).
Thanks for the added explanation on why it didn't work before though!
The easiest solution is to avoid the conversion altogether by writing your puzzle specification directly as a 2-D array. An ECLiPSe "array" is simply a structure with the functor '[]'/N, so you can write:
puzzle(P) :- P = [](
[](_,_,8,7,_,_,_,_,6),
[](4,_,_,_,_,9,_,_,_),
[](_,_,_,5,4,6,9,_,_),
[](_,_,_,_,_,3,_,5,_),
[](_,_,3,_,_,7,6,_,_),
[](_,_,_,_,_,_,_,8,9),
[](_,7,_,4,_,2,_,_,5),
[](8,_,_,9,_,5,_,2,3),
[](2,_,9,3,_,8,7,6,_)).
You can then use this 2-D array directly as the container for your domain variables:
sudoku(P) :-
puzzle(P),
P[1..9,1..9] :: 1..9,
...
However, if you want to keep your list-of-lists puzzle specification, and convert that to an array-of-arrays format, you can use array_list/2. But since that only works for 1-D arrays, you have to convert the nesting levels individually:
listoflists_to_matrix(Xss, Xzz) :-
% list of lists to list of arrays
( foreach(Xs,Xss), foreach(Xz,Xzs) do
array_list(Xz, Xs)
),
% list of arrays to array of arrays
array_list(Xzz, Xzs).
As for the reason your own code didn't work: this is due to the subscript notation P[I]. This
requires P to be an array (you were using it on lists)
works only in contexts where an arithmetic expression is expected, e.g. the right hand side of is/2, in arithmetic constraints, etc.

Concise way to create an array filled within a range in Matlab

I need to create an array filled within a range in Matlab
e.g.
from=2
to=6
increment=1
result
[2,3,4,5,6]
e.g.
from=15
to=25
increment=2
result
[15,17,19,21,23,25]
Obviously I can create a loop to perform this action from scratch but I wondering if there is a coincise and efficent way to do this with built-in matlab commands since seems a very common operation
EDIT
If I use linspace the operation is weird since the spacing between the points is (x2-x1)/(n-1).
This can be handled simply by the : operator in the following notation
array = from:increment:to
Note that the increment defaults to 1 if written with only one colon seperator
array = from:to
Example
array1 = 2:6 %Produces [2,3,4,5,6]
array2 = 15:2:25 %Produces [15,17,19,21,23,25]

Extract one Logical variable from several Elementwise-Conditions in multidimensional arrays in Matlab

What is the most elegant way to reduce elementwise-conditions in multidimensional-arrays to one logical variable in Matlab? I need this for a big project with a lot of if conditions and assertions. In the Matlab documentation about logical arrays and find array elements there is no satifying solution for this problem.
For example, a logical variable myBool is true iff there are two ones at the same position in the matrices A and B:
A = [0,1;0,0]
B = [0,1;1,0]
My preferred solution so far is:
myBool = any(A(:)==1 & B(:)==1)
But it doesn't look like the shortest solution and it doesn't work with array indexing.
A shorter but not very readable solution:
myBool = any(A(B==1))
The biggest problem is that for higher dimensional arrays the functions like nnz() only reduce the order by one dimension without the colon (:), but with the colon it is not possible to index a part of the array...
Firstly, if you use matrices of class logical, then you don't need to test for equality to 1.
Indexing aside, the best approach would be:
bFlag = any(A(:) & B(:));
If you need indexing, you have two options. You can use a small vectorising anonymous function:
fhVec = #(T)(T(:));
bFlag = any(fhVec(A(rowIndices, colIndices) & B(rowIndices, colIndices)));
alternatively, you can use linear indexing:
vnLinearIndices = sub2ind(size(A), rowIndices, colIndices);
bFlag = any(A(vnLinearIndices) & B(vnLinearIndices));

addressing cell arrays of structures

I have following cell array:
res{1}.nft.x=1;
res{2}.nft.x=2;
res{3}.nft.x=3;
How can I easily get an array of nft.x values, i.e., [1 2 3] in this case?
Thanks!
use cellfun
>> cellfun( #(x) x.nft.x, res )
Use comma-separated lists (a very powerful feature in MATLAB):
v = [res{:}];
v = [v.nft];
v = [v.x];
Of course, this only works if all structures have the identical fields. If not, you'll have to resort to a loop or something similar, for instance:
cellfun(#(x)x.nft.x, res)
the latter may seem a bit more elegant, but it's definitely much slower for a larger data set.
Clarification
res{:} creates a comma separated list of structs, and [res{:}] concatenates them into an array. Accessing a field of an array of structs again results in a comma separated list, hence the additional concatenation, field access and yet another concatenation.

Resources