z3 0.0.20180624 → 0.0.20211213
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 +4 -4
- data/README.md +2 -4
- data/Rakefile +15 -8
- data/examples/abc_path +187 -0
- data/examples/abc_path-1.txt +7 -0
- data/examples/algebra_problems +12 -12
- data/examples/aquarium +133 -0
- data/examples/aquarium-1.txt +11 -0
- data/examples/bridges +2 -2
- data/examples/cats_organized_neatly +133 -0
- data/examples/cats_organized_neatly-10.txt +15 -0
- data/examples/cats_organized_neatly-3.txt +8 -0
- data/examples/cats_organized_neatly-48.txt +32 -0
- data/examples/circuit_problems +4 -4
- data/examples/clogic_puzzle +2 -2
- data/examples/color_nonogram +150 -0
- data/examples/color_nonogram-1.txt +23 -0
- data/examples/crossflip +2 -4
- data/examples/dominion +153 -0
- data/examples/dominion-1.txt +8 -0
- data/examples/dominosa +133 -0
- data/examples/dominosa-1.txt +8 -0
- data/examples/eulero +99 -0
- data/examples/eulero-1.txt +5 -0
- data/examples/four_hackers_puzzle +2 -2
- data/examples/futoshiki +128 -0
- data/examples/futoshiki-1.txt +17 -0
- data/examples/kakurasu +73 -0
- data/examples/kakurasu-1.txt +2 -0
- data/examples/kakuro +2 -2
- data/examples/killer_sudoku +88 -0
- data/examples/killer_sudoku-1.txt +17 -0
- data/examples/killer_sudoku-2.txt +53 -0
- data/examples/kinematics_problems +20 -20
- data/examples/knights_puzzle +2 -2
- data/examples/kropki +100 -0
- data/examples/kropki-1.txt +13 -0
- data/examples/letter_connections +2 -2
- data/examples/light_up +2 -2
- data/examples/minisudoku +2 -2
- data/examples/miracle_sudoku +135 -0
- data/examples/miracle_sudoku-1.txt +9 -0
- data/examples/mortal_coil_puzzle +2 -2
- data/examples/nanro +245 -0
- data/examples/nanro-1.txt +8 -0
- data/examples/nine_clocks +106 -0
- data/examples/nonogram +2 -2
- data/examples/pyramid_nonogram +2 -2
- data/examples/regexp_crossword_solver +2 -2
- data/examples/regexp_solver +2 -2
- data/examples/renzoku +124 -0
- data/examples/renzoku-1.txt +17 -0
- data/examples/sandwich_sudoku +101 -0
- data/examples/sandwich_sudoku-1.txt +10 -0
- data/examples/selfref +2 -2
- data/examples/simple_regexp_parser.rb +58 -56
- data/examples/skyscrapers +118 -0
- data/examples/skyscrapers-1.txt +6 -0
- data/examples/skyscrapers-2.txt +11 -0
- data/examples/star_battle +134 -0
- data/examples/star_battle-1.txt +10 -0
- data/examples/stitches +180 -0
- data/examples/stitches-1.txt +11 -0
- data/examples/sudoku +2 -2
- data/examples/suguru +199 -0
- data/examples/suguru-1.txt +17 -0
- data/examples/verbal_arithmetic +2 -2
- data/examples/yajilin +268 -0
- data/examples/yajilin-1.txt +10 -0
- data/lib/z3/ast.rb +8 -0
- data/lib/z3/expr/bitvec_expr.rb +10 -0
- data/lib/z3/expr/expr.rb +16 -15
- data/lib/z3/low_level.rb +6 -2
- data/lib/z3/low_level_auto.rb +180 -36
- data/lib/z3/optimize.rb +5 -4
- data/lib/z3/printer.rb +29 -1
- data/lib/z3/sort/bitvec_sort.rb +1 -0
- data/lib/z3/sort/sort.rb +9 -5
- data/lib/z3/very_low_level.rb +8 -5
- data/lib/z3/very_low_level_auto.rb +45 -9
- data/spec/bitvec_expr_spec.rb +35 -21
- data/spec/bitvec_sort_spec.rb +4 -0
- data/spec/expr_spec.rb +62 -0
- data/spec/integration/abc_path_spec.rb +21 -0
- data/spec/integration/aquarium_spec.rb +27 -0
- data/spec/integration/cats_organized_neatly_spec.rb +14 -0
- data/spec/integration/color_nonogram_spec.rb +28 -0
- data/spec/integration/dominion_spec.rb +14 -0
- data/spec/integration/dominosa_spec.rb +21 -0
- data/spec/integration/eulero_spec.rb +11 -0
- data/spec/integration/futoshiki_spec.rb +23 -0
- data/spec/integration/kakurasu_spec.rb +18 -0
- data/spec/integration/killer_sudoku_spec.rb +10 -0
- data/spec/integration/knights_puzzle_spec.rb +11 -11
- data/spec/integration/kropki_spec.rb +19 -0
- data/spec/integration/miracle_sudoku_spec.rb +15 -0
- data/spec/integration/mortal_coil_puzzle_spec.rb +8 -6
- data/spec/integration/nanro_spec.rb +39 -0
- data/spec/integration/nine_clocks_spec.rb +30 -0
- data/spec/integration/oneofus_spec.rb +7 -15
- data/spec/integration/regexp_crossword_solver_spec.rb +1 -1
- data/spec/integration/renzoku_spec.rb +23 -0
- data/spec/integration/sandwich_sudoku_spec.rb +15 -0
- data/spec/integration/skyscraper_spec.rb +10 -0
- data/spec/integration/star_battle_spec.rb +27 -0
- data/spec/integration/stitches_spec.rb +25 -0
- data/spec/integration/suguru_spec.rb +23 -0
- data/spec/integration/yajilin_spec.rb +25 -0
- data/spec/interface_spec.rb +18 -0
- data/spec/optimize_spec.rb +6 -4
- data/spec/printer_spec.rb +30 -0
- data/spec/set_expr_spec.rb +14 -8
- data/spec/solver_spec.rb +4 -5
- data/spec/spec_helper.rb +15 -0
- metadata +104 -24
data/examples/futoshiki
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "pathname"
|
4
|
+
require_relative "../lib/z3"
|
5
|
+
|
6
|
+
class Futoshiki
|
7
|
+
# This needs to be very exactly formatted
|
8
|
+
def initialize(path)
|
9
|
+
@data = Pathname(path).readlines.map(&:chomp)
|
10
|
+
@size = (@data.size+1)/2
|
11
|
+
@solver = Z3::Solver.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def cell_value(x, y)
|
15
|
+
v = @data[y*2][x*2]
|
16
|
+
if v == "#"
|
17
|
+
nil
|
18
|
+
elsif v =~ /\d/
|
19
|
+
v.to_i
|
20
|
+
else
|
21
|
+
raise "Bad cell value"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def cmp_right(x, y)
|
26
|
+
v = @data[y*2][x*2 + 1]
|
27
|
+
if v == ">"
|
28
|
+
">"
|
29
|
+
elsif v == "<"
|
30
|
+
"<"
|
31
|
+
elsif v == " "
|
32
|
+
nil
|
33
|
+
else
|
34
|
+
raise "Bad dot value"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def cmp_bottom(x, y)
|
39
|
+
v = @data[y*2 + 1][x*2]
|
40
|
+
if v == "_"
|
41
|
+
">"
|
42
|
+
elsif v == "^"
|
43
|
+
"<"
|
44
|
+
elsif v == " " or v == nil
|
45
|
+
false
|
46
|
+
else
|
47
|
+
raise "Bad dot value"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def call
|
52
|
+
@vars = {}
|
53
|
+
@size.times do |y|
|
54
|
+
@size.times do |x|
|
55
|
+
v = Z3.Int("v#{x},#{y}")
|
56
|
+
@vars[[x,y]] = v
|
57
|
+
cv = cell_value(x, y)
|
58
|
+
if cv
|
59
|
+
@solver.assert (v == cv)
|
60
|
+
else
|
61
|
+
@solver.assert (v >= 1) & (v <= @size)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
@size.times do |x|
|
67
|
+
line = @size.times.map{|y| @vars[[x,y]] }
|
68
|
+
@solver.assert Z3.Distinct(*line)
|
69
|
+
end
|
70
|
+
|
71
|
+
@size.times do |y|
|
72
|
+
line = @size.times.map{|x| @vars[[x,y]] }
|
73
|
+
@solver.assert Z3.Distinct(*line)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Compare right
|
77
|
+
(0..@size-1).each do |y|
|
78
|
+
(0..@size-2).each do |x|
|
79
|
+
lv = @vars[[x,y]]
|
80
|
+
rv = @vars[[x+1,y]]
|
81
|
+
cmp = cmp_right(x,y)
|
82
|
+
if cmp == ">"
|
83
|
+
@solver.assert lv > rv
|
84
|
+
elsif cmp == "<"
|
85
|
+
@solver.assert lv < rv
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Compare bottom
|
91
|
+
(0..@size-2).each do |y|
|
92
|
+
(0..@size-1).each do |x|
|
93
|
+
tv = @vars[[x,y]]
|
94
|
+
bv = @vars[[x,y+1]]
|
95
|
+
cmp = cmp_bottom(x,y)
|
96
|
+
if cmp == ">"
|
97
|
+
@solver.assert tv > bv
|
98
|
+
elsif cmp == "<"
|
99
|
+
@solver.assert tv < bv
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
if @solver.satisfiable?
|
105
|
+
@model = @solver.model
|
106
|
+
print_answer!
|
107
|
+
else
|
108
|
+
puts "failed to solve"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def print_answer!
|
115
|
+
output = @data.map(&:dup)
|
116
|
+
@size.times do |y|
|
117
|
+
@size.times do |x|
|
118
|
+
v = @model[@vars[[x,y]]]
|
119
|
+
output[2*y][2*x] = "#{v}"
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
puts output
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
path = ARGV[0] || Pathname(__dir__) + "futoshiki-1.txt"
|
128
|
+
Futoshiki.new(path).call
|
data/examples/kakurasu
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "pathname"
|
4
|
+
require_relative "../lib/z3"
|
5
|
+
|
6
|
+
class Kakurasu
|
7
|
+
def initialize(path)
|
8
|
+
data = Pathname(path).readlines.grep(/\S/)
|
9
|
+
raise "Data needs to have two lines (cols, rows)" unless data.size == 2
|
10
|
+
@col_sums = data[0].split.map(&:to_i)
|
11
|
+
@row_sums = data[1].split.map(&:to_i)
|
12
|
+
|
13
|
+
@xsize = @col_sums.size
|
14
|
+
@ysize = @row_sums.size
|
15
|
+
@solver = Z3::Solver.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def call
|
19
|
+
# setup
|
20
|
+
@bvars = {}
|
21
|
+
@cvars = {}
|
22
|
+
@rvars = {}
|
23
|
+
@ysize.times do |y|
|
24
|
+
@ysize.times do |x|
|
25
|
+
b = Z3.Bool("b#{x},#{y}")
|
26
|
+
r = Z3.Int("r#{x},#{y}")
|
27
|
+
c = Z3.Int("c#{x},#{y}")
|
28
|
+
@solver.assert (!b).implies(r == 0)
|
29
|
+
@solver.assert (!b).implies(c == 0)
|
30
|
+
@solver.assert b.implies(r == (x+1))
|
31
|
+
@solver.assert b.implies(c == (y+1))
|
32
|
+
@bvars[[x,y]] = b
|
33
|
+
@cvars[x] ||= []
|
34
|
+
@cvars[x][y] = c
|
35
|
+
@rvars[y] ||= []
|
36
|
+
@rvars[y][x] = r
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
@xsize.times do |x|
|
41
|
+
@solver.assert Z3.Add(*@rvars[x]) == @row_sums[x]
|
42
|
+
end
|
43
|
+
|
44
|
+
@ysize.times do |y|
|
45
|
+
@solver.assert Z3.Add(*@cvars[y]) == @col_sums[y]
|
46
|
+
end
|
47
|
+
|
48
|
+
if @solver.satisfiable?
|
49
|
+
@model = @solver.model
|
50
|
+
print_board!
|
51
|
+
else
|
52
|
+
puts "failed to solve"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def print_board!
|
59
|
+
@ysize.times do |y|
|
60
|
+
@ysize.times do |x|
|
61
|
+
if @model[@bvars[[x,y]]].to_b
|
62
|
+
print "[X]"
|
63
|
+
else
|
64
|
+
print "[ ]"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
print "\n"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
path = ARGV[0] || Pathname(__dir__) + "kakurasu-1.txt"
|
73
|
+
Kakurasu.new(path).call
|
data/examples/kakuro
CHANGED
@@ -25,7 +25,7 @@ class Kakuro
|
|
25
25
|
@solver = Z3::Solver.new
|
26
26
|
end
|
27
27
|
|
28
|
-
def
|
28
|
+
def call
|
29
29
|
@cells = map_coordinates{|x,y| cell_var(x,y) if @data[[x,y]] == nil}.compact
|
30
30
|
|
31
31
|
(0...@ysize).each do |y|
|
@@ -111,4 +111,4 @@ class Kakuro
|
|
111
111
|
end
|
112
112
|
|
113
113
|
path = ARGV[0] || Pathname(__dir__) + "kakuro-1.txt"
|
114
|
-
Kakuro.new(path).
|
114
|
+
Kakuro.new(path).call
|
@@ -0,0 +1,88 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "pathname"
|
4
|
+
require_relative "../lib/z3"
|
5
|
+
|
6
|
+
class KillerSudokuSolver
|
7
|
+
def initialize(path)
|
8
|
+
data = Pathname(path).read
|
9
|
+
knowns, cages, cage_counts = data.split(/\n{2,}/)
|
10
|
+
@knowns = knowns.strip.split("\n").map do |line|
|
11
|
+
line.split.map{|c| c == "." ? nil : c.to_i}
|
12
|
+
end
|
13
|
+
@cages = cages.strip.split("\n").map do |line|
|
14
|
+
line.split
|
15
|
+
end
|
16
|
+
@size = @knowns.size
|
17
|
+
raise "Bad size" unless @knowns.all?{|line| line.size == @size}
|
18
|
+
raise "Bad size" unless @cages.size == @size
|
19
|
+
raise "Bad size" unless @cages.all?{|line| line.size == @size}
|
20
|
+
@cage_counts = cage_counts.split("\n").to_h(&:split).transform_values(&:to_i)
|
21
|
+
@solver = Z3::Solver.new
|
22
|
+
if @size == 9
|
23
|
+
@boxsize = 3
|
24
|
+
elsif @size == 4
|
25
|
+
@boxsize = 2
|
26
|
+
else
|
27
|
+
raise "Bad size"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def call
|
32
|
+
@cells = (0...@size).map do |j|
|
33
|
+
(0...@size).map do |i|
|
34
|
+
cell_var(@knowns[j][i], i, j)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
@cells.each do |row|
|
39
|
+
@solver.assert Z3.Distinct(*row)
|
40
|
+
end
|
41
|
+
@cells.transpose.each do |column|
|
42
|
+
@solver.assert Z3.Distinct(*column)
|
43
|
+
end
|
44
|
+
@cells.each_slice(@boxsize) do |rows|
|
45
|
+
rows.transpose.each_slice(@boxsize) do |square|
|
46
|
+
@solver.assert Z3.Distinct(*square.flatten)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
by_cage = {}
|
51
|
+
(0...@size).each do |j|
|
52
|
+
(0...@size).each do |i|
|
53
|
+
c = @cages[j][i]
|
54
|
+
by_cage[c] ||= []
|
55
|
+
by_cage[c] << @cells[j][i]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
by_cage.each do |cage_name, cells|
|
60
|
+
@solver.assert Z3.Add(*cells) == @cage_counts.fetch(cage_name)
|
61
|
+
@solver.assert Z3.Distinct(*cells)
|
62
|
+
end
|
63
|
+
|
64
|
+
if @solver.satisfiable?
|
65
|
+
@model = @solver.model
|
66
|
+
print_answer!
|
67
|
+
else
|
68
|
+
puts "failed to solve"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def cell_var(cell, i, j)
|
73
|
+
v = Z3.Int("cell[#{i+1},#{j+1}]")
|
74
|
+
@solver.assert v >= 1
|
75
|
+
@solver.assert v <= @size
|
76
|
+
@solver.assert v == cell if cell != nil
|
77
|
+
v
|
78
|
+
end
|
79
|
+
|
80
|
+
def print_answer!
|
81
|
+
@cells.each do |row|
|
82
|
+
puts row.map{|v| @model[v]}.join(" ")
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
path = ARGV[0] || Pathname(__dir__) + "killer_sudoku-1.txt"
|
88
|
+
KillerSudokuSolver.new(path).call
|
@@ -0,0 +1,53 @@
|
|
1
|
+
. . . . . . . . .
|
2
|
+
. . . . . . . . .
|
3
|
+
. . . . . . . . .
|
4
|
+
. . . . . . . . .
|
5
|
+
. . . . . . . . .
|
6
|
+
. . . . . . . . .
|
7
|
+
. . . . . . . . .
|
8
|
+
. . . . . . . . .
|
9
|
+
. . . . . . . . .
|
10
|
+
|
11
|
+
a a b c d d d e e
|
12
|
+
f g b c v v x y z
|
13
|
+
f g g u u w x y z
|
14
|
+
f s s t t w A A B
|
15
|
+
h h C C C D D A B
|
16
|
+
i i G G F E E r q
|
17
|
+
j j m G F n o r q
|
18
|
+
k m m F F n o p q
|
19
|
+
k l l n n n p p p
|
20
|
+
|
21
|
+
a 9
|
22
|
+
b 8
|
23
|
+
c 14
|
24
|
+
d 13
|
25
|
+
e 15
|
26
|
+
f 15
|
27
|
+
g 18
|
28
|
+
h 8
|
29
|
+
i 9
|
30
|
+
j 12
|
31
|
+
k 10
|
32
|
+
l 8
|
33
|
+
m 15
|
34
|
+
n 26
|
35
|
+
o 13
|
36
|
+
p 19
|
37
|
+
q 12
|
38
|
+
r 12
|
39
|
+
s 10
|
40
|
+
t 10
|
41
|
+
u 11
|
42
|
+
v 13
|
43
|
+
w 11
|
44
|
+
x 10
|
45
|
+
y 5
|
46
|
+
z 7
|
47
|
+
A 12
|
48
|
+
B 11
|
49
|
+
C 13
|
50
|
+
D 12
|
51
|
+
E 9
|
52
|
+
F 17
|
53
|
+
G 18
|
@@ -31,7 +31,7 @@ class KinematicsProblem01 < KinematicsProblem
|
|
31
31
|
An airplane accelerates down a runway at 3.20 m/s2 for 32.8 s until is finally lifts off the ground.
|
32
32
|
Determine the distance traveled before takeoff.
|
33
33
|
"""
|
34
|
-
def
|
34
|
+
def call
|
35
35
|
a = Z3.Real("a")
|
36
36
|
t = Z3.Real("t")
|
37
37
|
d = Z3.Real("d")
|
@@ -46,7 +46,7 @@ class KinematicsProblem02 < KinematicsProblem
|
|
46
46
|
"""
|
47
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
48
|
"""
|
49
|
-
def
|
49
|
+
def call
|
50
50
|
a = Z3.Real("a")
|
51
51
|
t = Z3.Real("t")
|
52
52
|
d = Z3.Real("d")
|
@@ -62,7 +62,7 @@ class KinematicsProblem03 < KinematicsProblem
|
|
62
62
|
Upton Chuck is riding the Giant Drop at Great America.
|
63
63
|
If Upton free falls for 2.60 seconds, what will be his final velocity and how far will he fall?
|
64
64
|
"""
|
65
|
-
def
|
65
|
+
def call
|
66
66
|
a = Z3.Real("a")
|
67
67
|
t = Z3.Real("t")
|
68
68
|
v = Z3.Real("v")
|
@@ -79,7 +79,7 @@ class KinematicsProblem04 < KinematicsProblem
|
|
79
79
|
"""
|
80
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
81
|
"""
|
82
|
-
def
|
82
|
+
def call
|
83
83
|
a = Z3.Real("a")
|
84
84
|
t = Z3.Real("t")
|
85
85
|
vs= Z3.Real("vs")
|
@@ -100,7 +100,7 @@ class KinematicsProblem05 < KinematicsProblem
|
|
100
100
|
The acceleration of gravity on the moon is 1.67 m/s2.
|
101
101
|
Determine the time for the feather to fall to the surface of the moon.
|
102
102
|
"""
|
103
|
-
def
|
103
|
+
def call
|
104
104
|
a = Z3.Real("a")
|
105
105
|
t = Z3.Real("t")
|
106
106
|
d = Z3.Real("d")
|
@@ -118,7 +118,7 @@ class KinematicsProblem06 < KinematicsProblem
|
|
118
118
|
If a rocket-powered sled is accelerated to a speed of 444 m/s in 1.83 seconds,
|
119
119
|
then what is the acceleration and what is the distance that the sled travels?
|
120
120
|
"""
|
121
|
-
def
|
121
|
+
def call
|
122
122
|
a = Z3.Real("a")
|
123
123
|
t = Z3.Real("t")
|
124
124
|
d = Z3.Real("d")
|
@@ -136,7 +136,7 @@ class KinematicsProblem07 < KinematicsProblem
|
|
136
136
|
A bike accelerates uniformly from rest to a speed of 7.10 m/s over a distance of 35.4 m.
|
137
137
|
Determine the acceleration of the bike.
|
138
138
|
"""
|
139
|
-
def
|
139
|
+
def call
|
140
140
|
a = Z3.Real("a")
|
141
141
|
t = Z3.Real("t")
|
142
142
|
d = Z3.Real("d")
|
@@ -156,7 +156,7 @@ class KinematicsProblem08 < KinematicsProblem
|
|
156
156
|
The takeoff speed for this plane will be 65 m/s.
|
157
157
|
Assuming this minimum acceleration, what is the minimum allowed length for the runway?
|
158
158
|
"""
|
159
|
-
def
|
159
|
+
def call
|
160
160
|
a = Z3.Real("a")
|
161
161
|
t = Z3.Real("t")
|
162
162
|
d = Z3.Real("d")
|
@@ -174,7 +174,7 @@ class KinematicsProblem09 < KinematicsProblem
|
|
174
174
|
A car traveling at 22.4 m/s skids to a stop in 2.55 s.
|
175
175
|
Determine the skidding distance of the car (assume uniform acceleration).
|
176
176
|
"""
|
177
|
-
def
|
177
|
+
def call
|
178
178
|
t = Z3.Real("t")
|
179
179
|
d = Z3.Real("d")
|
180
180
|
v = Z3.Real("v")
|
@@ -190,7 +190,7 @@ class KinematicsProblem10 < KinematicsProblem
|
|
190
190
|
A kangaroo is capable of jumping to a height of 2.62 m.
|
191
191
|
Determine the takeoff speed of the kangaroo.
|
192
192
|
"""
|
193
|
-
def
|
193
|
+
def call
|
194
194
|
a = Z3.Real("a")
|
195
195
|
t = Z3.Real("t")
|
196
196
|
d = Z3.Real("d")
|
@@ -207,13 +207,13 @@ end
|
|
207
207
|
# This is actually param for Python Z3 printer, can't work until we get that
|
208
208
|
# Z3.set_param("rational_to_decimal", true)
|
209
209
|
|
210
|
-
KinematicsProblem01.new.
|
211
|
-
KinematicsProblem02.new.
|
212
|
-
KinematicsProblem03.new.
|
213
|
-
KinematicsProblem04.new.
|
214
|
-
KinematicsProblem05.new.
|
215
|
-
KinematicsProblem06.new.
|
216
|
-
KinematicsProblem07.new.
|
217
|
-
KinematicsProblem08.new.
|
218
|
-
KinematicsProblem09.new.
|
219
|
-
KinematicsProblem10.new.
|
210
|
+
KinematicsProblem01.new.call
|
211
|
+
KinematicsProblem02.new.call
|
212
|
+
KinematicsProblem03.new.call
|
213
|
+
KinematicsProblem04.new.call
|
214
|
+
KinematicsProblem05.new.call
|
215
|
+
KinematicsProblem06.new.call
|
216
|
+
KinematicsProblem07.new.call
|
217
|
+
KinematicsProblem08.new.call
|
218
|
+
KinematicsProblem09.new.call
|
219
|
+
KinematicsProblem10.new.call
|
data/examples/knights_puzzle
CHANGED
@@ -39,7 +39,7 @@ class KnightsPuzzle
|
|
39
39
|
puts ""
|
40
40
|
end
|
41
41
|
|
42
|
-
def
|
42
|
+
def call
|
43
43
|
if @solver.satisfiable?
|
44
44
|
@model = @solver.model
|
45
45
|
puts "Solved"
|
@@ -119,4 +119,4 @@ class KnightsPuzzle
|
|
119
119
|
end
|
120
120
|
end
|
121
121
|
|
122
|
-
KnightsPuzzle.new.
|
122
|
+
KnightsPuzzle.new.call
|
data/examples/kropki
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
|
4
|
+
require "pathname"
|
5
|
+
require_relative "../lib/z3"
|
6
|
+
|
7
|
+
# Based on https://play.google.com/store/apps/details?id=com.alexuvarov.android.kropki.puzzle&hl=en_GB
|
8
|
+
#
|
9
|
+
# NxN grid
|
10
|
+
# Each cell contains numbers 1 to N
|
11
|
+
# Each row and each column contains distinct numbers
|
12
|
+
# If there's black dot (o) between cells, one is twice the other
|
13
|
+
# If there's white dot (*) between cells, one is the other plus one
|
14
|
+
# If there's no dot, neither of these is true
|
15
|
+
# (for 1/2, dot can be of either color)
|
16
|
+
|
17
|
+
class Kropki
|
18
|
+
def initialize(path)
|
19
|
+
@data = Pathname(path).readlines.map(&:chomp)
|
20
|
+
@size = (@data.size - 1) / 2
|
21
|
+
raise unless @data.size == 2 * @size + 1
|
22
|
+
raise unless @data.all?{ |row| row.size == 2 * @size + 1 }
|
23
|
+
@solver = Z3::Solver.new
|
24
|
+
end
|
25
|
+
|
26
|
+
def call
|
27
|
+
# Cells contain numbers 1 - N
|
28
|
+
@size.times do |y|
|
29
|
+
@size.times do |x|
|
30
|
+
@solver.assert cell(x, y) >= 1
|
31
|
+
@solver.assert cell(x, y) <= @size
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Each row and column distinct
|
36
|
+
@size.times do |y|
|
37
|
+
@solver.assert Z3.Distinct(*@size.times.map{ |x| cell(x,y) })
|
38
|
+
end
|
39
|
+
@size.times do |x|
|
40
|
+
@solver.assert Z3.Distinct(*@size.times.map{ |y| cell(x,y) })
|
41
|
+
end
|
42
|
+
|
43
|
+
# Horizontal dots
|
44
|
+
@size.times do |y|
|
45
|
+
(0...@size).each do |x|
|
46
|
+
dot_constraints cell(x, y), cell(x+1, y), @data[2*y+1][2*x+2]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Vertical dots
|
51
|
+
@size.times do |x|
|
52
|
+
(0...@size).each do |y|
|
53
|
+
dot_constraints cell(x, y), cell(x, y+1), @data[2*y+2][2*x+1]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
if @solver.satisfiable?
|
58
|
+
@model = @solver.model
|
59
|
+
print_answer
|
60
|
+
else
|
61
|
+
puts "failed to solve"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def dot_constraints(c1, c2, dot)
|
68
|
+
if dot == "o"
|
69
|
+
@solver.assert Z3.Or(c1 == c2 + 1, c2 == c1 + 1)
|
70
|
+
elsif dot == "*"
|
71
|
+
@solver.assert Z3.Or(c1 == c2 * 2, c2 == c1 * 2)
|
72
|
+
else
|
73
|
+
@solver.assert c1 != c2 + 1
|
74
|
+
@solver.assert c2 != c1 + 1
|
75
|
+
@solver.assert c1 != c2 * 2
|
76
|
+
@solver.assert c2 != c1 * 2
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def cell(x, y)
|
81
|
+
Z3.Int("c#{x},#{y}")
|
82
|
+
end
|
83
|
+
|
84
|
+
def print_answer
|
85
|
+
output = @data.map(&:dup)
|
86
|
+
@size.times do |y|
|
87
|
+
@size.times do |x|
|
88
|
+
# This only works for 1-9, could use hex or something for more
|
89
|
+
value = @model[cell(x,y)].to_s
|
90
|
+
output[2*y+1][2*x+1, 1] = value
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
puts output
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
path = ARGV[0] || Pathname(__dir__) + "kropki-1.txt"
|
100
|
+
Kropki.new(path).call
|
data/examples/letter_connections
CHANGED
@@ -61,7 +61,7 @@ class LetterConnections
|
|
61
61
|
@solver = Z3::Solver.new
|
62
62
|
end
|
63
63
|
|
64
|
-
def
|
64
|
+
def call
|
65
65
|
@line = map_coordinates{|x,y| line_var(x,y) }
|
66
66
|
@dir = map_coordinates{|x,y| dir_var(x,y) }
|
67
67
|
|
@@ -187,4 +187,4 @@ class LetterConnections
|
|
187
187
|
end
|
188
188
|
|
189
189
|
path = ARGV[0] || Pathname(__dir__) + "letter_connections-1.txt"
|
190
|
-
LetterConnections.new(path).
|
190
|
+
LetterConnections.new(path).call
|
data/examples/light_up
CHANGED
@@ -13,7 +13,7 @@ class LightUp
|
|
13
13
|
@solver = Z3::Solver.new
|
14
14
|
end
|
15
15
|
|
16
|
-
def
|
16
|
+
def call
|
17
17
|
@lamps = map_coordinates{|x,y| int01(x,y)}
|
18
18
|
|
19
19
|
# No lamps on walls
|
@@ -95,4 +95,4 @@ class LightUp
|
|
95
95
|
end
|
96
96
|
|
97
97
|
path = ARGV[0] || Pathname(__dir__) + "light_up-1.txt"
|
98
|
-
LightUp.new(path).
|
98
|
+
LightUp.new(path).call
|
data/examples/minisudoku
CHANGED
@@ -13,7 +13,7 @@ class MiniSudokuSolver
|
|
13
13
|
@solver = Z3::Solver.new
|
14
14
|
end
|
15
15
|
|
16
|
-
def
|
16
|
+
def call
|
17
17
|
@cells = (0..5).map do |j|
|
18
18
|
(0..5).map do |i|
|
19
19
|
cell_var(@data[j][i], i, j)
|
@@ -58,4 +58,4 @@ class MiniSudokuSolver
|
|
58
58
|
end
|
59
59
|
|
60
60
|
path = ARGV[0] || Pathname(__dir__) + "minisudoku-1.txt"
|
61
|
-
MiniSudokuSolver.new(path).
|
61
|
+
MiniSudokuSolver.new(path).call
|