From c08551dc42ef5a4503ed133c69bae716888d19fb Mon Sep 17 00:00:00 2001 From: David Tonhofer Date: Sat, 2 Oct 2021 17:16:14 +0200 Subject: [PATCH 1/6] Nicer comments --- CP/optimization/100potions.dzn | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/CP/optimization/100potions.dzn b/CP/optimization/100potions.dzn index 1c081e0..45ed7d0 100644 --- a/CP/optimization/100potions.dzn +++ b/CP/optimization/100potions.dzn @@ -1,8 +1,10 @@ -n = 100; %Water Number -w = 8; %Window Size -p = 140; %Leaves required in each Window -capacity= 380; %Total Energy we have for using holy Water -m= 4; %Mode numbers +% Input for "The Strongest YaoCao", 100 potions + +n = 100; % Number of potions +w = 8; % Window size +p = 140; % Min number of leaves-on-branches required in a window (actual value must be >= p) +capacity = 380; % Max capacity of nutrients available for any path from root node to outermost node +m = 4; % Max number of segments grown at each node (max branching factor) nutrient = [|6,5,381,381 @@ -208,4 +210,4 @@ leave = |93,35,0,0 |6,3,51,0 |19,0,0,0 -|]; \ No newline at end of file +|]; From fbdba2a3419607f78cdc6ee4863f823f4b82b51e Mon Sep 17 00:00:00 2001 From: David Tonhofer Date: Sat, 2 Oct 2021 17:18:27 +0200 Subject: [PATCH 2/6] Added comments --- CP/optimization/4potions.dzn | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/CP/optimization/4potions.dzn b/CP/optimization/4potions.dzn index 3aefa40..44a19dc 100644 --- a/CP/optimization/4potions.dzn +++ b/CP/optimization/4potions.dzn @@ -1,8 +1,10 @@ -n = 4; -m = 4; -w = 2; -p = 8; -capacity= 19; +% Input for "The Strongest YaoCao", 4 potions + +n = 4; % Number of potions +w = 2; % Window size +p = 8; % Min number of leaves-on-branches required in a window (actual value must be >= p) +capacity = 19; % Max capacity of nutrients available for any path from root node to outermost node +m = 4; % Max number of segments grown at each node (max branching factor) nutrient = [|4,2,3,7 @@ -16,4 +18,4 @@ leave = |5,8,0,0 |5,4,7,0 |6,9,3,0 -|]; \ No newline at end of file +|]; From d30f78011f84e3c5d5dea276a678b5ff96c54144 Mon Sep 17 00:00:00 2001 From: David Tonhofer Date: Sat, 2 Oct 2021 17:24:54 +0200 Subject: [PATCH 3/6] Added lots of comments --- CP/optimization/yaocao.mzn | 123 ++++++++++++++++++++++++++++++++----- 1 file changed, 108 insertions(+), 15 deletions(-) diff --git a/CP/optimization/yaocao.mzn b/CP/optimization/yaocao.mzn index 9f2adf6..b25a0ef 100644 --- a/CP/optimization/yaocao.mzn +++ b/CP/optimization/yaocao.mzn @@ -1,31 +1,90 @@ -int: n; % number of potions -set of int: POTIONS = 1..n; -int: w; % window size -int: p; % num of leaves in each window -int: capacity; % capacity of nutrients -int: m; % max number of grown segments +% === +% "The Strongest YaoCao" +% === + +% Grow (or explore) a tree. +% +% The root node has level 1. +% We need to reach level n (the number of potions) at which +% YaoCao grows (the best YaoCao is the one with the most +% leaves-on-branches over the path) +% The potions are used "in order" so "tree level" and "potion +% number" are equivalent (the potion x is applied to each node at +% level x equally) +% The choice is the selection of the branch (segment) to +% follow from each node. +% At each node, the potion determines the branching factor +% as well as the number of leaves and the nutrient requirements +% on each branch/segment. +% Along a path through the tree, the total nutrient +% requirements of each branch over the path must stay below a +% maximum. +% Along a path through the tree, the total number of leaves of +% the branches belonging to any "window" of a given length +% (a continuous series of segments of the path) must stay above +% a minimum. + +% --- +% Given +% --- + +int: n; % Number of potions +int: w; % Window size +int: p; % Min number of leaves-on-branches required in a window (actual value must be >= p) +int: capacity; % Max capacity of nutrients available for any path from root node to outermost node +int: m; % Max number of segments grown at each node (max branching factor) + +set of int: POTIONS = 1..n; set of int: SEGMENTS = 1..m; -array[POTIONS,SEGMENTS] of int: nutrient; % nutrient required -array[POTIONS,SEGMENTS] of int: leave; % num of leaves to grow +% Nutrients required by segment/branch x if the node +% was expanded with potion y (capacity+1 if segment does not exist) + +array[POTIONS,SEGMENTS] of int: nutrient; + +% (Typo: Should be "leaf") Number of leaves that will to grow on +% segment/branch x if the node was expanded with potion y (0 if +% segment does not exist) + +array[POTIONS,SEGMENTS] of int: leave; + +% --- +% Sought +% --- + +% The "path": which segment/branch to select at every level "x" +% (equivalent to potion "x") of the tree + +array[POTIONS] of var SEGMENTS: choice; + +% The list of nutrients needed over the path implied by "choice" -array[POTIONS] of var SEGMENTS: choice; %Choice of segment for each potion -array[POTIONS] of var int: nutrient_list = +array[POTIONS] of var int: nutrient_list = [nutrient[i,choice[i]] | i in POTIONS]; -array[POTIONS] of var int: leave_list = + +% The list of leaves-on-branches over the path implied by "choice" + +array[POTIONS] of var int: leave_list = [leave[i,choice[i]] | i in POTIONS]; var int: total_nutrient = sum(nutrient_list); var int: total_leaves = sum(leave_list); -constraint assert(n>=w,"Window Size larger than # of steps"); +constraint assert(w<=n,"Window size must be <= than number of potions"); + +% Nutrients required by the full path may not exceed capacity -%Capacity constraint total_nutrient <= capacity; -%In each window, leave numbers should be larger than p + +% Number of leaves-on-branches in any window on the path must be >= p + constraint forall(tail in w..n) (sum(i in tail-w+1..tail)(leave_list[i]) >= p); +% --- +% Solving +% --- + solve :: ssearch2 maximize total_leaves; ann: search1 = int_search(leave_list, input_order, indomain_min, complete); @@ -41,4 +100,38 @@ ann: ssearch2 = seq_search([ int_search([total_leaves], input_order, indomain_max, complete), search1 ]); -output ["choice = ",show(choice),";\n","total_leaves = ",show(total_leaves),";\n","total_nutrient = ", show(total_nutrient)]; \ No newline at end of file +% --- +% Info output +% --- + +function string: braced(SEGMENTS: s, SEGMENTS: chosen, int: val) = + if s == chosen then + if val<10 then " [" ++ show(val) ++ "]" + elseif val<100 then " [" ++ show(val) ++ "]" + else "[" ++ show(val) ++ "]" + endif + else + if val<10 then " " ++ show(val) ++ " " + elseif val<100 then " " ++ show(val) ++ " " + else " " ++ show(val) ++ " " + endif + endif; + +output ["% Number of potions: \(n)\n" ]; +output ["% Min leaves-on-branches required in a window of size \(w): \(p)\n" ]; +output ["% Max capacity of nutrients available for any path: \(capacity)\n" ]; +output ["% Nutrients needed by each of the up to \(m) segments:\n"]; +output ["% Potion " ++ show_int(3,i) ++ ": " ++ + join(",", [ braced(s,fix(choice[i]),nutrient[i,s]) | s in SEGMENTS where nutrient[i,s]<=capacity ]) ++ "\n" + | i in POTIONS ]; +output ["% Leaves grown on each of the up to \(m) segments:\n"]; +output ["% Potion " ++ show_int(3,i) ++ ": " ++ + join(",", [ braced(s,fix(choice[i]),leave[i,s]) | s in SEGMENTS where leave[i,s]>0]) ++ "\n" + | i in POTIONS ]; +output ["\n"]; + +% --- +% Solution output +% --- + +output ["choice = \(choice);\ntotal_leaves = \(total_leaves);\ntotal_nutrient = \(total_nutrient);\n"]; From fda4f57a14b53d2ee71f06b14aeb09ae5958c986 Mon Sep 17 00:00:00 2001 From: David Tonhofer Date: Sat, 2 Oct 2021 19:52:44 +0200 Subject: [PATCH 4/6] Added comments --- CP/optimization/4potions.dzn | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CP/optimization/4potions.dzn b/CP/optimization/4potions.dzn index 44a19dc..0e67faf 100644 --- a/CP/optimization/4potions.dzn +++ b/CP/optimization/4potions.dzn @@ -1,10 +1,10 @@ % Input for "The Strongest YaoCao", 4 potions -n = 4; % Number of potions -w = 2; % Window size -p = 8; % Min number of leaves-on-branches required in a window (actual value must be >= p) -capacity = 19; % Max capacity of nutrients available for any path from root node to outermost node -m = 4; % Max number of segments grown at each node (max branching factor) +n = 4; % Number of potions +w = 2; % Window size +p = 8; % Min number of "leaves on all segments in a window" (actual value must be >= p) +capacity = 19; % Max capacity of nutrients available for any branch (i.e. path) from root node to outermost node +m = 4; % Max number of segments grown at each node (i.e. max branching factor) nutrient = [|4,2,3,7 From 6bef2da14beed996a560ebf1954625d944f22b63 Mon Sep 17 00:00:00 2001 From: David Tonhofer Date: Sat, 2 Oct 2021 19:53:53 +0200 Subject: [PATCH 5/6] Update 100potions.dzn --- CP/optimization/100potions.dzn | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CP/optimization/100potions.dzn b/CP/optimization/100potions.dzn index 45ed7d0..1906e0a 100644 --- a/CP/optimization/100potions.dzn +++ b/CP/optimization/100potions.dzn @@ -2,9 +2,9 @@ n = 100; % Number of potions w = 8; % Window size -p = 140; % Min number of leaves-on-branches required in a window (actual value must be >= p) -capacity = 380; % Max capacity of nutrients available for any path from root node to outermost node -m = 4; % Max number of segments grown at each node (max branching factor) +p = 140; % Min number of "leaves on all segments in a window" (actual value must be >= p) +capacity = 380; % Max capacity of nutrients available for any branch (i.e. path) from root node to outermost node +m = 4; % Max number of segments grown at each node (i.e. max branching factor) nutrient = [|6,5,381,381 From 0250bb8303b9ffe6703a981a1c985f1966c4e390 Mon Sep 17 00:00:00 2001 From: David Tonhofer Date: Sat, 2 Oct 2021 19:54:36 +0200 Subject: [PATCH 6/6] Update yaocao.mzn --- CP/optimization/yaocao.mzn | 102 +++++++++++++++++++++---------------- 1 file changed, 57 insertions(+), 45 deletions(-) diff --git a/CP/optimization/yaocao.mzn b/CP/optimization/yaocao.mzn index b25a0ef..e3ccb40 100644 --- a/CP/optimization/yaocao.mzn +++ b/CP/optimization/yaocao.mzn @@ -6,22 +6,21 @@ % % The root node has level 1. % We need to reach level n (the number of potions) at which -% YaoCao grows (the best YaoCao is the one with the most -% leaves-on-branches over the path) -% The potions are used "in order" so "tree level" and "potion -% number" are equivalent (the potion x is applied to each node at -% level x equally) -% The choice is the selection of the branch (segment) to -% follow from each node. -% At each node, the potion determines the branching factor -% as well as the number of leaves and the nutrient requirements -% on each branch/segment. -% Along a path through the tree, the total nutrient -% requirements of each branch over the path must stay below a -% maximum. -% Along a path through the tree, the total number of leaves of -% the branches belonging to any "window" of a given length -% (a continuous series of segments of the path) must stay above +% YaoCao grows. The best YaoCao is the one with the most +% leaves-on-segments over the branch (the "branch" is the path +% through the tree, consisting of "segments") +% The potions are used "in order" so "tree height" (or "tree level") +% and "potion number" are equivalent (the potion x is applied to +% each node at level x equally) +% The choice is the selection of the segment to follow from each node. +% At each node, the potion determines the "branching factor" +% (the number of outgoing segments) as well as the number of leaves +% on each segment and the nutrient requirements on each segment. +% Along a branch (path through the tree), the total nutrient +% requirements of each segment must stay below a maximum. +% Along a branch, the total number of leaves of on the segments +% belonging to any "window" (a continuous series of segments of +% the branch, with the number of segments fixed) must stay above % a minimum. % --- @@ -30,53 +29,54 @@ int: n; % Number of potions int: w; % Window size -int: p; % Min number of leaves-on-branches required in a window (actual value must be >= p) -int: capacity; % Max capacity of nutrients available for any path from root node to outermost node +int: p; % Min number of leaves-on-segments required in a window (actual value must be >= p) +int: capacity; % Max capacity of nutrients available for any branch/path from root node to outermost node int: m; % Max number of segments grown at each node (max branching factor) set of int: POTIONS = 1..n; set of int: SEGMENTS = 1..m; -% Nutrients required by segment/branch x if the node -% was expanded with potion y (capacity+1 if segment does not exist) +% Nutrients required by segment x if the node +% was expanded with potion y +% (capacity+1 if segment does not exist) array[POTIONS,SEGMENTS] of int: nutrient; -% (Typo: Should be "leaf") Number of leaves that will to grow on -% segment/branch x if the node was expanded with potion y (0 if -% segment does not exist) +% Number of leaves that will to grow on +% segment x if the node was expanded with potion y +% (0 if segment does not exist) -array[POTIONS,SEGMENTS] of int: leave; +array[POTIONS,SEGMENTS] of int: leaf; % --- % Sought % --- -% The "path": which segment/branch to select at every level "x" -% (equivalent to potion "x") of the tree +% The branch (i.e. the path through the tree): which segment to select at +% every height "x" (equivalent to potion "x") of the tree array[POTIONS] of var SEGMENTS: choice; -% The list of nutrients needed over the path implied by "choice" +% The list of nutrients needed over the branch/path implied by "choice" array[POTIONS] of var int: nutrient_list = [nutrient[i,choice[i]] | i in POTIONS]; -% The list of leaves-on-branches over the path implied by "choice" +% The list of leaves-on-segments over the branch/path implied by "choice" array[POTIONS] of var int: leave_list = - [leave[i,choice[i]] | i in POTIONS]; + [leaf[i,choice[i]] | i in POTIONS]; var int: total_nutrient = sum(nutrient_list); var int: total_leaves = sum(leave_list); constraint assert(w<=n,"Window size must be <= than number of potions"); -% Nutrients required by the full path may not exceed capacity +% Nutrients required by the full branch/path may not exceed capacity constraint total_nutrient <= capacity; -% Number of leaves-on-branches in any window on the path must be >= p +% Number of leaves-on-segments in any window on the branch/path must be >= p constraint forall(tail in w..n) (sum(i in tail-w+1..tail)(leave_list[i]) >= p); @@ -87,18 +87,30 @@ constraint forall(tail in w..n) solve :: ssearch2 maximize total_leaves; -ann: search1 = int_search(leave_list, input_order, indomain_min, complete); -ann: search2 = int_search(leave_list, input_order, indomain_max, complete); -ann: search3 = int_search(leave_list, largest, indomain_min, complete); -ann: search4 = int_search(leave_list, largest, indomain_max, complete); -ann: search5 = int_search(leave_list, smallest, indomain_min, complete); -ann: search6 = int_search(leave_list, smallest, indomain_max, complete); +% search4: finds optimum (6443 for "100 potions") in least time (seconds) +% search6: finds optimum, a bit slower than largest+max (seconds) +% search5: finds optimum, rather slower than smallest+max (a few minutes) +% searchTL: fix a high leaf value, then see whether it can be realized, +% finds optimum in a few minutes +% search2: finds optimum, rather slower than smallest+min (multiple minutes) +% search1: does not find optimum within 15 mins +% search3: finds worst value within 15 mins +% +% ssearch1: redundant sequential search equivalent to search 1 alone +% ssearch2: optimistic search: set the total leaves to a high value, then +% search for a branch/path that matches (finds optimum in about a minute) + +ann: search1 = int_search(leave_list, input_order, indomain_min); +ann: search2 = int_search(leave_list, input_order, indomain_max); +ann: search3 = int_search(leave_list, largest, indomain_min); +ann: search4 = int_search(leave_list, largest, indomain_max); +ann: search5 = int_search(leave_list, smallest, indomain_min); +ann: search6 = int_search(leave_list, smallest, indomain_max); + +ann: searchTL = int_search([total_leaves], input_order, indomain_max); -ann: ssearch1 = seq_search([search1, - int_search([total_leaves], input_order, indomain_max, complete) ]); -ann: ssearch2 = seq_search([ - int_search([total_leaves], input_order, indomain_max, complete), - search1 ]); +ann: ssearch1 = seq_search([search1,searchTL]); +ann: ssearch2 = seq_search([searchTL,search1]); % --- % Info output @@ -118,15 +130,15 @@ function string: braced(SEGMENTS: s, SEGMENTS: chosen, int: val) = endif; output ["% Number of potions: \(n)\n" ]; -output ["% Min leaves-on-branches required in a window of size \(w): \(p)\n" ]; -output ["% Max capacity of nutrients available for any path: \(capacity)\n" ]; +output ["% Min leaves-on-segments required in a window of size \(w): \(p)\n" ]; +output ["% Max capacity of nutrients available for any branch: \(capacity)\n" ]; output ["% Nutrients needed by each of the up to \(m) segments:\n"]; output ["% Potion " ++ show_int(3,i) ++ ": " ++ join(",", [ braced(s,fix(choice[i]),nutrient[i,s]) | s in SEGMENTS where nutrient[i,s]<=capacity ]) ++ "\n" | i in POTIONS ]; output ["% Leaves grown on each of the up to \(m) segments:\n"]; output ["% Potion " ++ show_int(3,i) ++ ": " ++ - join(",", [ braced(s,fix(choice[i]),leave[i,s]) | s in SEGMENTS where leave[i,s]>0]) ++ "\n" + join(",", [ braced(s,fix(choice[i]),leaf[i,s]) | s in SEGMENTS where leaf[i,s]>0]) ++ "\n" | i in POTIONS ]; output ["\n"];