z3 0.0.20161117 → 0.0.20170204
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/examples/crossflip +1 -1
- data/examples/oneofus +1 -2
- data/examples/pyramid_nonogram +166 -0
- data/examples/regexp_crossword_solver +4 -4
- data/examples/regexp_solver +3 -4
- data/examples/simple_regexp_parser.rb +8 -5
- data/spec/float_expr_spec.rb +6 -1
- data/spec/integration/pyramid_nonogram_spec.rb +18 -0
- data/spec/set_expr_spec.rb +41 -39
- data/spec/spec_helper.rb +5 -1
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c6f02c4166af3fe459893d1ee5d19e181f5bce45
|
4
|
+
data.tar.gz: 62497676a02f20c92a53afe81abee249632d026e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9e48a27d5cf718468b6dc7030e212b7eaf8c141c40cc3456d89ee4f1cb8b37f3075e2505323a830cc9af40999f62b2a91389acf2a24aa6ac3516009310e523f9
|
7
|
+
data.tar.gz: b83dfe9c5600a816de119a7440f0e5bb1df3e048421504d9c4c61dc26c8b19a2f73ea32cc9ebff17b9f89fa6e9b063f24dc91f6ed9d695cd27651e1945974764
|
data/examples/crossflip
CHANGED
data/examples/oneofus
CHANGED
@@ -0,0 +1,166 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require_relative "../lib/z3"
|
4
|
+
|
5
|
+
class PyramidNonogram
|
6
|
+
def initialize(size)
|
7
|
+
@size = size
|
8
|
+
@solver = Z3::Solver.new
|
9
|
+
@stripe_index = 0
|
10
|
+
end
|
11
|
+
|
12
|
+
def bottom_to_right(*args)
|
13
|
+
(0...@size).each do |i|
|
14
|
+
match! bottom_to_right_stripe(i), args[i]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def right_to_left(*args)
|
19
|
+
(0...@size).each do |i|
|
20
|
+
match! right_to_left_stripe(i), args[i]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def left_to_bottom(*args)
|
25
|
+
(0...@size).each do |i|
|
26
|
+
match! left_to_bottom_stripe(i), args[i]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def solve!
|
31
|
+
if @solver.satisfiable?
|
32
|
+
@model = @solver.model
|
33
|
+
print_answer!
|
34
|
+
else
|
35
|
+
puts "There is no solution"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def match!(cells, constraints)
|
42
|
+
@stripe_index += 1
|
43
|
+
prefix = "#{@stripe_index}"
|
44
|
+
group_vars = []
|
45
|
+
# Groups have size specified by constraints
|
46
|
+
# and start and end within specified cell range
|
47
|
+
(0...constraints.size).each do |i|
|
48
|
+
vs = Z3.Int("#{prefix},#{i+1},s")
|
49
|
+
ve = Z3.Int("#{prefix},#{i+1},e")
|
50
|
+
if constraints[i]
|
51
|
+
@solver.assert ve-vs == constraints[i]-1
|
52
|
+
end
|
53
|
+
@solver.assert vs >= 0
|
54
|
+
@solver.assert ve < cells.size
|
55
|
+
group_vars << [vs,ve]
|
56
|
+
end
|
57
|
+
|
58
|
+
# Gap between groups are at least one
|
59
|
+
(0...constraints.size-1).each do |i|
|
60
|
+
ve0 = group_vars[i][1]
|
61
|
+
vs1 = group_vars[i+1][0]
|
62
|
+
@solver.assert vs1 >= ve0+2
|
63
|
+
end
|
64
|
+
|
65
|
+
# Cell is on iff it belongs to a group
|
66
|
+
(0...cells.size).each do |i|
|
67
|
+
if constraints.empty?
|
68
|
+
rule_i = false
|
69
|
+
else
|
70
|
+
rule_i = Z3.Or(
|
71
|
+
*group_vars.map{|vs,ve| Z3.And(vs <= i, i <= ve) }
|
72
|
+
)
|
73
|
+
end
|
74
|
+
@solver.assert cells[i] == rule_i
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def right_to_left_stripe(y)
|
79
|
+
(-y..y).map{|x|
|
80
|
+
cell(x,y)
|
81
|
+
}.reverse
|
82
|
+
end
|
83
|
+
|
84
|
+
def bottom_to_right_stripe(i)
|
85
|
+
(0...@size).to_a.reverse.flat_map{|y|
|
86
|
+
[[-y+2*i, y], [-y+2*i+1, y]]
|
87
|
+
}.select{|x,y| (-y..y).include?(x) }.map{|x,y| cell(x,y) }
|
88
|
+
end
|
89
|
+
|
90
|
+
def left_to_bottom_stripe(i)
|
91
|
+
(0...@size).to_a.flat_map{|y|
|
92
|
+
[[y-2*i-1, y], [y-2*i, y]] }
|
93
|
+
.select{|x,y| (-y..y).include?(x) }.map{|x,y| cell(x,y) }
|
94
|
+
end
|
95
|
+
|
96
|
+
def cell(x,y)
|
97
|
+
Z3.Bool("c#{x},#{y}")
|
98
|
+
end
|
99
|
+
|
100
|
+
def print_answer!
|
101
|
+
(0...@size).each do |y|
|
102
|
+
(-@size..@size).each do |x|
|
103
|
+
if (-y..y).include?(x)
|
104
|
+
value = @model[cell(x,y)].to_b
|
105
|
+
if (x+y).odd?
|
106
|
+
cell = value ? "▼" : "▽"
|
107
|
+
else
|
108
|
+
cell = value ? "▲" : "△"
|
109
|
+
end
|
110
|
+
else
|
111
|
+
cell = " "
|
112
|
+
end
|
113
|
+
print cell
|
114
|
+
end
|
115
|
+
print "\n"
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# Example from:
|
121
|
+
# http://www.rankk.org/challenges/images/nonogrampyramid.png
|
122
|
+
_ = nil # nil means group of unknown size
|
123
|
+
pyramid_nonogram = PyramidNonogram.new(12)
|
124
|
+
pyramid_nonogram.bottom_to_right(
|
125
|
+
[2,1,1,5,3,2],
|
126
|
+
[1,2,1,1,1],
|
127
|
+
[3,1,1,3],
|
128
|
+
[1,1,1,2],
|
129
|
+
[3,2,2,3],
|
130
|
+
[2,1,1,1],
|
131
|
+
[2,2],
|
132
|
+
[1,3,1],
|
133
|
+
[2,3],
|
134
|
+
[1,1],
|
135
|
+
[1],
|
136
|
+
[1],
|
137
|
+
)
|
138
|
+
pyramid_nonogram.right_to_left(
|
139
|
+
[],
|
140
|
+
[1,1],
|
141
|
+
[1],
|
142
|
+
[1,1,2],
|
143
|
+
[1,2,2],
|
144
|
+
[2,3],
|
145
|
+
[1,1,2,2],
|
146
|
+
[4,2,1],
|
147
|
+
[1,2,2],
|
148
|
+
[3,1,1,2,3,1],
|
149
|
+
[1,3,1,2],
|
150
|
+
[2,3,1,4,1,2],
|
151
|
+
)
|
152
|
+
pyramid_nonogram.left_to_bottom(
|
153
|
+
[_,_,_,_,_,_,_],
|
154
|
+
[_,_,_,_,_],
|
155
|
+
[_,_,_,_,_],
|
156
|
+
[_,_,_,_,_,_],
|
157
|
+
[_,_,_],
|
158
|
+
[_,_,_,_],
|
159
|
+
[_,_,_],
|
160
|
+
[_,_],
|
161
|
+
[],
|
162
|
+
[_,_],
|
163
|
+
[_],
|
164
|
+
[_],
|
165
|
+
)
|
166
|
+
pyramid_nonogram.solve!
|
@@ -62,16 +62,16 @@ class RegexpCrosswordSolver
|
|
62
62
|
end
|
63
63
|
|
64
64
|
def print_answer
|
65
|
-
|
65
|
+
while @solver.satisfiable?
|
66
66
|
@model = @solver.model
|
67
67
|
@ysize.times do |y|
|
68
68
|
puts @xsize.times.map{|x|
|
69
69
|
@model[@crossword[[x,y]]].to_i.chr
|
70
70
|
}.join.inspect[1...-1]
|
71
71
|
end
|
72
|
-
|
73
|
-
|
74
|
-
|
72
|
+
break # If you want more solutions...
|
73
|
+
puts ""
|
74
|
+
@solver.assert Z3.Or(*@crossword.values.map{|v| @model[v] != v})
|
75
75
|
end
|
76
76
|
end
|
77
77
|
end
|
data/examples/regexp_solver
CHANGED
@@ -24,12 +24,11 @@ class RegexpSolver
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def print_answer
|
27
|
-
|
27
|
+
while @solver.satisfiable?
|
28
28
|
@model = @solver.model
|
29
29
|
puts @str.map{|c| @model[c].to_i.chr }.join.inspect[1...-1]
|
30
|
-
|
31
|
-
|
32
|
-
print "Crossword has no solution"
|
30
|
+
break # If you want more solutions...
|
31
|
+
@solver.assert Z3.Or(*@str.map{|v| @model[v] != v})
|
33
32
|
end
|
34
33
|
end
|
35
34
|
end
|
@@ -95,11 +95,13 @@ class SimpleRegexpParser
|
|
95
95
|
# Groups and qualifiers interact in weird ways, (a){3} is actually aa(a)
|
96
96
|
# We need to do extensive rewriting to make it work
|
97
97
|
def repeat_group(part, min, max)
|
98
|
-
base = part
|
98
|
+
_, group, base = part
|
99
99
|
if max == -1
|
100
|
-
|
100
|
+
# (a)* -> ()|a*(a)
|
101
|
+
# with same group id for both ()s
|
102
|
+
if min == 0
|
101
103
|
alternative(
|
102
|
-
empty,
|
104
|
+
[:group, group, empty],
|
103
105
|
sequence(repeat(base, min, max), part)
|
104
106
|
)
|
105
107
|
else # (a){2,} -> a{1,}(a)
|
@@ -109,9 +111,10 @@ class SimpleRegexpParser
|
|
109
111
|
:empty
|
110
112
|
else
|
111
113
|
if min == 0
|
112
|
-
# (a){2,3} -> |a{1,2}(a)
|
114
|
+
# (a){2,3} -> ()|a{1,2}(a)
|
115
|
+
# with same group id for both ()s
|
113
116
|
alternative(
|
114
|
-
empty,
|
117
|
+
[:group, group, empty],
|
115
118
|
sequence(repeat(base, min, max-1), part)
|
116
119
|
)
|
117
120
|
else # (a){2,3} -> a{1,2}(a)
|
data/spec/float_expr_spec.rb
CHANGED
@@ -101,7 +101,12 @@ module Z3
|
|
101
101
|
expect(positive_infinity.to_s).to eq("+oo")
|
102
102
|
expect(negative_infinity.to_s).to eq("-oo")
|
103
103
|
expect(nan.to_s).to eq("NaN")
|
104
|
-
|
104
|
+
# Denormals changed
|
105
|
+
if Z3.version >= '4.5'
|
106
|
+
expect(float_double.from_const(1234 * 0.5**1040).to_s).to eq("0.00470733642578125B-1022")
|
107
|
+
else
|
108
|
+
expect(float_double.from_const(1234 * 0.5**1040).to_s).to eq("1.205078125B-1030")
|
109
|
+
end
|
105
110
|
end
|
106
111
|
|
107
112
|
it "zero?" do
|
@@ -0,0 +1,18 @@
|
|
1
|
+
describe "Pyramid Nonogram" do
|
2
|
+
it do
|
3
|
+
expect("pyramid_nonogram").to have_output <<EOF
|
4
|
+
△
|
5
|
+
▲▽▲
|
6
|
+
△▼△▽△
|
7
|
+
▲▼△▽▲▽▲
|
8
|
+
△▼▲▽▲▼△▼△
|
9
|
+
▲▼▲▽△▽△▽▲▼△
|
10
|
+
▲▼△▽△▼▲▽△▼△▼△
|
11
|
+
△▼△▽△▽△▽▲▼△▼▲▼▲
|
12
|
+
△▼▲▽△▼▲▽▲▽△▽△▽△▽△
|
13
|
+
▲▽△▼▲▼△▽△▼▲▽▲▽▲▽▲▼▲
|
14
|
+
△▽△▽△▼▲▽▲▽△▽△▼▲▼△▼△▽△
|
15
|
+
▲▼△▼△▽△▽▲▼▲▼△▽▲▽▲▼▲▽△▼▲
|
16
|
+
EOF
|
17
|
+
end
|
18
|
+
end
|
data/spec/set_expr_spec.rb
CHANGED
@@ -15,47 +15,49 @@ module Z3
|
|
15
15
|
)
|
16
16
|
end
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
18
|
+
if Z3.version >= "4.5"
|
19
|
+
# Only works in z3 4.5, 4.4 (like on Ubuntu) returns bad stuff
|
20
|
+
it "union" do
|
21
|
+
expect([
|
22
|
+
a.include?(1),
|
23
|
+
a.include?(2),
|
24
|
+
b.include?(2),
|
25
|
+
b.include?(3),
|
26
|
+
c == a.union(b),
|
27
|
+
]).to have_solution(
|
28
|
+
a => "store(store(const(false), 1, true), 2, true)",
|
29
|
+
b => "store(store(const(false), 3, true), 2, true)",
|
30
|
+
c => "store(store(store(const(false), 1, true), 3, true), 2, true)",
|
31
|
+
)
|
32
|
+
end
|
32
33
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
34
|
+
it "difference" do
|
35
|
+
expect([
|
36
|
+
a.include?(1),
|
37
|
+
a.include?(2),
|
38
|
+
b.include?(2),
|
39
|
+
b.include?(3),
|
40
|
+
c == a.difference(b),
|
41
|
+
]).to have_solution(
|
42
|
+
a => "store(store(const(false), 1, true), 2, true)",
|
43
|
+
b => "store(const(true), 1, false)",
|
44
|
+
c => "store(const(false), 1, true)",
|
45
|
+
)
|
46
|
+
end
|
46
47
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
48
|
+
it "intersection" do
|
49
|
+
expect([
|
50
|
+
a.include?(1),
|
51
|
+
a.include?(2),
|
52
|
+
b.include?(2),
|
53
|
+
b.include?(3),
|
54
|
+
c == a.intersection(b),
|
55
|
+
]).to have_solution(
|
56
|
+
a => "store(store(const(false), 1, true), 2, true)",
|
57
|
+
b => "store(store(const(false), 3, true), 2, true)",
|
58
|
+
c => "store(store(store(const(false), 1, true), 3, true), 2, true)",
|
59
|
+
)
|
60
|
+
end
|
59
61
|
end
|
60
62
|
end
|
61
63
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -80,7 +80,11 @@ RSpec::Matchers.define :have_solution do |expected|
|
|
80
80
|
failure_message do |asts|
|
81
81
|
solver = setup_solver(asts)
|
82
82
|
if solver.satisfiable?
|
83
|
-
"expected #{asts.inspect} to have solution
|
83
|
+
"expected #{asts.inspect} to have solution:\n#{
|
84
|
+
expected.map{|var,val| "#{var}=#{val}\n"}.join
|
85
|
+
}instead got:\n#{
|
86
|
+
solver.model.map{|var,val| "#{var}=#{solver.model[var]}\n"}.join
|
87
|
+
}"
|
84
88
|
else
|
85
89
|
"expected #{asts.inspect} to have solution #{expected.inspect}, instead not solvable"
|
86
90
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: z3
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.20170204
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tomasz Wegrzanowski
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-02-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pry
|
@@ -128,6 +128,7 @@ files:
|
|
128
128
|
- examples/mortal_coil_puzzle-9.txt
|
129
129
|
- examples/nonogram
|
130
130
|
- examples/oneofus
|
131
|
+
- examples/pyramid_nonogram
|
131
132
|
- examples/regexp_crossword/beginner-1.txt
|
132
133
|
- examples/regexp_crossword/beginner-2.txt
|
133
134
|
- examples/regexp_crossword/beginner-3.txt
|
@@ -221,6 +222,7 @@ files:
|
|
221
222
|
- spec/integration/mortal_coil_puzzle_spec.rb
|
222
223
|
- spec/integration/nonogram_spec.rb
|
223
224
|
- spec/integration/oneofus_spec.rb
|
225
|
+
- spec/integration/pyramid_nonogram_spec.rb
|
224
226
|
- spec/integration/regexp_crossword_solver_spec.rb
|
225
227
|
- spec/integration/regexp_solver_spec.rb
|
226
228
|
- spec/integration/selfref_spec.rb
|
@@ -261,7 +263,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
261
263
|
requirements:
|
262
264
|
- z3 library
|
263
265
|
rubyforge_project:
|
264
|
-
rubygems_version: 2.5.
|
266
|
+
rubygems_version: 2.5.2
|
265
267
|
signing_key:
|
266
268
|
specification_version: 4
|
267
269
|
summary: Z3 Constraint Solver
|