z3 0.0.20161117 → 0.0.20170204
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/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
|