git-subtree-dir: software/minizinc git-subtree-split: 4f10c82056ffcb1041d7ffef29d77a7eef92cf76
161 lines
3.9 KiB
MiniZinc
161 lines
3.9 KiB
MiniZinc
/***
|
|
!Test
|
|
solvers: [gecode, chuffed]
|
|
expected:
|
|
- !Result
|
|
solution: !Solution
|
|
node_used: [3, 4, 6, 9, 11, 13, 15, 8, 9, 10, 11, 12, 13, 14, 15]
|
|
x: [6, 2, 6, 2, 4, 6, 8, 1, 2, 3, 4, 5, 6, 7, 8]
|
|
***/
|
|
|
|
% Regression test for a problem in mzn2fzn 1.2 where log/2
|
|
% was not recognised as a built-in operation by the flattening
|
|
% engine.
|
|
|
|
% THe model is from: http://www.hakank.org/minizinc/decision_tree_binary.mzn
|
|
|
|
% Decision tree in MiniZinc.
|
|
%
|
|
% Simple zero sum binary decision trees.
|
|
%
|
|
%
|
|
% Model created by Hakan Kjellerstrand, hakank@bonetmail.com
|
|
|
|
% The model only handles complete binary trees of sizes
|
|
% n = (a**2) - 1, for some a. The values are at the lowest level.
|
|
%
|
|
% Example with n = 7
|
|
%
|
|
% x1 A maximizes
|
|
% /\
|
|
% x2 x3 B minimizes
|
|
% / \ /\
|
|
% x4 x5 x6 x7 (A)
|
|
%
|
|
% The value nodes (the last level):
|
|
% x4 = 6
|
|
% x5 = 1
|
|
% x6 = 5
|
|
% x7 = 3
|
|
%
|
|
% First B minimizes the last level (x4..x7):
|
|
% x2 = argmin(x5, x4) -> x2 = x5
|
|
% x3 = argmin(x6, x7) -> x3 = x7
|
|
%
|
|
% A then maximizes from B's choices as the last step:
|
|
% x1 = argmax( x3, x2) -> x1 = x3
|
|
%
|
|
%
|
|
% The solution is a decision tree represented here as as:
|
|
%
|
|
%
|
|
% x (the values):
|
|
% 3
|
|
% 1 3
|
|
% 6 1 5 3
|
|
%
|
|
% node_used:
|
|
% 3
|
|
% 5 7
|
|
% 4 5 6 7
|
|
|
|
|
|
%
|
|
% minizinc and fz can handle n as large as 4095 (2**12-1)
|
|
% without breaking much sweat.
|
|
% For n = 8191 (2**13-1), it core dumps however.
|
|
%
|
|
|
|
|
|
int: n; % must be a (a**2) - 1, for some a, e.g. 7, 15, 31, 63 etc
|
|
int: levels = n div 2; % the number of levels
|
|
|
|
array[1..n] of var int: x; % the decision variables, the value tree
|
|
array[1..n] of var 1..n: node_used; % the nodes indices
|
|
|
|
|
|
%
|
|
% tree_levels contains the levels in the tree, e.g.
|
|
% [1, 2,2, 3,3,3,3, 4,4,4,4,4,4,4,4, ....]
|
|
% for odd levels: A is trying to maximize his/her gain,
|
|
% for even levels B is trying to minimize A's gains
|
|
%
|
|
array[1..n] of 0..n: tree_levels = [1+floor(log(2.0,int2float(i))) | i in 1..n ];
|
|
|
|
% solve :: int_search(x, "first_fail", "indomain", "complete") satisfy;
|
|
solve satisfy;
|
|
|
|
%
|
|
% argmax: maximize A's values
|
|
%
|
|
predicate argmax(array[int] of var int: x, int: i1, int: i2, array[int] of var int: node_used, int: node_used_ix) =
|
|
(x[i1] >= x[i2] -> node_used[node_used_ix] = i1)
|
|
/\
|
|
(x[i1] < x[i2] -> node_used[node_used_ix] = i2)
|
|
;
|
|
|
|
% argmin: minimize A's values
|
|
predicate argmin(array[int] of var int: x, int: i1, int: i2, array[int] of var int: node_used, int: node_used_ix) =
|
|
(-x[i1] >= -x[i2] -> node_used[node_used_ix] = i1)
|
|
/\
|
|
(-x[i1] < -x[i2] -> node_used[node_used_ix] = i2)
|
|
;
|
|
|
|
predicate cp1d(array[int] of var int: x, array[int] of var int: y) =
|
|
assert(index_set(x) = index_set(y),
|
|
"cp1d: x and y have different sizes",
|
|
forall(i in index_set(x)) ( x[i] = y[i] ) )
|
|
;
|
|
|
|
|
|
constraint
|
|
|
|
% the first 1..n div 2 in x is to be decided by the model,
|
|
% the rest is the node values.
|
|
|
|
cp1d(x, [_, _,_, _,_, _,_, 1,2, 3,4, 5,6, 7,8]) % n = 15
|
|
|
|
/\ % the last n div 2 positions (the node "row") in node_used is static
|
|
forall(i in levels+1..n) (
|
|
node_used[i] = i
|
|
% more general: makes the node value 1.. .
|
|
% Comment it if another tree should be used.
|
|
% /\ x[i] = -(n - i - levels) + 1
|
|
)
|
|
/\
|
|
% the first n div 2 positions and values are dynamic,
|
|
% the rest are static.
|
|
forall(i in 1..levels) (
|
|
x[i] = x[node_used[i]]
|
|
)
|
|
/\ % Should we maximize or minimize?
|
|
% It depends on the level.
|
|
forall(i in 1..levels) (
|
|
if tree_levels[i] mod 2 = 1 then
|
|
argmax(x, 2*i, 2*i+1, node_used, i)
|
|
else
|
|
argmin(x, 2*i, 2*i+1, node_used, i)
|
|
endif
|
|
)
|
|
|
|
;
|
|
|
|
% A "nice tree" (OK, it's not so nice. :-)
|
|
output
|
|
["x (the values):\n" , show(x[1])]
|
|
++
|
|
[
|
|
if tree_levels[i] > tree_levels[i-1] then "\n" else " " endif ++
|
|
show(x[i])
|
|
| i in 2..n
|
|
] ++
|
|
["\n\nnode_used:\n", show(node_used[1])]
|
|
++
|
|
[
|
|
if tree_levels[i] > tree_levels[i-1] then "\n" else " " endif ++
|
|
show(node_used[i])
|
|
| i in 2..n
|
|
] ++ ["\n"];
|
|
|
|
n = 15;
|