alpar@1
|
1 |
/* A solver for the Japanese number-puzzle Hashiwokakero
|
alpar@1
|
2 |
* (http://en.wikipedia.org/wiki/Hashiwokakero)
|
alpar@1
|
3 |
*
|
alpar@1
|
4 |
* Sebastian Nowozin <nowozin@gmail.com>, 13th January 2009
|
alpar@1
|
5 |
*/
|
alpar@1
|
6 |
|
alpar@1
|
7 |
param n := 25;
|
alpar@1
|
8 |
set rows := 1..n;
|
alpar@1
|
9 |
set cols := 1..n;
|
alpar@1
|
10 |
param givens{rows, cols}, integer, >= 0, <= 8, default 0;
|
alpar@1
|
11 |
|
alpar@1
|
12 |
/* Set of vertices as (row,col) coordinates */
|
alpar@1
|
13 |
set V := { (i,j) in { rows, cols }: givens[i,j] != 0 };
|
alpar@1
|
14 |
|
alpar@1
|
15 |
/* Set of feasible horizontal edges from (i,j) to (k,l) rightwards */
|
alpar@1
|
16 |
set Eh := { (i,j,k,l) in { V, V }:
|
alpar@1
|
17 |
i = k and j < l and # Same row and left to right
|
alpar@1
|
18 |
card({ (s,t) in V: s = i and t > j and t < l }) = 0 # No vertex inbetween
|
alpar@1
|
19 |
};
|
alpar@1
|
20 |
|
alpar@1
|
21 |
/* Set of feasible vertical edges from (i,j) to (k,l) downwards */
|
alpar@1
|
22 |
set Ev := { (i,j,k,l) in { V, V }:
|
alpar@1
|
23 |
j = l and i < k and # Same column and top to bottom
|
alpar@1
|
24 |
card({ (s,t) in V: t = j and s > i and s < k }) = 0 # No vertex inbetween
|
alpar@1
|
25 |
};
|
alpar@1
|
26 |
|
alpar@1
|
27 |
set E := Eh union Ev;
|
alpar@1
|
28 |
|
alpar@1
|
29 |
/* Indicators: use edge once/twice */
|
alpar@1
|
30 |
var xe1{E}, binary;
|
alpar@1
|
31 |
var xe2{E}, binary;
|
alpar@1
|
32 |
|
alpar@1
|
33 |
/* Constraint: Do not use edge or do use once or do use twice */
|
alpar@1
|
34 |
s.t. edge_sel{(i,j,k,l) in E}:
|
alpar@1
|
35 |
xe1[i,j,k,l] + xe2[i,j,k,l] <= 1;
|
alpar@1
|
36 |
|
alpar@1
|
37 |
/* Constraint: There must be as many edges used as the node value */
|
alpar@1
|
38 |
s.t. satisfy_vertex_demand{(s,t) in V}:
|
alpar@1
|
39 |
sum{(i,j,k,l) in E: (i = s and j = t) or (k = s and l = t)}
|
alpar@1
|
40 |
(xe1[i,j,k,l] + 2.0*xe2[i,j,k,l]) = givens[s,t];
|
alpar@1
|
41 |
|
alpar@1
|
42 |
/* Constraint: No crossings */
|
alpar@1
|
43 |
s.t. no_crossing1{(i,j,k,l) in Eh, (s,t,u,v) in Ev:
|
alpar@1
|
44 |
s < i and u > i and j < t and l > t}:
|
alpar@1
|
45 |
xe1[i,j,k,l] + xe1[s,t,u,v] <= 1;
|
alpar@1
|
46 |
s.t. no_crossing2{(i,j,k,l) in Eh, (s,t,u,v) in Ev:
|
alpar@1
|
47 |
s < i and u > i and j < t and l > t}:
|
alpar@1
|
48 |
xe1[i,j,k,l] + xe2[s,t,u,v] <= 1;
|
alpar@1
|
49 |
s.t. no_crossing3{(i,j,k,l) in Eh, (s,t,u,v) in Ev:
|
alpar@1
|
50 |
s < i and u > i and j < t and l > t}:
|
alpar@1
|
51 |
xe2[i,j,k,l] + xe1[s,t,u,v] <= 1;
|
alpar@1
|
52 |
s.t. no_crossing4{(i,j,k,l) in Eh, (s,t,u,v) in Ev:
|
alpar@1
|
53 |
s < i and u > i and j < t and l > t}:
|
alpar@1
|
54 |
xe2[i,j,k,l] + xe2[s,t,u,v] <= 1;
|
alpar@1
|
55 |
|
alpar@1
|
56 |
|
alpar@1
|
57 |
/* Model connectivity by auxiliary network flow problem:
|
alpar@1
|
58 |
* One vertex becomes a target node and all other vertices send a unit flow
|
alpar@1
|
59 |
* to it. The edge selection variables xe1/xe2 are VUB constraints and
|
alpar@1
|
60 |
* therefore xe1/xe2 select the feasible graph for the max-flow problems.
|
alpar@1
|
61 |
*/
|
alpar@1
|
62 |
set node_target := { (s,t) in V:
|
alpar@1
|
63 |
card({ (i,j) in V: i < s or (i = s and j < t) }) = 0};
|
alpar@1
|
64 |
set node_sources := { (s,t) in V: (s,t) not in node_target };
|
alpar@1
|
65 |
|
alpar@1
|
66 |
var flow_forward{ E }, >= 0;
|
alpar@1
|
67 |
var flow_backward{ E }, >= 0;
|
alpar@1
|
68 |
s.t. flow_conservation{ (s,t) in node_target, (p,q) in V }:
|
alpar@1
|
69 |
/* All incoming flows */
|
alpar@1
|
70 |
- sum{(i,j,k,l) in E: k = p and l = q} flow_forward[i,j,k,l]
|
alpar@1
|
71 |
- sum{(i,j,k,l) in E: i = p and j = q} flow_backward[i,j,k,l]
|
alpar@1
|
72 |
/* All outgoing flows */
|
alpar@1
|
73 |
+ sum{(i,j,k,l) in E: k = p and l = q} flow_backward[i,j,k,l]
|
alpar@1
|
74 |
+ sum{(i,j,k,l) in E: i = p and j = q} flow_forward[i,j,k,l]
|
alpar@1
|
75 |
= 0 + (if (p = s and q = t) then card(node_sources) else -1);
|
alpar@1
|
76 |
|
alpar@1
|
77 |
/* Variable-Upper-Bound (VUB) constraints: xe1/xe2 bound the flows.
|
alpar@1
|
78 |
*/
|
alpar@1
|
79 |
s.t. connectivity_vub1{(i,j,k,l) in E}:
|
alpar@1
|
80 |
flow_forward[i,j,k,l] <= card(node_sources)*(xe1[i,j,k,l] + xe2[i,j,k,l]);
|
alpar@1
|
81 |
s.t. connectivity_vub2{(i,j,k,l) in E}:
|
alpar@1
|
82 |
flow_backward[i,j,k,l] <= card(node_sources)*(xe1[i,j,k,l] + xe2[i,j,k,l]);
|
alpar@1
|
83 |
|
alpar@1
|
84 |
/* A feasible solution is enough
|
alpar@1
|
85 |
*/
|
alpar@1
|
86 |
minimize cost: 0;
|
alpar@1
|
87 |
|
alpar@1
|
88 |
solve;
|
alpar@1
|
89 |
|
alpar@1
|
90 |
/* Output solution graphically */
|
alpar@1
|
91 |
printf "\nSolution:\n";
|
alpar@1
|
92 |
for { row in rows } {
|
alpar@1
|
93 |
for { col in cols } {
|
alpar@1
|
94 |
/* First print this cell information: givens or space */
|
alpar@1
|
95 |
printf{0..0: givens[row,col] != 0} "%d", givens[row,col];
|
alpar@1
|
96 |
printf{0..0: givens[row,col] = 0 and
|
alpar@1
|
97 |
card({(i,j,k,l) in Eh: i = row and col >= j and col < l and
|
alpar@1
|
98 |
xe1[i,j,k,l] = 1}) = 1} "-";
|
alpar@1
|
99 |
printf{0..0: givens[row,col] = 0 and
|
alpar@1
|
100 |
card({(i,j,k,l) in Eh: i = row and col >= j and col < l and
|
alpar@1
|
101 |
xe2[i,j,k,l] = 1}) = 1} "=";
|
alpar@1
|
102 |
printf{0..0: givens[row,col] = 0
|
alpar@1
|
103 |
and card({(i,j,k,l) in Ev: j = col and row >= i and row < k and
|
alpar@1
|
104 |
xe1[i,j,k,l] = 1}) = 1} "|";
|
alpar@1
|
105 |
printf{0..0: givens[row,col] = 0
|
alpar@1
|
106 |
and card({(i,j,k,l) in Ev: j = col and row >= i and row < k and
|
alpar@1
|
107 |
xe2[i,j,k,l] = 1}) = 1} '"';
|
alpar@1
|
108 |
printf{0..0: givens[row,col] = 0
|
alpar@1
|
109 |
and card({(i,j,k,l) in Eh: i = row and col >= j and col < l and
|
alpar@1
|
110 |
(xe1[i,j,k,l] = 1 or xe2[i,j,k,l] = 1)}) = 0
|
alpar@1
|
111 |
and card({(i,j,k,l) in Ev: j = col and row >= i and row < k and
|
alpar@1
|
112 |
(xe1[i,j,k,l] = 1 or xe2[i,j,k,l] = 1)}) = 0} " ";
|
alpar@1
|
113 |
|
alpar@1
|
114 |
/* Now print any edges */
|
alpar@1
|
115 |
printf{(i,j,k,l) in Eh: i = row and col >= j and col < l and xe1[i,j,k,l] = 1} "-";
|
alpar@1
|
116 |
printf{(i,j,k,l) in Eh: i = row and col >= j and col < l and xe2[i,j,k,l] = 1} "=";
|
alpar@1
|
117 |
|
alpar@1
|
118 |
printf{(i,j,k,l) in Eh: i = row and col >= j and col < l and
|
alpar@1
|
119 |
xe1[i,j,k,l] = 0 and xe2[i,j,k,l] = 0} " ";
|
alpar@1
|
120 |
printf{0..0: card({(i,j,k,l) in Eh: i = row and col >= j and col < l}) = 0} " ";
|
alpar@1
|
121 |
}
|
alpar@1
|
122 |
printf "\n";
|
alpar@1
|
123 |
for { col in cols } {
|
alpar@1
|
124 |
printf{(i,j,k,l) in Ev: j = col and row >= i and row < k and xe1[i,j,k,l] = 1} "|";
|
alpar@1
|
125 |
printf{(i,j,k,l) in Ev: j = col and row >= i and row < k and xe2[i,j,k,l] = 1} '"';
|
alpar@1
|
126 |
printf{(i,j,k,l) in Ev: j = col and row >= i and row < k and
|
alpar@1
|
127 |
xe1[i,j,k,l] = 0 and xe2[i,j,k,l] = 0} " ";
|
alpar@1
|
128 |
/* No vertical edges: skip also a field */
|
alpar@1
|
129 |
printf{0..0: card({(i,j,k,l) in Ev: j = col and row >= i and row < k}) = 0} " ";
|
alpar@1
|
130 |
printf " ";
|
alpar@1
|
131 |
}
|
alpar@1
|
132 |
printf "\n";
|
alpar@1
|
133 |
}
|
alpar@1
|
134 |
|
alpar@1
|
135 |
data;
|
alpar@1
|
136 |
|
alpar@1
|
137 |
/* This is a difficult 25x25 Hashiwokakero.
|
alpar@1
|
138 |
*/
|
alpar@1
|
139 |
param givens : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
alpar@1
|
140 |
25 :=
|
alpar@1
|
141 |
1 2 . 2 . 2 . . 2 . 2 . . 2 . . . . 2 . 2 . 2 . 2 .
|
alpar@1
|
142 |
2 . 1 . . . . 2 . . . 4 . . 5 . 2 . . 1 . 2 . 2 . 1
|
alpar@1
|
143 |
3 2 . . 5 . 4 . . 3 . . . . . 1 . . 4 . 5 . 1 . 1 .
|
alpar@1
|
144 |
4 . . . . . . . . . . . 1 . 3 . . 1 . . . . . . . .
|
alpar@1
|
145 |
5 2 . . 6 . 6 . . 8 . 5 . 2 . . 3 . 5 . 7 . . 2 . .
|
alpar@1
|
146 |
6 . 1 . . . . . . . . . 1 . . 2 . . . . . 1 . . . 3
|
alpar@1
|
147 |
7 2 . . . . 5 . . 6 . 4 . . 2 . . . 2 . 5 . 4 . 2 .
|
alpar@1
|
148 |
8 . 2 . 2 . . . . . . . . . . . 3 . . 3 . . . 1 . 2
|
alpar@1
|
149 |
9 . . . . . . . . . . 4 . 2 . 2 . . 1 . . . 3 . 1 .
|
alpar@1
|
150 |
10 2 . 3 . . 6 . . 2 . . . . . . . . . . 3 . . . . .
|
alpar@1
|
151 |
11 . . . . 1 . . 2 . . 5 . . 1 . 4 . 3 . . . . 2 . 4
|
alpar@1
|
152 |
12 . . 2 . . 1 . . . . . . 5 . 4 . . . . 4 . 3 . . .
|
alpar@1
|
153 |
13 2 . . . 3 . 1 . . . . . . . . 3 . . 5 . 5 . . 2 .
|
alpar@1
|
154 |
14 . . . . . 2 . 5 . . 7 . 5 . 3 . 1 . . 1 . . 1 . 4
|
alpar@1
|
155 |
15 2 . 5 . 3 . . . . 1 . 2 . 1 . . . . 2 . 4 . . 2 .
|
alpar@1
|
156 |
16 . . . . . 1 . . . . . . . . . . 2 . . 2 . 1 . . 3
|
alpar@1
|
157 |
17 2 . 6 . 6 . . 2 . . 2 . 2 . 5 . . . . . 2 . . . .
|
alpar@1
|
158 |
18 . . . . . 1 . . . 3 . . . . . 1 . . 1 . . 4 . 3 .
|
alpar@1
|
159 |
19 . . 4 . 5 . . 2 . . . 2 . . 6 . 6 . . 3 . . . . 3
|
alpar@1
|
160 |
20 2 . . . . . . . . . 2 . . 1 . . . . . . 1 . . 1 .
|
alpar@1
|
161 |
21 . . 3 . . 3 . 5 . 5 . . 4 . 6 . 7 . . 4 . 6 . . 4
|
alpar@1
|
162 |
22 2 . . . 3 . 5 . 2 . 1 . . . . . . . . . . . . . .
|
alpar@1
|
163 |
23 . . . . . . . . . 1 . . . . . . 3 . 2 . . 5 . . 5
|
alpar@1
|
164 |
24 2 . 3 . 3 . 5 . 4 . 3 . 3 . 4 . . 2 . 2 . . . 1 .
|
alpar@1
|
165 |
25 . 1 . 2 . 2 . . . 2 . 2 . . . 2 . . . . 2 . 2 . 2
|
alpar@1
|
166 |
;
|
alpar@1
|
167 |
|
alpar@1
|
168 |
end;
|