z3 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9155c71b227576436cf55fe332fb04748bf8a2ed
4
+ data.tar.gz: bf1c5200d857ed21311d2f5cb468e8cceac2f627
5
+ SHA512:
6
+ metadata.gz: 67c4b499c50f0c288900667f13bcdcca543629d55332a6247011c8e135b1d9b41a4865f9900e2884155aa28844492c3fcb1d5aacad775e1b556e3d1a6a265d3a
7
+ data.tar.gz: 88e74e1966920896bc2ca0ec8a2712c8180aeb79a97be8551aceb69b21016df907a579091fded5b688f8ebc8bdd3ad4ede8037f6a4458b7fa1831081b5f2bcee
data/README.md ADDED
@@ -0,0 +1,27 @@
1
+ This is Ruby interface for Z3 [ https://github.com/Z3Prover/z3 ].
2
+
3
+ It's in extremely early stages of development. Pull requests always welcome.
4
+
5
+ ### Interface
6
+
7
+ `Z3::VeryLowLever` / `Z3::LowLevel` are low level FFI interface, and they shouldn't be used directly.
8
+
9
+ The rest of `Z3` is high level API, but the interface is extremely unstable at this point, and it's pretty much guaranteed to change many times. Check specs or `examples/` directory for usage.
10
+
11
+ You can use most Ruby operators to construct ASTs, but use `~ | &` instead of `! || &&` for boolean operators.
12
+
13
+ As for API internals, attributes starting with `_` are FFI internals you shouldn't touch, other attributes are generally legitimate Ruby objects.
14
+
15
+ ### Requirements
16
+
17
+ To use it, you'll need to install `z3`. On OSX that would be:
18
+
19
+ brew install z3
20
+
21
+ On other systems use appropriate package manager.
22
+
23
+ ### Known Bugs
24
+
25
+ Ruby API tries to catch the most common mistakes, but if you use API in a weird way you can get C crash instead of nice Ruby exception.
26
+
27
+ Memory will leak a good deal. Generally avoid in long running processes.
@@ -0,0 +1,148 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative "../lib/z3"
4
+
5
+ class AlgebraProblem
6
+ attr_reader :solver
7
+ def initialize
8
+ @solver = Z3::Solver.new
9
+ end
10
+
11
+ def print_solution!(number)
12
+ puts("Solution to problem %s:" % number)
13
+ if @solver.check() == :sat
14
+ @solver.model.each do |n,v|
15
+ puts "* #{n} = #{v}"
16
+ end
17
+ else
18
+ puts "* Can't solve the problem"
19
+ end
20
+ end
21
+ end
22
+
23
+ class AlgebraProblem01 < AlgebraProblem
24
+ def solve!
25
+ x = Z3::Ast.real("x")
26
+ solver.assert 5*(-3*x - 2) - (x - 3) == -4*(4*x + 5) + 13
27
+ print_solution! "01"
28
+ # No nice way to say x is unconstrained
29
+ end
30
+ end
31
+
32
+ class AlgebraProblem03 < AlgebraProblem
33
+ def declare_abs(var, expr)
34
+ solver.assert Z3::Ast.or(
35
+ Z3::Ast.and(var == expr, expr >= 0),
36
+ Z3::Ast.and(var == -expr, expr <= 0)
37
+ )
38
+ end
39
+
40
+ def solve!
41
+ x = Z3::Ast.real("x")
42
+ xm2abs = Z3::Ast.real("|x-2|")
43
+ declare_abs(xm2abs, x-2)
44
+ m6abs = Z3::Ast.real("|-6|")
45
+ declare_abs(m6abs, -6)
46
+ solver.assert x < 2
47
+ solver.assert xm2abs == 4*m6abs
48
+ print_solution! "03"
49
+ end
50
+ end
51
+
52
+ class AlgebraProblem04 < AlgebraProblem
53
+ def declare_distance(a_b, ax, ay, bx, by)
54
+ solver.assert a_b >= 0
55
+ solver.assert a_b**2 == (ax-bx)**2 + (ay-by)**2
56
+ end
57
+
58
+ def solve!
59
+ ax = Z3::Ast.real("ax")
60
+ ay = Z3::Ast.real("ay")
61
+ bx = Z3::Ast.real("bx")
62
+ by = Z3::Ast.real("by")
63
+ a_b = Z3::Ast.real("|a-b|")
64
+ declare_distance(a_b, ax, ay, bx, by)
65
+ solver.assert ax == -4
66
+ solver.assert ay == -5
67
+ solver.assert bx == -1
68
+ solver.assert by == -1
69
+ print_solution! "04"
70
+ end
71
+ end
72
+
73
+ class AlgebraProblem05 < AlgebraProblem
74
+ def solve!
75
+ x = Z3::Ast.real("x")
76
+ y = Z3::Ast.real("y")
77
+ solver.assert 2*x - 4*y == 9
78
+ solver.assert y == 0
79
+ print_solution! "05"
80
+ end
81
+ end
82
+
83
+ class AlgebraProblem06 < AlgebraProblem
84
+ def declare_f(x,y)
85
+ solver.assert y == 6*x + 1
86
+ end
87
+
88
+ def solve!
89
+ x1 = Z3::Ast.real("x1")
90
+ y1 = Z3::Ast.real("y1")
91
+ x2 = Z3::Ast.real("x2")
92
+ y2 = Z3::Ast.real("y2")
93
+ answer = Z3::Ast.real("answer")
94
+ solver.assert x2 == 2
95
+ solver.assert x1 == 1
96
+ declare_f(x1, y1)
97
+ declare_f(x2, y2)
98
+ solver.assert answer == y2 - y1
99
+ print_solution! "06"
100
+ end
101
+ end
102
+
103
+ class AlgebraProblem10 < AlgebraProblem
104
+ def declare_abs(var, expr)
105
+ solver.assert Z3::Ast.or(
106
+ Z3::Ast.and(var == expr, expr >= 0),
107
+ Z3::Ast.and(var == -expr, expr <= 0)
108
+ )
109
+ end
110
+
111
+ def solve!
112
+ x = Z3::Ast.real("x")
113
+ y = Z3::Ast.real("|-2x + 2|")
114
+ declare_abs(y, -2*x + 2)
115
+ solver.assert y - 3 == -3
116
+ print_solution! "10"
117
+ end
118
+ end
119
+
120
+ AlgebraProblem01.new.solve!
121
+ AlgebraProblem03.new.solve!
122
+ AlgebraProblem04.new.solve!
123
+ AlgebraProblem05.new.solve!
124
+ AlgebraProblem06.new.solve!
125
+ AlgebraProblem10.new.solve!
126
+
127
+ """
128
+ http://www.analyzemath.com/Algebra1/Algebra1.html
129
+
130
+
131
+ Problem 1: Solve the equation
132
+ 5(-3x - 2) - (x - 3) = -4(4x + 5) + 13
133
+
134
+ Problem 3: If x <2, simplify
135
+ |x - 2| = 4|-6|
136
+ (actually I misread original, whatever)
137
+
138
+ Problem 4: Find the distance between the points (-4 , -5) and (-1 , -1).
139
+
140
+ Problem 5: Find the x intercept of the graph of the equation
141
+ 2x - 4y = 9
142
+
143
+ Problem 6: Evaluate f(2) - f(1)
144
+ f(x) = 6x + 1
145
+
146
+ Problem 10: Solve the equation
147
+ |-2x + 2| -3 = -3
148
+ """
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative "../lib/z3"
4
+
5
+ def check_multiplication_laws_1
6
+ a = Z3::Ast.int("a")
7
+ b = Z3::Ast.int("b")
8
+ solver = Z3::Solver.new
9
+ puts "Checking if (a+b)(a-b)==a*a-b*b"
10
+ solver.prove!(
11
+ (a+b)*(a-b) == (a*a - b*b)
12
+ )
13
+ end
14
+
15
+ def check_inequalities
16
+ a = Z3::Ast.int("a")
17
+ b = Z3::Ast.int("b")
18
+ solver = Z3::Solver.new
19
+ puts "Checking if a+b >= a"
20
+ solver.prove!(a+b >= a)
21
+
22
+ solver = Z3::Solver.new
23
+ solver.assert(a >= 0)
24
+ solver.assert(b >= 0)
25
+ puts "Checking if a+b >= a if a,b >= 0"
26
+ solver.prove!(a+b >= a)
27
+ end
28
+
29
+ check_multiplication_laws_1
30
+ check_inequalities
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative "../lib/z3"
4
+
5
+ def check_if_true_is_true
6
+ a = Z3::Ast.true
7
+ b = Z3::Ast.true
8
+ solver = Z3::Solver.new
9
+ puts "Checking if true == true"
10
+ solver.prove!(a == b)
11
+ end
12
+
13
+ def check_if_true_is_false
14
+ a = Z3::Ast.true
15
+ b = Z3::Ast.false
16
+ solver = Z3::Solver.new
17
+ puts "Checking if true == false"
18
+ solver.prove!(a==b)
19
+ end
20
+
21
+ # We prove it by checking that negation is unsatisfiable
22
+ def check_de_morgan_law_1
23
+ a = Z3::Ast::bool("a")
24
+ b = Z3::Ast::bool("b")
25
+ solver = Z3::Solver.new
26
+ puts "Proving ~(a & b) == (~a | ~b)"
27
+ solver.prove!(~(a & b) == (~a | ~b))
28
+ end
29
+
30
+ def check_de_morgan_law_2
31
+ a = Z3::Ast::bool("a")
32
+ b = Z3::Ast::bool("b")
33
+ solver = Z3::Solver.new
34
+ puts "Proving ~(a | b) == (~a & ~b)"
35
+ solver.prove!(~(a | b) == (~a & ~b))
36
+ end
37
+
38
+ check_if_true_is_true
39
+ check_if_true_is_false
40
+ check_de_morgan_law_1
41
+ check_de_morgan_law_2
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative "../lib/z3"
4
+
5
+ solver = Z3::Solver.new
6
+
7
+ ax = Z3::Ast.real("a.x")
8
+ ay = Z3::Ast.real("a.y")
9
+ bx = Z3::Ast.real("b.x")
10
+ by = Z3::Ast.real("b.y")
11
+ cx = Z3::Ast.real("c.x")
12
+ cy = Z3::Ast.real("c.y")
13
+ dx = Z3::Ast.real("d.x")
14
+ dy = Z3::Ast.real("d.y")
15
+
16
+ a_c = Z3::Ast.real("|a-c|")
17
+ b_d = Z3::Ast.real("|b-d|")
18
+
19
+ solver.assert(bx == 0)
20
+ solver.assert(by == 0)
21
+ solver.assert(cx == 10)
22
+ solver.assert(cy == 0)
23
+ solver.assert(dx == cx)
24
+ solver.assert(ay == dy)
25
+ solver.assert(ax == 0)
26
+
27
+ # BD is on the circle
28
+ solver.assert(b_d**2 == (bx-dx)**2 + (by-dy)**2)
29
+ solver.assert(b_d == 20)
30
+
31
+ solver.assert(a_c**2 == (ax-cx)**2 + (ay-cy)**2)
32
+
33
+ if solver.check == :sat
34
+ model = solver.model
35
+ model.each do |n,v|
36
+ puts "* #{n} = #{v}"
37
+ end
38
+ else
39
+ puts "Can't solve the problem"
40
+ end
@@ -0,0 +1,219 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Problems from: http://www.physicsclassroom.com/class/1DKin/Lesson-6/Sample-Problems-and-Solutions
4
+
5
+ require_relative "../lib/z3"
6
+
7
+ class KinematicsProblem
8
+ attr_reader :solver
9
+ def initialize
10
+ @solver = Z3::Solver.new
11
+ end
12
+
13
+ def assert(ast)
14
+ @solver.assert(ast)
15
+ end
16
+
17
+ def print_solution!(number)
18
+ puts("Solution to problem %s:" % number)
19
+ if @solver.check() == :sat
20
+ @solver.model.each do |n,v|
21
+ puts "* #{n} = #{v}"
22
+ end
23
+ else
24
+ puts "* Can't solve the problem"
25
+ end
26
+ end
27
+ end
28
+
29
+ class KinematicsProblem01 < KinematicsProblem
30
+ """
31
+ An airplane accelerates down a runway at 3.20 m/s2 for 32.8 s until is finally lifts off the ground.
32
+ Determine the distance traveled before takeoff.
33
+ """
34
+ def solve!
35
+ a = Z3::Ast.real("a")
36
+ t = Z3::Ast.real("t")
37
+ d = Z3::Ast.real("d")
38
+ assert a == 3.20
39
+ assert t == 32.8
40
+ assert d == a*t*t/2
41
+ print_solution! "01"
42
+ end
43
+ end
44
+
45
+ class KinematicsProblem02 < KinematicsProblem
46
+ """
47
+ A car starts from rest and accelerates uniformly over a time of 5.21 seconds for a distance of 110 m. Determine the acceleration of the car.
48
+ """
49
+ def solve!
50
+ a = Z3::Ast.real("a")
51
+ t = Z3::Ast.real("t")
52
+ d = Z3::Ast.real("d")
53
+ assert d == a*t*t/2
54
+ assert t == 5.21
55
+ assert d == 110
56
+ print_solution! "02"
57
+ end
58
+ end
59
+
60
+ class KinematicsProblem03 < KinematicsProblem
61
+ """
62
+ Upton Chuck is riding the Giant Drop at Great America.
63
+ If Upton free falls for 2.60 seconds, what will be his final velocity and how far will he fall?
64
+ """
65
+ def solve!
66
+ a = Z3::Ast.real("a")
67
+ t = Z3::Ast.real("t")
68
+ v = Z3::Ast.real("v")
69
+ d = Z3::Ast.real("d")
70
+ assert a == 9.81
71
+ assert d == a*t*t/2
72
+ assert v == a*t
73
+ assert t == 2.60
74
+ print_solution! "03"
75
+ end
76
+ end
77
+
78
+ class KinematicsProblem04 < KinematicsProblem
79
+ """
80
+ A race car accelerates uniformly from 18.5 m/s to 46.1 m/s in 2.47 seconds. Determine the acceleration of the car and the distance traveled.
81
+ """
82
+ def solve!
83
+ a = Z3::Ast.real("a")
84
+ t = Z3::Ast.real("t")
85
+ vs= Z3::Ast.real("vs")
86
+ ve = Z3::Ast.real("ve")
87
+ d = Z3::Ast.real("d")
88
+ assert vs == 18.5
89
+ assert ve == 46.1
90
+ assert t == 2.47
91
+ assert a == (ve-vs)/t
92
+ assert d == (vs+ve)/2*t
93
+ print_solution! "04"
94
+ end
95
+ end
96
+
97
+ class KinematicsProblem05 < KinematicsProblem
98
+ """
99
+ A feather is dropped on the moon from a height of 1.40 meters.
100
+ The acceleration of gravity on the moon is 1.67 m/s2.
101
+ Determine the time for the feather to fall to the surface of the moon.
102
+ """
103
+ def solve!
104
+ a = Z3::Ast.real("a")
105
+ t = Z3::Ast.real("t")
106
+ d = Z3::Ast.real("d")
107
+ assert a == 1.67
108
+ assert d == 1.40
109
+ assert t >= 0
110
+ assert d == a*t*t/2
111
+ print_solution! "05"
112
+ end
113
+ end
114
+
115
+ class KinematicsProblem06 < KinematicsProblem
116
+ """
117
+ Rocket-powered sleds are used to test the human response to acceleration.
118
+ If a rocket-powered sled is accelerated to a speed of 444 m/s in 1.83 seconds,
119
+ then what is the acceleration and what is the distance that the sled travels?
120
+ """
121
+ def solve!
122
+ a = Z3::Ast.real("a")
123
+ t = Z3::Ast.real("t")
124
+ d = Z3::Ast.real("d")
125
+ v = Z3::Ast.real("v")
126
+ assert v == 444
127
+ assert t == 1.83
128
+ assert v == a*t
129
+ assert d == a*t*t/2
130
+ print_solution! "06"
131
+ end
132
+ end
133
+
134
+ class KinematicsProblem07 < KinematicsProblem
135
+ """
136
+ A bike accelerates uniformly from rest to a speed of 7.10 m/s over a distance of 35.4 m.
137
+ Determine the acceleration of the bike.
138
+ """
139
+ def solve!
140
+ a = Z3::Ast.real("a")
141
+ t = Z3::Ast.real("t")
142
+ d = Z3::Ast.real("d")
143
+ v = Z3::Ast.real("v")
144
+ assert v == 7.10
145
+ assert d == 35.4
146
+ assert a*t == v
147
+ assert t*v/2 == d
148
+ print_solution! "07"
149
+ end
150
+ end
151
+
152
+ class KinematicsProblem08 < KinematicsProblem
153
+ """
154
+ An engineer is designing the runway for an airport.
155
+ Of the planes that will use the airport, the lowest acceleration rate is likely to be 3 m/s2.
156
+ The takeoff speed for this plane will be 65 m/s.
157
+ Assuming this minimum acceleration, what is the minimum allowed length for the runway?
158
+ """
159
+ def solve!
160
+ a = Z3::Ast.real("a")
161
+ t = Z3::Ast.real("t")
162
+ d = Z3::Ast.real("d")
163
+ v = Z3::Ast.real("v")
164
+ assert a == 3
165
+ assert v == 65
166
+ assert a*t == v
167
+ assert t*v/2 == d
168
+ print_solution! "08"
169
+ end
170
+ end
171
+
172
+ class KinematicsProblem09 < KinematicsProblem
173
+ """
174
+ A car traveling at 22.4 m/s skids to a stop in 2.55 s.
175
+ Determine the skidding distance of the car (assume uniform acceleration).
176
+ """
177
+ def solve!
178
+ t = Z3::Ast.real("t")
179
+ d = Z3::Ast.real("d")
180
+ v = Z3::Ast.real("v")
181
+ assert v == 22.4
182
+ assert t == 2.55
183
+ assert d == t*v/2
184
+ print_solution! "09"
185
+ end
186
+ end
187
+
188
+ class KinematicsProblem10 < KinematicsProblem
189
+ """
190
+ A kangaroo is capable of jumping to a height of 2.62 m.
191
+ Determine the takeoff speed of the kangaroo.
192
+ """
193
+ def solve!
194
+ a = Z3::Ast.real("a")
195
+ t = Z3::Ast.real("t")
196
+ d = Z3::Ast.real("d")
197
+ v = Z3::Ast.real("v")
198
+ assert d == 2.62
199
+ assert a == -9.81
200
+ assert d == v*t/2
201
+ assert v + a*t == 0
202
+ assert t >= 0
203
+ print_solution! "10"
204
+ end
205
+ end
206
+
207
+ # This is actually param for Python Z3 printer, can't work until we get that
208
+ # Z3.set_param("rational_to_decimal", true)
209
+
210
+ KinematicsProblem01.new.solve!
211
+ KinematicsProblem02.new.solve!
212
+ KinematicsProblem03.new.solve!
213
+ KinematicsProblem04.new.solve!
214
+ KinematicsProblem05.new.solve!
215
+ KinematicsProblem06.new.solve!
216
+ KinematicsProblem07.new.solve!
217
+ KinematicsProblem08.new.solve!
218
+ KinematicsProblem09.new.solve!
219
+ KinematicsProblem10.new.solve!
@@ -0,0 +1,105 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative "../lib/z3"
4
+
5
+ class LightUp
6
+ def initialize(data)
7
+ data = data.split.map{|line| line.strip.chars}
8
+ @xsize = data[0].size
9
+ @ysize = data.size
10
+ @data = map_coordinates{|x,y| data[y][x]}
11
+ @solver = Z3::Solver.new
12
+ end
13
+
14
+ def solve!
15
+ @lamps = map_coordinates{|x,y| int01(x,y)}
16
+
17
+ # No lamps on walls
18
+ # Numbers count lamps next to node (diagonals don't count)
19
+ (0...@ysize).each do |y|
20
+ (0...@xsize).each do |x|
21
+ v = @data[[x,y]]
22
+ next if v == "."
23
+ @solver.assert @lamps[[x,y]] == 0
24
+ if ("0".."4").include?(v)
25
+ @solver.assert Z3::Ast.add(*lamps_next_to_cell(x,y)) == v.to_i
26
+ end
27
+ end
28
+ end
29
+
30
+ # Every cell is in raycast of a lamp
31
+ # No lamp is in raycast of another lamp
32
+ (0...@ysize).each do |y|
33
+ (0...@xsize).each do |x|
34
+ raycast = Z3::Ast.add(*raycast_cells(x,y))
35
+ @solver.assert Z3::Ast.implies(@lamps[[x,y]] == 0, raycast >= 1)
36
+ @solver.assert Z3::Ast.implies(@lamps[[x,y]] == 1, raycast == 0)
37
+ end
38
+ end
39
+
40
+ if @solver.check == :sat
41
+ @model = @solver.model
42
+ print_answer!
43
+ else
44
+ puts "failed to solve"
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ def lamps_next_to_cell(x0,y0)
51
+ [[x0-1,y0],[x0+1,y0],[x0,y0-1],[x0,y0+1]].map{|x,y| @lamps[[x,y]]}.compact
52
+ end
53
+
54
+ def raycast_cells(x0,y0)
55
+ result = []
56
+ [[1,0],[-1,0],[0,1],[0,-1]].each do |dx,dy|
57
+ x = x0+dx
58
+ y = y0+dy
59
+ while @data[[x,y]] == "."
60
+ result << @lamps[[x,y]]
61
+ x += dx
62
+ y += dy
63
+ end
64
+ end
65
+ result
66
+ end
67
+
68
+ def map_coordinates
69
+ Hash[(0...@xsize).to_a.product((0...@ysize).to_a).map{|x,y| [[x,y],yield(x,y)]}]
70
+ end
71
+
72
+ def print_answer!
73
+ (0...@ysize).each do |y|
74
+ (0...@xsize).each do |x|
75
+ if @data[[x,y]] != "."
76
+ print(@data[[x,y]])
77
+ elsif @model[@lamps[[x,y]]].to_s == "1"
78
+ print("*")
79
+ else
80
+ print(" ")
81
+ end
82
+ end
83
+ puts "\n"
84
+ end
85
+ end
86
+
87
+ def int01(x,y)
88
+ v = Z3::Ast.int("l#{x},#{y}")
89
+ @solver.assert v >= 0
90
+ @solver.assert v <= 1
91
+ v
92
+ end
93
+ end
94
+
95
+ LightUp.new(
96
+ """
97
+ ....0..
98
+ .......
99
+ x.2.x..
100
+ ...3...
101
+ ..x.x.3
102
+ .......
103
+ ..1....
104
+ """
105
+ ).solve!
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative "../lib/z3"
4
+
5
+ class MiniSudokuSolver
6
+ def initialize(data)
7
+ @data = data
8
+ @solver = Z3::Solver.new
9
+ end
10
+
11
+ def solve!
12
+ @cells = (0..5).map do |j|
13
+ (0..5).map do |i|
14
+ cell_var(@data[j][i], i, j)
15
+ end
16
+ end
17
+
18
+ @cells.each do |row|
19
+ @solver.assert Z3::Ast.distinct(*row)
20
+ end
21
+ @cells.transpose.each do |column|
22
+ @solver.assert Z3::Ast.distinct(*column)
23
+ end
24
+ @cells.each_slice(2) do |rows|
25
+ rows.transpose.each_slice(3) do |square|
26
+ @solver.assert Z3::Ast.distinct(*square.flatten)
27
+ end
28
+ end
29
+
30
+ if @solver.check == :sat
31
+ @model = @solver.model
32
+ print_answer!
33
+ else
34
+ puts "failed to solve"
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def cell_var(cell, i, j)
41
+ v = Z3::Ast.int("cell[#{i+1},#{j+1}]")
42
+ @solver.assert v >= 1
43
+ @solver.assert v <= 6
44
+ @solver.assert v == cell if cell != nil
45
+ v
46
+ end
47
+
48
+ def print_answer!
49
+ @cells.each do |row|
50
+ puts row.map{|v| @model[v]}.join(" ")
51
+ end
52
+ end
53
+ end
54
+
55
+ _ = nil
56
+ minisudoku = MiniSudokuSolver.new([
57
+ [_, _, _, 4, _, _],
58
+ [_, _, 4, 1, 2, _],
59
+ [_, _, 6, 5, 4, _],
60
+ [_, 5, 2, 3, _, _],
61
+ [_, 2, 3, 6, _, _],
62
+ [_, _, 1, _, _, _],
63
+ ])
64
+ minisudoku.solve!