z3 0.0.20171020 → 0.0.20180203
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +2 -0
- data/examples/zebra_puzzle +146 -0
- data/lib/z3/low_level_auto.rb +0 -36
- data/lib/z3/very_low_level_auto.rb +0 -9
- data/spec/expr_spec.rb +5 -3
- data/spec/integration/knights_puzzle_spec.rb +52 -50
- data/spec/integration/zebra_puzzle_spec.rb +11 -0
- data/spec/set_expr_spec.rb +2 -0
- data/spec/solver_spec.rb +20 -2
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 82ddc6984f24ee79d2dcd7fba162818c0bce9959f6f7c4daad11305b09ac84b8
|
4
|
+
data.tar.gz: 977d33cbd061672c85297e19dba7612c2f67bc0b5785ab1a67da828f17678b65
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 49db1f83e829f4b982abb5aea5014f9b64f6e558ee945a3d4d451227004fbd562cc5cddda955b3148582bedc73e2d8e251bf1198f87454145fe22e889bb9eaba
|
7
|
+
data.tar.gz: edcd476f98a22595b6a60a11606aec007b7852b7447904413c57388f3a8d6d06c5a058cc72d115f85ce61ebcb57d02c51c66535928b30a6f7de78f5a94ccc852
|
data/README.md
CHANGED
@@ -20,6 +20,8 @@ To use it, you'll need to install `z3`. On OSX that would be:
|
|
20
20
|
|
21
21
|
On other systems use appropriate package manager.
|
22
22
|
|
23
|
+
*NB: On Linux, since FFI will look for `libz3.so`, you might need to install `libz3-dev`using your usual package manager.*
|
24
|
+
|
23
25
|
### Known Issues
|
24
26
|
|
25
27
|
As Z3 is a C library, doing anything weird with it will segfault your process. Ruby API tries its best to prevent such problems and turn them into exceptions instead, but if you do anything weird (especially touch any method prefixed with `_` or `Z3::LowLevel` interface), crashes are possible. If you have reproducible crash on reasonable looking code, definitely submit it as a bug, and I'll try to come up with a workaround.
|
@@ -0,0 +1,146 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# https://en.wikipedia.org/wiki/Zebra_Puzzle
|
4
|
+
|
5
|
+
require_relative "../lib/z3"
|
6
|
+
|
7
|
+
class ZebraPuzzle
|
8
|
+
def initialize
|
9
|
+
@solver = Z3::Solver.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def traits
|
13
|
+
[:color, :nationality, :drink, :cigarettes, :pet]
|
14
|
+
end
|
15
|
+
|
16
|
+
def color
|
17
|
+
["red", "yellow", "green", "blue", "ivory"]
|
18
|
+
end
|
19
|
+
|
20
|
+
def nationality
|
21
|
+
["Englishman", "Spaniard", "Norwegian", "Ukrainian", "Japanese"]
|
22
|
+
end
|
23
|
+
|
24
|
+
def drink
|
25
|
+
["water", "coffee", "tea", "milk", "orange juice"]
|
26
|
+
end
|
27
|
+
|
28
|
+
def pet
|
29
|
+
["zebra", "dog", "snails", "fox", "horse"]
|
30
|
+
end
|
31
|
+
|
32
|
+
def cigarettes
|
33
|
+
["Parliaments", "Old Gold", "Lucky Strike", "Kools", "Chesterfields"]
|
34
|
+
end
|
35
|
+
|
36
|
+
def trait_index(trait, name)
|
37
|
+
send(trait).index(name) or raise "Bad value #{name.inspect} for trait #{trait.inspect}"
|
38
|
+
end
|
39
|
+
|
40
|
+
def trait_value(trait, index)
|
41
|
+
send(trait)[index] or raise "Bad index #{index.inspect} for trait #{trait.inspect}"
|
42
|
+
end
|
43
|
+
|
44
|
+
# House I has TRAIT value X
|
45
|
+
def variable(trait, i)
|
46
|
+
Z3.Int("#{trait}-#{i}")
|
47
|
+
end
|
48
|
+
|
49
|
+
def setup_variables(trait)
|
50
|
+
vars = (0..4).map{|i| variable(trait, i) }
|
51
|
+
@solver.assert Z3.Distinct(*vars)
|
52
|
+
vars.each do |v|
|
53
|
+
@solver.assert v >= 0
|
54
|
+
@solver.assert v <= 4
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
def house_has_trait_value(i, trait, value)
|
60
|
+
index = trait_index(trait, value)
|
61
|
+
(variable(trait, i) == index)
|
62
|
+
end
|
63
|
+
|
64
|
+
def same_house(t1,v1,t2,v2)
|
65
|
+
(0..4).each do |i|
|
66
|
+
@solver.assert house_has_trait_value(i,t1,v1) == house_has_trait_value(i,t2,v2)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def left_rigth_house(t1,v1,t2,v2)
|
71
|
+
(0..3).each do |i|
|
72
|
+
@solver.assert house_has_trait_value(i,t1,v1) == house_has_trait_value(i+1,t2,v2)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def next_house(t1,v1,t2,v2)
|
77
|
+
(0..4).each do |i|
|
78
|
+
opts = [i+1,i-1].grep(0..4).map{|j| house_has_trait_value(i,t1,v1) == house_has_trait_value(j,t2,v2) }
|
79
|
+
@solver.assert Z3.Or(*opts)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def call
|
84
|
+
traits.each do |trait|
|
85
|
+
setup_variables(trait)
|
86
|
+
end
|
87
|
+
|
88
|
+
same_house(:nationality, "Englishman", :color, "red")
|
89
|
+
same_house(:nationality, "Spaniard", :pet, "dog")
|
90
|
+
same_house(:drink, "coffee", :color, "green")
|
91
|
+
same_house(:nationality, "Ukrainian", :drink, "tea")
|
92
|
+
same_house(:pet, "snails", :cigarettes, "Old Gold")
|
93
|
+
same_house(:cigarettes, "Kools", :color, "yellow")
|
94
|
+
same_house(:cigarettes, "Lucky Strike", :drink, "orange juice")
|
95
|
+
same_house(:nationality, "Japanese", :cigarettes, "Parliaments")
|
96
|
+
|
97
|
+
next_house(:nationality, "Norwegian", :color, "blue")
|
98
|
+
next_house(:cigarettes, "Chesterfields", :pet, "fox")
|
99
|
+
next_house(:cigarettes, "Kools", :pet, "horse")
|
100
|
+
|
101
|
+
left_rigth_house(:color, "ivory", :color, "green")
|
102
|
+
|
103
|
+
@solver.assert house_has_trait_value(2, :drink, "milk")
|
104
|
+
@solver.assert house_has_trait_value(0, :nationality, "Norwegian")
|
105
|
+
|
106
|
+
if @solver.satisfiable?
|
107
|
+
print_solution
|
108
|
+
else
|
109
|
+
puts "No solution"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def print_solution
|
114
|
+
model = @solver.model
|
115
|
+
(0..4).each do |i|
|
116
|
+
print "House #{i}:"
|
117
|
+
traits.each do |trait|
|
118
|
+
j = model[variable(trait, i)].to_s.to_i
|
119
|
+
t = trait_value(trait, j)
|
120
|
+
print " #{t}"
|
121
|
+
end
|
122
|
+
print "\n"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
ZebraPuzzle.new.call
|
128
|
+
|
129
|
+
__END__
|
130
|
+
|
131
|
+
There are five houses.
|
132
|
+
The Englishman lives in the red house.
|
133
|
+
The Spaniard owns the dog.
|
134
|
+
Coffee is drunk in the green house.
|
135
|
+
The Ukrainian drinks tea.
|
136
|
+
The green house is immediately to the right of the ivory house.
|
137
|
+
The Old Gold smoker owns snails.
|
138
|
+
Kools are smoked in the yellow house.
|
139
|
+
Milk is drunk in the middle house.
|
140
|
+
The Norwegian lives in the first house.
|
141
|
+
The man who smokes Chesterfields lives in the house next to the man with the fox.
|
142
|
+
Kools are smoked in the house next to the house where the horse is kept.
|
143
|
+
The Lucky Strike smoker drinks orange juice.
|
144
|
+
The Japanese smokes Parliaments.
|
145
|
+
The Norwegian lives next to the blue house.
|
146
|
+
Now, who drinks water? Who owns the zebra?
|
data/lib/z3/low_level_auto.rb
CHANGED
@@ -581,42 +581,6 @@ module Z3
|
|
581
581
|
VeryLowLevel.Z3_get_relation_column(_ctx_pointer, sort._ast, num)
|
582
582
|
end
|
583
583
|
|
584
|
-
def get_smtlib_assumption(num) #=> :ast_pointer
|
585
|
-
VeryLowLevel.Z3_get_smtlib_assumption(_ctx_pointer, num)
|
586
|
-
end
|
587
|
-
|
588
|
-
def get_smtlib_decl(num) #=> :func_decl_pointer
|
589
|
-
VeryLowLevel.Z3_get_smtlib_decl(_ctx_pointer, num)
|
590
|
-
end
|
591
|
-
|
592
|
-
def get_smtlib_error #=> :string
|
593
|
-
VeryLowLevel.Z3_get_smtlib_error(_ctx_pointer)
|
594
|
-
end
|
595
|
-
|
596
|
-
def get_smtlib_formula(num) #=> :ast_pointer
|
597
|
-
VeryLowLevel.Z3_get_smtlib_formula(_ctx_pointer, num)
|
598
|
-
end
|
599
|
-
|
600
|
-
def get_smtlib_num_assumptions #=> :uint
|
601
|
-
VeryLowLevel.Z3_get_smtlib_num_assumptions(_ctx_pointer)
|
602
|
-
end
|
603
|
-
|
604
|
-
def get_smtlib_num_decls #=> :uint
|
605
|
-
VeryLowLevel.Z3_get_smtlib_num_decls(_ctx_pointer)
|
606
|
-
end
|
607
|
-
|
608
|
-
def get_smtlib_num_formulas #=> :uint
|
609
|
-
VeryLowLevel.Z3_get_smtlib_num_formulas(_ctx_pointer)
|
610
|
-
end
|
611
|
-
|
612
|
-
def get_smtlib_num_sorts #=> :uint
|
613
|
-
VeryLowLevel.Z3_get_smtlib_num_sorts(_ctx_pointer)
|
614
|
-
end
|
615
|
-
|
616
|
-
def get_smtlib_sort(num) #=> :sort_pointer
|
617
|
-
VeryLowLevel.Z3_get_smtlib_sort(_ctx_pointer, num)
|
618
|
-
end
|
619
|
-
|
620
584
|
def get_sort(ast) #=> :sort_pointer
|
621
585
|
VeryLowLevel.Z3_get_sort(_ctx_pointer, ast._ast)
|
622
586
|
end
|
@@ -145,15 +145,6 @@ module Z3
|
|
145
145
|
attach_function :Z3_get_range, [:ctx_pointer, :func_decl_pointer], :sort_pointer
|
146
146
|
attach_function :Z3_get_relation_arity, [:ctx_pointer, :sort_pointer], :uint
|
147
147
|
attach_function :Z3_get_relation_column, [:ctx_pointer, :sort_pointer, :uint], :sort_pointer
|
148
|
-
attach_function :Z3_get_smtlib_assumption, [:ctx_pointer, :uint], :ast_pointer
|
149
|
-
attach_function :Z3_get_smtlib_decl, [:ctx_pointer, :uint], :func_decl_pointer
|
150
|
-
attach_function :Z3_get_smtlib_error, [:ctx_pointer], :string
|
151
|
-
attach_function :Z3_get_smtlib_formula, [:ctx_pointer, :uint], :ast_pointer
|
152
|
-
attach_function :Z3_get_smtlib_num_assumptions, [:ctx_pointer], :uint
|
153
|
-
attach_function :Z3_get_smtlib_num_decls, [:ctx_pointer], :uint
|
154
|
-
attach_function :Z3_get_smtlib_num_formulas, [:ctx_pointer], :uint
|
155
|
-
attach_function :Z3_get_smtlib_num_sorts, [:ctx_pointer], :uint
|
156
|
-
attach_function :Z3_get_smtlib_sort, [:ctx_pointer, :uint], :sort_pointer
|
157
148
|
attach_function :Z3_get_sort, [:ctx_pointer, :ast_pointer], :sort_pointer
|
158
149
|
attach_function :Z3_get_sort_id, [:ctx_pointer, :sort_pointer], :uint
|
159
150
|
attach_function :Z3_get_sort_kind, [:ctx_pointer, :sort_pointer], :uint
|
data/spec/expr_spec.rb
CHANGED
@@ -113,15 +113,16 @@ module Z3
|
|
113
113
|
|
114
114
|
it "casts to correct type if possible" do
|
115
115
|
expect((a == 42).sexpr).to eq "(= a 42)"
|
116
|
-
|
116
|
+
# https://bugs.ruby-lang.org/issues/14437
|
117
|
+
#expect((42 == a).sexpr).to eq "(= a 42)"
|
117
118
|
expect((a == e).sexpr).to eq "(= (to_real a) e)"
|
118
119
|
expect((e == a).sexpr).to eq "(= e (to_real a))"
|
119
120
|
expect((c == true).sexpr).to eq "(= c true)"
|
120
121
|
expect((c == false).sexpr).to eq "(= c false)"
|
121
122
|
expect((a == 42.5).sexpr).to eq "(= (to_real a) (/ 85.0 2.0))"
|
122
|
-
expect((42.5 == a).sexpr).to eq "(= (to_real a) (/ 85.0 2.0))"
|
123
|
+
# expect((42.5 == a).sexpr).to eq "(= (to_real a) (/ 85.0 2.0))"
|
123
124
|
expect((e == 42.5).sexpr).to eq "(= e (/ 85.0 2.0))"
|
124
|
-
expect((42.5 == e).sexpr).to eq "(= e (/ 85.0 2.0))"
|
125
|
+
# expect((42.5 == e).sexpr).to eq "(= e (/ 85.0 2.0))"
|
125
126
|
# expect((true == c).sexpr).to eq "(= true c)"
|
126
127
|
# expect((false == c).sexpr).to eq "(= false c)"
|
127
128
|
end
|
@@ -149,6 +150,7 @@ module Z3
|
|
149
150
|
|
150
151
|
it "casts to correct type if possible" do
|
151
152
|
expect((a != 42).sexpr).to eq "(distinct a 42)"
|
153
|
+
# https://bugs.ruby-lang.org/issues/14437
|
152
154
|
# expect((42 != a).sexpr).to eq "(distinct a 42)"
|
153
155
|
expect((a != e).sexpr).to eq "(distinct (to_real a) e)"
|
154
156
|
expect((e != a).sexpr).to eq "(distinct e (to_real a))"
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# There are multiple solutions, so this test is nondeterministic
|
2
|
+
# Changing it to one returned by z3 4.6.0, but perhaps it needs some serious fixing
|
1
3
|
describe "Knights Swap Puzzle" do
|
2
4
|
it do
|
3
5
|
expect("knights_puzzle").to have_output <<EOF
|
@@ -7,84 +9,84 @@ bbb.
|
|
7
9
|
xbxw
|
8
10
|
..ww
|
9
11
|
x.xw
|
10
|
-
b:
|
12
|
+
b: 0,0 -> 1,2
|
11
13
|
|
12
14
|
State 1:
|
13
|
-
|
14
|
-
|
15
|
-
|
15
|
+
.bb.
|
16
|
+
xbxw
|
17
|
+
.bww
|
16
18
|
x.xw
|
17
|
-
w:
|
19
|
+
w: 2,2 -> 3,0
|
18
20
|
|
19
21
|
State 2:
|
20
|
-
|
21
|
-
|
22
|
-
|
22
|
+
.bbw
|
23
|
+
xbxw
|
24
|
+
.b.w
|
23
25
|
x.xw
|
24
|
-
b:
|
26
|
+
b: 1,0 -> 2,2
|
25
27
|
|
26
28
|
State 3:
|
27
|
-
|
28
|
-
|
29
|
-
|
29
|
+
..bw
|
30
|
+
xbxw
|
31
|
+
.bbw
|
30
32
|
x.xw
|
31
|
-
w: 3,
|
33
|
+
w: 3,1 -> 1,0
|
32
34
|
|
33
35
|
State 4:
|
34
|
-
|
35
|
-
|
36
|
-
.
|
37
|
-
x.
|
38
|
-
|
36
|
+
.wbw
|
37
|
+
xbx.
|
38
|
+
.bbw
|
39
|
+
x.xw
|
40
|
+
b: 1,2 -> 3,1
|
39
41
|
|
40
42
|
State 5:
|
41
|
-
|
42
|
-
|
43
|
-
..
|
44
|
-
x.
|
45
|
-
|
43
|
+
.wbw
|
44
|
+
xbxb
|
45
|
+
..bw
|
46
|
+
x.xw
|
47
|
+
w: 3,3 -> 1,2
|
46
48
|
|
47
49
|
State 6:
|
48
|
-
.
|
49
|
-
|
50
|
-
.
|
50
|
+
.wbw
|
51
|
+
xbxb
|
52
|
+
.wbw
|
51
53
|
x.x.
|
52
|
-
|
54
|
+
w: 1,2 -> 0,0
|
53
55
|
|
54
56
|
State 7:
|
55
|
-
|
56
|
-
|
57
|
-
..
|
58
|
-
x.
|
59
|
-
|
57
|
+
wwbw
|
58
|
+
xbxb
|
59
|
+
..bw
|
60
|
+
x.x.
|
61
|
+
b: 2,0 -> 1,2
|
60
62
|
|
61
63
|
State 8:
|
62
|
-
.
|
63
|
-
|
64
|
-
.
|
65
|
-
x.
|
66
|
-
|
64
|
+
ww.w
|
65
|
+
xbxb
|
66
|
+
.bbw
|
67
|
+
x.x.
|
68
|
+
w: 3,2 -> 2,0
|
67
69
|
|
68
70
|
State 9:
|
69
|
-
|
70
|
-
|
71
|
-
.
|
72
|
-
x.
|
73
|
-
|
71
|
+
wwww
|
72
|
+
xbxb
|
73
|
+
.bb.
|
74
|
+
x.x.
|
75
|
+
b: 1,1 -> 3,2
|
74
76
|
|
75
77
|
State 10:
|
76
|
-
|
77
|
-
xwxb
|
78
|
-
.w.b
|
78
|
+
wwww
|
79
79
|
x.xb
|
80
|
-
|
80
|
+
.bbb
|
81
|
+
x.x.
|
82
|
+
b: 1,2 -> 3,3
|
81
83
|
|
82
84
|
State 11:
|
83
|
-
|
84
|
-
xwxb
|
85
|
-
.wbb
|
85
|
+
wwww
|
86
86
|
x.xb
|
87
|
-
|
87
|
+
..bb
|
88
|
+
x.xb
|
89
|
+
w: 3,0 -> 1,1
|
88
90
|
|
89
91
|
State 12:
|
90
92
|
www.
|
@@ -0,0 +1,11 @@
|
|
1
|
+
describe "Zebra Puzzle" do
|
2
|
+
it do
|
3
|
+
expect("zebra_puzzle").to have_output <<EOF
|
4
|
+
House 0: yellow Norwegian water Kools fox
|
5
|
+
House 1: blue Ukrainian tea Chesterfields horse
|
6
|
+
House 2: red Englishman milk Old Gold snails
|
7
|
+
House 3: ivory Spaniard orange juice Lucky Strike dog
|
8
|
+
House 4: green Japanese coffee Parliaments zebra
|
9
|
+
EOF
|
10
|
+
end
|
11
|
+
end
|
data/spec/set_expr_spec.rb
CHANGED
data/spec/solver_spec.rb
CHANGED
@@ -37,13 +37,31 @@ module Z3
|
|
37
37
|
solver.assert b >= 2
|
38
38
|
solver.assert Z3.Or(a == 2, a == -2)
|
39
39
|
stats = solver.statistics
|
40
|
-
|
40
|
+
# "mk bool var" added in 4.6.0
|
41
|
+
expect(stats.keys).to match_array(["rlimit count", "max memory", "memory", "num allocs", "mk bool var"])
|
41
42
|
end
|
42
43
|
|
43
44
|
# This is a very simple example of unknown satisfiablity
|
44
45
|
# so we might need more complex one in the future
|
46
|
+
# This is now satisfiable in 4.6.0
|
47
|
+
if Z3.version >= "4.6"
|
48
|
+
it "third way (until 4.6 fix)" do
|
49
|
+
solver.assert a**3 == a
|
50
|
+
expect(solver.check).to eq(:sat)
|
51
|
+
expect(solver).to be_satisfiable
|
52
|
+
expect(solver).to_not be_unsatisfiable
|
53
|
+
end
|
54
|
+
else
|
55
|
+
it "third way (until 4.6 fix)" do
|
56
|
+
solver.assert a**3 == a
|
57
|
+
expect(solver.check).to eq(:unknown)
|
58
|
+
expect{solver.satisfiable?}.to raise_error("Satisfiability unknown")
|
59
|
+
expect{solver.unsatisfiable?}.to raise_error("Satisfiability unknown")
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
45
63
|
it "third way" do
|
46
|
-
solver.assert a**
|
64
|
+
solver.assert a**a == a
|
47
65
|
expect(solver.check).to eq(:unknown)
|
48
66
|
expect{solver.satisfiable?}.to raise_error("Satisfiability unknown")
|
49
67
|
expect{solver.unsatisfiable?}.to raise_error("Satisfiability unknown")
|
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.20180203
|
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: 2018-02-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pry
|
@@ -156,6 +156,7 @@ files:
|
|
156
156
|
- examples/sudoku
|
157
157
|
- examples/sudoku-1.txt
|
158
158
|
- examples/verbal_arithmetic
|
159
|
+
- examples/zebra_puzzle
|
159
160
|
- lib/z3.rb
|
160
161
|
- lib/z3/ast.rb
|
161
162
|
- lib/z3/context.rb
|
@@ -228,6 +229,7 @@ files:
|
|
228
229
|
- spec/integration/selfref_spec.rb
|
229
230
|
- spec/integration/sudoku_spec.rb
|
230
231
|
- spec/integration/verbal_arithmetic_spec.rb
|
232
|
+
- spec/integration/zebra_puzzle_spec.rb
|
231
233
|
- spec/model_spec.rb
|
232
234
|
- spec/printer_spec.rb
|
233
235
|
- spec/probe_spec.rb
|
@@ -263,7 +265,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
263
265
|
requirements:
|
264
266
|
- z3 library
|
265
267
|
rubyforge_project:
|
266
|
-
rubygems_version: 2.
|
268
|
+
rubygems_version: 2.7.3
|
267
269
|
signing_key:
|
268
270
|
specification_version: 4
|
269
271
|
summary: Z3 Constraint Solver
|