I am trying to write an output statement with nested loops, and non-trivial output at the outer levels. If Minizinc had a top level for
command, I would do something like
for (f in Foo) (
output(["Foo: ", f])
for (b in Bar) (
for (q in Quz) (
output([myArray[f,b,q], " "]);
)
output(["\n"]);
)
output(["\n"]);
)
so that if
myArray = [[[1,2], [3,4]], [[5,6], [7,8]]];
it would output
Foo: 1
1 2
3 4
Foo: 2
5 6
7 8
I think I can do this with something like
output(if (b = 1 /\ q = 1) then "Foo: " ++ show(f) else "" endif ++
show(myArray[f,b,q] ++ " " ++
if (<maximum q>) <newline> ++
if (<maximum q and maximum b>) <newline>
| f in Foo, b in Bar, q in Quz);
but that seems awkward (and my first attempt did not work).
I saw Minizinc nested for loop which is different, because all of the output is inside the inner-most loop. I want output in the outer loops as well.
I think a slightly clearer version of the accepted answer would be
output [
"Foo: \(f)\n"
++ concat(
concat([show(myArray[f,b,q]) ++ " " | q in Quz])
++ "\n"
| b in Bar])
++ "\n"
| f in Foo];
This avoids the if/then/else construct, and makes it clear that we are adding additional output before/after each inner loop.
As you already said: MiniZinc output statements can be a little awkward. The output statement consists of the keyword output
followed by an array of strings. In a lot of cases we would like to use for-loop, but in a declarative language like MiniZinc those kind of control-flow structure are not available.
You already offered the solution though: Array Comprehensions! It seems you were almost there, but your syntax was a little off and you might not be understanding how they actually work. An array comprehension is similar to a for-loop in that it does iterate over all values in a set. However, it is different in that it doesn't just execute the statements in the loop, but evaluates them and all results need to be of the same type, string in this case.
The output statement you are writing could be written like this:
output [
"Foo: \(f)\n"
++ concat(["\(myArray[f,b,q])"
++ if q == max(Quz
then "\n"
else " "
endif
|b in Bar, q in Quz])
++ "\n"
| f in Foo];