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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 23036614e8d142331481794ca573d49be3d4c18f
4
- data.tar.gz: 1d765179f046c53ae950605fbf4d431d9bc3d7b6
3
+ metadata.gz: c6f02c4166af3fe459893d1ee5d19e181f5bce45
4
+ data.tar.gz: 62497676a02f20c92a53afe81abee249632d026e
5
5
  SHA512:
6
- metadata.gz: f49fb4df1ff7df3b283aa2f2eada3b263d13af54ddf0b9e7640d315efcae9fe5cdcaa00b5f4693e5ead379d9babf45923832c269de5dedef84b516a9c1245f78
7
- data.tar.gz: c936f488e71e3b8fe99f86ec8602bfde64848d1c008407a73316739dec194e0f99a0567487f3d6371ba775265431bfb44fa64ea52c1a7042941f4b5289a71fcb
6
+ metadata.gz: 9e48a27d5cf718468b6dc7030e212b7eaf8c141c40cc3456d89ee4f1cb8b37f3075e2505323a830cc9af40999f62b2a91389acf2a24aa6ac3516009310e523f9
7
+ data.tar.gz: b83dfe9c5600a816de119a7440f0e5bb1df3e048421504d9c4c61dc26c8b19a2f73ea32cc9ebff17b9f89fa6e9b063f24dc91f6ed9d695cd27651e1945974764
data/examples/crossflip CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require "z3"
3
+ require_relative "../lib/z3"
4
4
 
5
5
  class CrossFlipSolver
6
6
  def initialize(board)
data/examples/oneofus CHANGED
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require "z3"
4
- require "pry"
3
+ require_relative "../lib/z3"
5
4
 
6
5
  class OneofusSolver
7
6
  def initialize
@@ -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
- if @solver.satisfiable?
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
- else
73
- raise
74
- print "Crossword has no solution"
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
@@ -24,12 +24,11 @@ class RegexpSolver
24
24
  end
25
25
 
26
26
  def print_answer
27
- if @solver.satisfiable?
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
- else
31
- raise
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[2]
98
+ _, group, base = part
99
99
  if max == -1
100
- if min == 0 # (a)* -> |a*(a)
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)
@@ -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
- expect(float_double.from_const(1234 * 0.5**1040).to_s).to eq("1.205078125B-1030")
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
@@ -15,47 +15,49 @@ module Z3
15
15
  )
16
16
  end
17
17
 
18
- # FIXME: This is not even real spec at this point, just a no-crash-spec
19
- it "union" do
20
- expect([
21
- a.include?(1),
22
- a.include?(2),
23
- b.include?(2),
24
- b.include?(3),
25
- c == a.union(b),
26
- ]).to have_solution(
27
- a => "(declare-fun k! (Int) Bool)",
28
- b => "(declare-fun k! (Int) Bool)",
29
- c => "(declare-fun k! (Int) Bool)",
30
- )
31
- end
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
- it "difference" do
34
- expect([
35
- a.include?(1),
36
- a.include?(2),
37
- b.include?(2),
38
- b.include?(3),
39
- c == a.difference(b),
40
- ]).to have_solution(
41
- a => "(declare-fun k! (Int) Bool)",
42
- b => "(declare-fun k! (Int) Bool)",
43
- c => "(declare-fun k! (Int) Bool)",
44
- )
45
- end
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
- it "intersection" do
48
- expect([
49
- a.include?(1),
50
- a.include?(2),
51
- b.include?(2),
52
- b.include?(3),
53
- c == a.intersection(b),
54
- ]).to have_solution(
55
- a => "(declare-fun k! (Int) Bool)",
56
- b => "(declare-fun k! (Int) Bool)",
57
- c => "(declare-fun k! (Int) Bool)",
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 #{expected.inspect}, instead got #{solver.model}"
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.20161117
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: 2016-11-17 00:00:00.000000000 Z
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.1
266
+ rubygems_version: 2.5.2
265
267
  signing_key:
266
268
  specification_version: 4
267
269
  summary: Z3 Constraint Solver