z3 0.0.20251017 → 0.0.20260727
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 +45 -5
- data/Rakefile +11 -0
- data/examples/aquarium +2 -4
- data/examples/color_nonogram +1 -2
- data/examples/dominosa +2 -2
- data/examples/kakurasu +7 -6
- data/examples/kakurasu-2.txt +2 -0
- data/examples/light_up +35 -31
- data/examples/light_up-2.txt +2 -0
- data/examples/nanro +1 -4
- data/examples/regexp_string_matcher.rb +1 -1
- data/examples/simple_regexp_parser.rb +1 -1
- data/examples/star_battle +3 -6
- data/examples/stitches +5 -5
- data/examples/yajilin +3 -5
- data/lib/z3/expr/bitvec_expr.rb +9 -8
- data/lib/z3/expr/bool_expr.rb +26 -0
- data/lib/z3/expr/expr.rb +6 -1
- data/lib/z3/expr/set_expr.rb +1 -1
- data/lib/z3/func_decl.rb +29 -4
- data/lib/z3/goal.rb +7 -0
- data/lib/z3/interface.rb +20 -1
- data/lib/z3/low_level.rb +32 -3
- data/lib/z3/low_level_auto.rb +20 -8
- data/lib/z3/model.rb +7 -3
- data/lib/z3/optimize.rb +45 -2
- data/lib/z3/param_descrs.rb +55 -0
- data/lib/z3/params.rb +99 -0
- data/lib/z3/printer.rb +17 -3
- data/lib/z3/probe.rb +20 -3
- data/lib/z3/reference_counted.rb +23 -0
- data/lib/z3/solver.rb +56 -2
- data/lib/z3/sort/float_sort.rb +15 -7
- data/lib/z3/sort/set_sort.rb +2 -2
- data/lib/z3/sort/sort.rb +5 -2
- data/lib/z3/tactic.rb +9 -1
- data/lib/z3/very_low_level.rb +3 -0
- data/lib/z3/very_low_level_auto.rb +5 -2
- data/lib/z3.rb +3 -0
- data/spec/array_expr_spec.rb +7 -16
- data/spec/bitvec_expr_spec.rb +32 -3
- data/spec/bool_expr_spec.rb +27 -0
- data/spec/expr_spec.rb +7 -0
- data/spec/float_expr_spec.rb +15 -9
- data/spec/float_sort_spec.rb +75 -0
- data/spec/goal_spec.rb +16 -0
- data/spec/integration/examples/knights_puzzle-10.txt +90 -0
- data/spec/integration/examples/knights_puzzle-9.txt +90 -0
- data/spec/integration/kakurasu_spec.rb +15 -0
- data/spec/integration/light_up_spec.rb +8 -0
- data/spec/integration/regexp_solver_spec.rb +6 -0
- data/spec/model_spec.rb +56 -0
- data/spec/optimize_spec.rb +72 -0
- data/spec/param_descrs_spec.rb +50 -0
- data/spec/params_spec.rb +85 -0
- data/spec/printer_spec.rb +35 -0
- data/spec/probe_spec.rb +26 -0
- data/spec/reference_counted_spec.rb +91 -0
- data/spec/set_expr_spec.rb +4 -3
- data/spec/set_sort_spec.rb +15 -0
- data/spec/solver_spec.rb +130 -7
- data/spec/sort_spec.rb +50 -0
- data/spec/tactic_spec.rb +34 -0
- metadata +28 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2722943f324098ac25b10410d1b4d8b24afab4681ee8b28772824f25daf83ad9
|
|
4
|
+
data.tar.gz: b6e1b3225862edce94fe37751739467db74e6ebbd432e122f53aa00afff1e0b1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 35a9657f906d701f0b433cf209e90280a05f65f7df10c748febcf8f6deeb3cae180fb002572461bce9db63b1c6aedc0ee31e2474c7460f1a3611731121a508fd
|
|
7
|
+
data.tar.gz: 72343dc4e5bca1b0dd33a0f483a92552390b07ea004759dbbaac413fa2195b5287f047ed701e5ab4bbdf3c368bba66901d064d03231399e1b9f154a3ac3679e3
|
data/README.md
CHANGED
|
@@ -1,12 +1,52 @@
|
|
|
1
|
-
|
|
1
|
+
# Ruby bindings for Z3
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
This is a Ruby interface for [Z3](https://github.com/Z3Prover/z3).
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Recommended [Z3](https://github.com/Z3Prover/z3) version is 4.16 or newer. Make sure you have it first (e.g. `brew install z3` on MacOS).
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
```sh
|
|
8
|
+
gem install z3
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
[API documentation is here](https://taw.github.io/z3/).
|
|
12
|
+
|
|
13
|
+
## Basic usage
|
|
14
|
+
|
|
15
|
+
Variables are initialized with `Z3.Bool`, `Z3.Int`, `Z3.Real`, `Z3.Bitvec`.
|
|
16
|
+
|
|
17
|
+
Constrain and solve with `Z3::Solver` and `Z3::Optimize`.
|
|
18
|
+
|
|
19
|
+
```ruby
|
|
20
|
+
require 'z3'
|
|
21
|
+
|
|
22
|
+
# make z3 variables
|
|
23
|
+
a, b = Z3.Int('a'), Z3.Int('b')
|
|
24
|
+
|
|
25
|
+
# add constraints with expressions
|
|
26
|
+
solver = Z3::Solver.new
|
|
27
|
+
solver.assert(a > 1)
|
|
28
|
+
solver.assert(b > 0)
|
|
29
|
+
solver.assert(a + b == 3)
|
|
30
|
+
|
|
31
|
+
# check sat, find model
|
|
32
|
+
if solver.satisfiable?
|
|
33
|
+
model = solver.model
|
|
34
|
+
|
|
35
|
+
# convert z3 model to ruby types
|
|
36
|
+
hash = model.to_h do |zvar, zvalue|
|
|
37
|
+
[zvar.to_s, zvalue.to_i]
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
p hash
|
|
41
|
+
# {"a" => 2, "b" => 1}
|
|
42
|
+
end
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Interface
|
|
46
|
+
|
|
47
|
+
The public interface is various methods in `Z3` module, and on objects created by it.
|
|
8
48
|
|
|
9
|
-
The
|
|
49
|
+
The [`examples/`](https://github.com/taw/z3/blob/master/examples) directory is probably the best place to start.
|
|
10
50
|
|
|
11
51
|
You can use most Ruby operators to construct Z3 expressions, but use `| &` instead of `|| &&` for boolean operators. They unfortunately have wrong operator precedence so you'll need to use some extra parentheses.
|
|
12
52
|
|
data/Rakefile
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require "json"
|
|
2
|
+
require "rdoc/task"
|
|
2
3
|
|
|
3
4
|
task "default" => "spec"
|
|
4
5
|
task "test" => "spec"
|
|
@@ -61,3 +62,13 @@ task "coverage:missing" do
|
|
|
61
62
|
file.puts missing
|
|
62
63
|
end
|
|
63
64
|
end
|
|
65
|
+
|
|
66
|
+
RDoc::Task.new do |rdoc|
|
|
67
|
+
rdoc.main = "README.md"
|
|
68
|
+
rdoc.rdoc_dir = "docs"
|
|
69
|
+
rdoc.rdoc_files.include("README.md", "lib/**/*.rb")
|
|
70
|
+
rdoc.rdoc_files.exclude("lib/z3/hacks.rb")
|
|
71
|
+
rdoc.rdoc_files.exclude("lib/z3/low_level.rb")
|
|
72
|
+
rdoc.rdoc_files.exclude("lib/z3/very_low_level.rb")
|
|
73
|
+
rdoc.rdoc_files.exclude("lib/z3/very_low_level_auto.rb")
|
|
74
|
+
end
|
data/examples/aquarium
CHANGED
|
@@ -25,14 +25,12 @@ class Aquarium
|
|
|
25
25
|
|
|
26
26
|
# Row sums
|
|
27
27
|
@ysize.times do |y|
|
|
28
|
-
|
|
29
|
-
@solver.assert sum == @rows[y]
|
|
28
|
+
@solver.assert Z3.Exactly(@xsize.times.map{|x| cell_var(x, y) }, @rows[y])
|
|
30
29
|
end
|
|
31
30
|
|
|
32
31
|
# Col sums
|
|
33
32
|
@xsize.times do |x|
|
|
34
|
-
|
|
35
|
-
@solver.assert sum == @cols[x]
|
|
33
|
+
@solver.assert Z3.Exactly(@ysize.times.map{|y| cell_var(x, y) }, @cols[x])
|
|
36
34
|
end
|
|
37
35
|
|
|
38
36
|
# Container water flow
|
data/examples/color_nonogram
CHANGED
|
@@ -58,8 +58,7 @@ class ColorNonogram
|
|
|
58
58
|
def constraint_line(color_constraints, line_vars)
|
|
59
59
|
color_constraints.each_with_index do |(expected_total, expected_continuity), color_index|
|
|
60
60
|
correct_color = line_vars.map{|vi| (vi == color_index) }
|
|
61
|
-
|
|
62
|
-
@solver.assert total == expected_total
|
|
61
|
+
@solver.assert Z3.Exactly(correct_color, expected_total)
|
|
63
62
|
# For 0 / 1 this is all
|
|
64
63
|
if expected_total >= 2
|
|
65
64
|
continuity = continuity_somewhere(correct_color, expected_total)
|
data/examples/dominosa
CHANGED
|
@@ -73,7 +73,7 @@ class Dominosa
|
|
|
73
73
|
end
|
|
74
74
|
|
|
75
75
|
all.each do |_, vars|
|
|
76
|
-
@solver.assert Z3.
|
|
76
|
+
@solver.assert Z3.Exactly(vars, 1)
|
|
77
77
|
end
|
|
78
78
|
end
|
|
79
79
|
|
|
@@ -86,7 +86,7 @@ class Dominosa
|
|
|
86
86
|
left_var(x,y),
|
|
87
87
|
up_var(x,y),
|
|
88
88
|
].compact
|
|
89
|
-
@solver.assert Z3.
|
|
89
|
+
@solver.assert Z3.Exactly(vars, 1)
|
|
90
90
|
end
|
|
91
91
|
end
|
|
92
92
|
end
|
data/examples/kakurasu
CHANGED
|
@@ -21,7 +21,7 @@ class Kakurasu
|
|
|
21
21
|
@cvars = {}
|
|
22
22
|
@rvars = {}
|
|
23
23
|
@ysize.times do |y|
|
|
24
|
-
@
|
|
24
|
+
@xsize.times do |x|
|
|
25
25
|
b = Z3.Bool("b#{x},#{y}")
|
|
26
26
|
r = Z3.Int("r#{x},#{y}")
|
|
27
27
|
c = Z3.Int("c#{x},#{y}")
|
|
@@ -37,12 +37,13 @@ class Kakurasu
|
|
|
37
37
|
end
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
# Row sums weight cells by their column index, column sums by their row index
|
|
41
|
+
@ysize.times do |y|
|
|
42
|
+
@solver.assert Z3.Add(*@rvars[y]) == @row_sums[y]
|
|
42
43
|
end
|
|
43
44
|
|
|
44
|
-
@
|
|
45
|
-
@solver.assert Z3.Add(*@cvars[
|
|
45
|
+
@xsize.times do |x|
|
|
46
|
+
@solver.assert Z3.Add(*@cvars[x]) == @col_sums[x]
|
|
46
47
|
end
|
|
47
48
|
|
|
48
49
|
if @solver.satisfiable?
|
|
@@ -57,7 +58,7 @@ class Kakurasu
|
|
|
57
58
|
|
|
58
59
|
def print_board!
|
|
59
60
|
@ysize.times do |y|
|
|
60
|
-
@
|
|
61
|
+
@xsize.times do |x|
|
|
61
62
|
if @model[@bvars[[x,y]]].to_b
|
|
62
63
|
print "[X]"
|
|
63
64
|
else
|
data/examples/light_up
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require "pathname"
|
|
4
4
|
require_relative "../lib/z3"
|
|
5
5
|
|
|
6
|
+
# Also known as Akari
|
|
6
7
|
class LightUp
|
|
7
8
|
def initialize(path)
|
|
8
9
|
data = Pathname(path).read
|
|
@@ -14,29 +15,23 @@ class LightUp
|
|
|
14
15
|
end
|
|
15
16
|
|
|
16
17
|
def call
|
|
17
|
-
@lamps = map_coordinates{|x,y|
|
|
18
|
+
@lamps = map_coordinates{|x,y| Z3.Bool("l#{x},#{y}") }
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
end
|
|
20
|
+
each_cell do |x, y|
|
|
21
|
+
v = @data[[x,y]]
|
|
22
|
+
if v == "."
|
|
23
|
+
# Every white cell must be lit: at least one lamp in its line of sight
|
|
24
|
+
@solver.assert Z3.AtLeast(line_of_sight(x, y), 1)
|
|
25
|
+
else
|
|
26
|
+
# No lamps on walls; numbers count lamps next to node (diagonals don't count)
|
|
27
|
+
@solver.assert ~@lamps[[x,y]]
|
|
28
|
+
@solver.assert Z3.Exactly(lamps_next_to_cell(x, y), v.to_i) if ("0".."4").include?(v)
|
|
29
29
|
end
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
-
#
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
(0...@xsize).each do |x|
|
|
36
|
-
raycast = Z3.Add(*raycast_cells(x,y))
|
|
37
|
-
@solver.assert Z3.Implies(@lamps[[x,y]] == 0, raycast >= 1)
|
|
38
|
-
@solver.assert Z3.Implies(@lamps[[x,y]] == 1, raycast == 0)
|
|
39
|
-
end
|
|
32
|
+
# No lamp is in raycast of another: at most one lamp per maximal white run
|
|
33
|
+
(white_runs(:horizontal) + white_runs(:vertical)).each do |run|
|
|
34
|
+
@solver.assert Z3.AtMost(run.map{|xy| @lamps[xy]}, 1)
|
|
40
35
|
end
|
|
41
36
|
|
|
42
37
|
if @solver.satisfiable?
|
|
@@ -53,11 +48,11 @@ class LightUp
|
|
|
53
48
|
[[x0-1,y0],[x0+1,y0],[x0,y0-1],[x0,y0+1]].map{|x,y| @lamps[[x,y]]}.compact
|
|
54
49
|
end
|
|
55
50
|
|
|
56
|
-
|
|
57
|
-
|
|
51
|
+
# The white cell itself plus every white cell visible from it in a straight line
|
|
52
|
+
def line_of_sight(x0,y0)
|
|
53
|
+
result = [@lamps[[x0,y0]]]
|
|
58
54
|
[[1,0],[-1,0],[0,1],[0,-1]].each do |dx,dy|
|
|
59
|
-
x = x0+dx
|
|
60
|
-
y = y0+dy
|
|
55
|
+
x, y = x0+dx, y0+dy
|
|
61
56
|
while @data[[x,y]] == "."
|
|
62
57
|
result << @lamps[[x,y]]
|
|
63
58
|
x += dx
|
|
@@ -67,6 +62,22 @@ class LightUp
|
|
|
67
62
|
result
|
|
68
63
|
end
|
|
69
64
|
|
|
65
|
+
# Maximal runs of white cells, broken up by walls, in either direction
|
|
66
|
+
def white_runs(direction)
|
|
67
|
+
lines = if direction == :horizontal
|
|
68
|
+
(0...@ysize).map{|y| (0...@xsize).map{|x| [x,y]}}
|
|
69
|
+
else
|
|
70
|
+
(0...@xsize).map{|x| (0...@ysize).map{|y| [x,y]}}
|
|
71
|
+
end
|
|
72
|
+
lines.flat_map do |line|
|
|
73
|
+
line.chunk{|xy| @data[xy] == "."}.select{|white,_| white}.map{|_,run| run}
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def each_cell
|
|
78
|
+
(0...@ysize).each{|y| (0...@xsize).each{|x| yield x, y}}
|
|
79
|
+
end
|
|
80
|
+
|
|
70
81
|
def map_coordinates
|
|
71
82
|
Hash[(0...@xsize).to_a.product((0...@ysize).to_a).map{|x,y| [[x,y],yield(x,y)]}]
|
|
72
83
|
end
|
|
@@ -76,7 +87,7 @@ class LightUp
|
|
|
76
87
|
(0...@xsize).each do |x|
|
|
77
88
|
if @data[[x,y]] != "."
|
|
78
89
|
print(@data[[x,y]])
|
|
79
|
-
elsif @model[@lamps[[x,y]]].
|
|
90
|
+
elsif @model[@lamps[[x,y]]].to_b
|
|
80
91
|
print("*")
|
|
81
92
|
else
|
|
82
93
|
print(" ")
|
|
@@ -85,13 +96,6 @@ class LightUp
|
|
|
85
96
|
puts "\n"
|
|
86
97
|
end
|
|
87
98
|
end
|
|
88
|
-
|
|
89
|
-
def int01(x,y)
|
|
90
|
-
v = Z3.Int("l#{x},#{y}")
|
|
91
|
-
@solver.assert v >= 0
|
|
92
|
-
@solver.assert v <= 1
|
|
93
|
-
v
|
|
94
|
-
end
|
|
95
99
|
end
|
|
96
100
|
|
|
97
101
|
path = ARGV[0] || Pathname(__dir__) + "light_up-1.txt"
|
data/examples/nanro
CHANGED
|
@@ -91,10 +91,7 @@ class Nanro
|
|
|
91
91
|
@solver.assert (cvar(x,y) != 0).implies(Z3.Or(nvar(x,y) == 0, nvar(x,y) == nval))
|
|
92
92
|
end
|
|
93
93
|
|
|
94
|
-
@solver.assert Z3.
|
|
95
|
-
*enum_for(:each_xy).map{|x,y|
|
|
96
|
-
(nvar(x,y) == 0).ite(1,0)
|
|
97
|
-
}) == 1
|
|
94
|
+
@solver.assert Z3.Exactly(enum_for(:each_xy).map{|x,y| nvar(x,y) == 0 }, 1)
|
|
98
95
|
end
|
|
99
96
|
|
|
100
97
|
def call
|
|
@@ -47,7 +47,7 @@ class RegexpStringMatcher
|
|
|
47
47
|
~regexp_match([:seq, anchor[1], [:any_star]], start_idx, @str.size)
|
|
48
48
|
when :lookbehind
|
|
49
49
|
regexp_match([:seq, [:any_star], anchor[1]], 0, start_idx)
|
|
50
|
-
when :
|
|
50
|
+
when :negative_lookbehind
|
|
51
51
|
~regexp_match([:seq, [:any_star], anchor[1]], 0, start_idx)
|
|
52
52
|
else
|
|
53
53
|
raise "Unknown anchor type #{anchor[0]}"
|
data/examples/star_battle
CHANGED
|
@@ -15,20 +15,17 @@ class StarBattle
|
|
|
15
15
|
def call
|
|
16
16
|
# Each row contains 2 stars
|
|
17
17
|
@size.times do |y|
|
|
18
|
-
|
|
19
|
-
@solver.assert sum == 2
|
|
18
|
+
@solver.assert Z3.Exactly(@size.times.map{|x| cell_var(x, y) }, 2)
|
|
20
19
|
end
|
|
21
20
|
|
|
22
21
|
# Each column contains 2 stars
|
|
23
22
|
@size.times do |x|
|
|
24
|
-
|
|
25
|
-
@solver.assert sum == 2
|
|
23
|
+
@solver.assert Z3.Exactly(@size.times.map{|y| cell_var(x, y) }, 2)
|
|
26
24
|
end
|
|
27
25
|
|
|
28
26
|
# Each container contains 2 stars
|
|
29
27
|
coords.group_by{|x,y| container_at(x,y) }.each do |name, cells|
|
|
30
|
-
|
|
31
|
-
@solver.assert sum == 2
|
|
28
|
+
@solver.assert Z3.Exactly(cells.map{|x,y| cell_var(x, y) }, 2)
|
|
32
29
|
end
|
|
33
30
|
|
|
34
31
|
# Can't be adjacent
|
data/examples/stitches
CHANGED
|
@@ -55,20 +55,20 @@ class StitchesSolver
|
|
|
55
55
|
end
|
|
56
56
|
|
|
57
57
|
def row_of_cell_vars(y)
|
|
58
|
-
@xsize.times.map{|x| @cell_vars[[x,y]]
|
|
58
|
+
@xsize.times.map{|x| @cell_vars[[x,y]] }
|
|
59
59
|
end
|
|
60
60
|
|
|
61
61
|
def col_of_cell_vars(x)
|
|
62
|
-
@ysize.times.map{|y| @cell_vars[[x,y]]
|
|
62
|
+
@ysize.times.map{|y| @cell_vars[[x,y]] }
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
def setup_cell_assertions!
|
|
66
66
|
@xsize.times do |x|
|
|
67
|
-
@solver.assert Z3.
|
|
67
|
+
@solver.assert Z3.Exactly(col_of_cell_vars(x), @col_counts[x])
|
|
68
68
|
end
|
|
69
69
|
|
|
70
70
|
@ysize.times do |y|
|
|
71
|
-
@solver.assert Z3.
|
|
71
|
+
@solver.assert Z3.Exactly(row_of_cell_vars(y), @row_counts[y])
|
|
72
72
|
end
|
|
73
73
|
end
|
|
74
74
|
|
|
@@ -110,7 +110,7 @@ class StitchesSolver
|
|
|
110
110
|
|
|
111
111
|
def setup_stitch_assertions!
|
|
112
112
|
@stitch_groups.each do |g, vars|
|
|
113
|
-
@solver.assert Z3.
|
|
113
|
+
@solver.assert Z3.Exactly(vars, @stitch_count)
|
|
114
114
|
end
|
|
115
115
|
end
|
|
116
116
|
|
data/examples/yajilin
CHANGED
|
@@ -134,7 +134,8 @@ class Yajilin
|
|
|
134
134
|
raise
|
|
135
135
|
end
|
|
136
136
|
|
|
137
|
-
|
|
137
|
+
# cvar is true for white, so ~cvar counts the black cells the arrow sees
|
|
138
|
+
@solver.assert Z3.Exactly(stripe.map{|c| ~c }, count)
|
|
138
139
|
end
|
|
139
140
|
end
|
|
140
141
|
end
|
|
@@ -182,10 +183,7 @@ class Yajilin
|
|
|
182
183
|
end
|
|
183
184
|
|
|
184
185
|
# only one loop start
|
|
185
|
-
@solver.assert Z3.
|
|
186
|
-
*enum_for(:each_xy).map{|x,y|
|
|
187
|
-
(nvar(x,y) == 0).ite(1,0)
|
|
188
|
-
}) == 1
|
|
186
|
+
@solver.assert Z3.Exactly(enum_for(:each_xy).map{|x,y| nvar(x,y) == 0 }, 1)
|
|
189
187
|
end
|
|
190
188
|
|
|
191
189
|
def call
|
data/lib/z3/expr/bitvec_expr.rb
CHANGED
|
@@ -77,10 +77,12 @@ module Z3
|
|
|
77
77
|
end
|
|
78
78
|
|
|
79
79
|
def rotate_left(num)
|
|
80
|
+
raise Z3::Exception, "Rotation amount must be a nonnegative Integer" unless num.is_a?(Integer) and num >= 0
|
|
80
81
|
sort.new(LowLevel.mk_rotate_left(num, self))
|
|
81
82
|
end
|
|
82
83
|
|
|
83
84
|
def rotate_right(num)
|
|
85
|
+
raise Z3::Exception, "Rotation amount must be a nonnegative Integer" unless num.is_a?(Integer) and num >= 0
|
|
84
86
|
sort.new(LowLevel.mk_rotate_right(num, self))
|
|
85
87
|
end
|
|
86
88
|
|
|
@@ -95,10 +97,12 @@ module Z3
|
|
|
95
97
|
end
|
|
96
98
|
|
|
97
99
|
def zero_ext(size)
|
|
100
|
+
raise Z3::Exception, "Extension size must be a nonnegative Integer" unless size.is_a?(Integer) and size >= 0
|
|
98
101
|
BitvecSort.new(sort.size + size).new(LowLevel.mk_zero_ext(size, self))
|
|
99
102
|
end
|
|
100
103
|
|
|
101
104
|
def sign_ext(size)
|
|
105
|
+
raise Z3::Exception, "Extension size must be a nonnegative Integer" unless size.is_a?(Integer) and size >= 0
|
|
102
106
|
BitvecSort.new(sort.size + size).new(LowLevel.mk_sign_ext(size, self))
|
|
103
107
|
end
|
|
104
108
|
|
|
@@ -106,9 +110,6 @@ module Z3
|
|
|
106
110
|
raise Z3::Exception, "Use #signed_add_no_overflow? or #unsigned_add_no_overflow? for Bitvec, not #add_no_overflow?"
|
|
107
111
|
end
|
|
108
112
|
|
|
109
|
-
def add_no_overflow?(other)
|
|
110
|
-
raise "Use signed_add_no_overflow? or unsigned_add_no_overflow?"
|
|
111
|
-
end
|
|
112
113
|
def signed_add_no_overflow?(other)
|
|
113
114
|
BitvecExpr.SignedAddNoOverflow(self, other)
|
|
114
115
|
end
|
|
@@ -123,11 +124,11 @@ module Z3
|
|
|
123
124
|
BitvecExpr.SignedAddNoUnderflow(self, other)
|
|
124
125
|
end
|
|
125
126
|
def unsigned_add_no_underflow?(other)
|
|
126
|
-
raise "Unsigned + cannot underflow"
|
|
127
|
+
raise Z3::Exception, "Unsigned + cannot underflow"
|
|
127
128
|
end
|
|
128
129
|
|
|
129
130
|
def unsigned_neg_no_overflow?
|
|
130
|
-
raise "There is no unsigned negation"
|
|
131
|
+
raise Z3::Exception, "There is no unsigned negation"
|
|
131
132
|
end
|
|
132
133
|
def signed_neg_no_overflow?
|
|
133
134
|
BitvecExpr.SignedNegNoOverflow(self)
|
|
@@ -137,7 +138,7 @@ module Z3
|
|
|
137
138
|
end
|
|
138
139
|
|
|
139
140
|
def mul_no_overflow?(other)
|
|
140
|
-
raise "Use signed_mul_no_overflow? or unsigned_mul_no_overflow?"
|
|
141
|
+
raise Z3::Exception, "Use signed_mul_no_overflow? or unsigned_mul_no_overflow?"
|
|
141
142
|
end
|
|
142
143
|
def signed_mul_no_overflow?(other)
|
|
143
144
|
BitvecExpr.SignedMulNoOverflow(self, other)
|
|
@@ -153,7 +154,7 @@ module Z3
|
|
|
153
154
|
BitvecExpr.SignedMulNoUnderflow(self, other)
|
|
154
155
|
end
|
|
155
156
|
def unsigned_mul_no_underflow?(other)
|
|
156
|
-
raise "Unsigned
|
|
157
|
+
raise Z3::Exception, "Unsigned * cannot underflow"
|
|
157
158
|
end
|
|
158
159
|
|
|
159
160
|
def div_no_overflow?(other)
|
|
@@ -163,7 +164,7 @@ module Z3
|
|
|
163
164
|
BitvecExpr.SignedDivNoOverflow(self, other)
|
|
164
165
|
end
|
|
165
166
|
def unsigned_div_no_overflow?(other)
|
|
166
|
-
raise "Unsigned / cannot
|
|
167
|
+
raise Z3::Exception, "Unsigned / cannot overflow"
|
|
167
168
|
end
|
|
168
169
|
|
|
169
170
|
def >>(other)
|
data/lib/z3/expr/bool_expr.rb
CHANGED
|
@@ -71,6 +71,32 @@ module Z3
|
|
|
71
71
|
b, c = coerce_to_same_sort(b, c)
|
|
72
72
|
b.sort.new(LowLevel.mk_ite(a, b, c))
|
|
73
73
|
end
|
|
74
|
+
|
|
75
|
+
# Native cardinality constraint: at most k of the given Bool exprs are true
|
|
76
|
+
def AtMost(args, k)
|
|
77
|
+
args = cardinality_args(args, k)
|
|
78
|
+
BoolSort.new.new(LowLevel.mk_atmost(args, k))
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Native cardinality constraint: at least k of the given Bool exprs are true
|
|
82
|
+
def AtLeast(args, k)
|
|
83
|
+
args = cardinality_args(args, k)
|
|
84
|
+
BoolSort.new.new(LowLevel.mk_atleast(args, k))
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Native cardinality constraint: exactly k of the given Bool exprs are true
|
|
88
|
+
def Exactly(args, k)
|
|
89
|
+
args = cardinality_args(args, k)
|
|
90
|
+
BoolSort.new.new(LowLevel.mk_pbeq(args, [1] * args.size, k))
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
private
|
|
94
|
+
|
|
95
|
+
def cardinality_args(args, k)
|
|
96
|
+
raise Z3::Exception, "Cardinality bound must be a non-negative Integer" unless k.is_a?(Integer) and k >= 0
|
|
97
|
+
raise Z3::Exception, "Cardinality constraint requires at least one argument" if args.empty?
|
|
98
|
+
coerce_to_same_bool_sort(*args)
|
|
99
|
+
end
|
|
74
100
|
end
|
|
75
101
|
end
|
|
76
102
|
end
|
data/lib/z3/expr/expr.rb
CHANGED
|
@@ -106,6 +106,7 @@ module Z3
|
|
|
106
106
|
end
|
|
107
107
|
|
|
108
108
|
def And(*args)
|
|
109
|
+
raise Z3::Exception, "And requires at least one argument" if args.empty?
|
|
109
110
|
args = coerce_to_same_sort(*args)
|
|
110
111
|
case args[0]
|
|
111
112
|
when BoolExpr
|
|
@@ -120,6 +121,7 @@ module Z3
|
|
|
120
121
|
end
|
|
121
122
|
|
|
122
123
|
def Or(*args)
|
|
124
|
+
raise Z3::Exception, "Or requires at least one argument" if args.empty?
|
|
123
125
|
args = coerce_to_same_sort(*args)
|
|
124
126
|
case args[0]
|
|
125
127
|
when BoolExpr
|
|
@@ -134,6 +136,7 @@ module Z3
|
|
|
134
136
|
end
|
|
135
137
|
|
|
136
138
|
def Xor(*args)
|
|
139
|
+
raise Z3::Exception, "Xor requires at least one argument" if args.empty?
|
|
137
140
|
args = coerce_to_same_sort(*args)
|
|
138
141
|
case args[0]
|
|
139
142
|
when BoolExpr
|
|
@@ -150,7 +153,7 @@ module Z3
|
|
|
150
153
|
end
|
|
151
154
|
|
|
152
155
|
def Add(*args)
|
|
153
|
-
raise Z3::Exception if args.empty?
|
|
156
|
+
raise Z3::Exception, "Add requires at least one argument" if args.empty?
|
|
154
157
|
args = coerce_to_same_sort(*args)
|
|
155
158
|
case args[0]
|
|
156
159
|
when ArithExpr
|
|
@@ -165,6 +168,7 @@ module Z3
|
|
|
165
168
|
end
|
|
166
169
|
|
|
167
170
|
def Sub(*args)
|
|
171
|
+
raise Z3::Exception, "Sub requires at least one argument" if args.empty?
|
|
168
172
|
args = coerce_to_same_sort(*args)
|
|
169
173
|
case args[0]
|
|
170
174
|
when ArithExpr
|
|
@@ -179,6 +183,7 @@ module Z3
|
|
|
179
183
|
end
|
|
180
184
|
|
|
181
185
|
def Mul(*args)
|
|
186
|
+
raise Z3::Exception, "Mul requires at least one argument" if args.empty?
|
|
182
187
|
args = coerce_to_same_sort(*args)
|
|
183
188
|
case args[0]
|
|
184
189
|
when ArithExpr
|
data/lib/z3/expr/set_expr.rb
CHANGED
data/lib/z3/func_decl.rb
CHANGED
|
@@ -23,10 +23,35 @@ module Z3
|
|
|
23
23
|
Sort.from_pointer(LowLevel::get_range(self))
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
|
|
26
|
+
# Decl parameters are the `_`-part of an indexed decl like
|
|
27
|
+
# `(_ map or)`, `(_ extract 7 0)`, `(_ zero_extend 8)`.
|
|
28
|
+
# They have nothing to do with the domain, so they're not counted by #arity.
|
|
29
|
+
PARAMETER_KINDS = {
|
|
30
|
+
0 => :int,
|
|
31
|
+
1 => :double,
|
|
32
|
+
2 => :rational,
|
|
33
|
+
3 => :symbol,
|
|
34
|
+
4 => :sort,
|
|
35
|
+
5 => :ast,
|
|
36
|
+
6 => :func_decl,
|
|
37
|
+
7 => :internal,
|
|
38
|
+
8 => :zstring,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
def num_parameters
|
|
42
|
+
LowLevel.get_decl_num_parameters(self)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def parameter_kind(i)
|
|
46
|
+
raise Z3::Exception, "Trying to access parameter #{i} but decl has #{num_parameters} parameters" if i < 0 or i >= num_parameters
|
|
47
|
+
k = LowLevel.get_decl_parameter_kind(self, i)
|
|
48
|
+
PARAMETER_KINDS.fetch(k) { raise Z3::Exception, "Unknown decl parameter kind #{k}" }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def func_decl_parameter(i)
|
|
52
|
+
raise Z3::Exception, "Parameter #{i} is a #{parameter_kind(i)}, not a func decl" unless parameter_kind(i) == :func_decl
|
|
53
|
+
FuncDecl.new(LowLevel.get_decl_func_decl_parameter(self, i))
|
|
54
|
+
end
|
|
30
55
|
|
|
31
56
|
def to_s
|
|
32
57
|
name
|
data/lib/z3/goal.rb
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
module Z3
|
|
2
2
|
class Goal
|
|
3
|
+
include ReferenceCounted
|
|
4
|
+
|
|
3
5
|
attr_reader :_goal
|
|
4
6
|
def initialize(_goal)
|
|
5
7
|
@_goal = _goal
|
|
8
|
+
inc_ref! :goal, _goal
|
|
6
9
|
end
|
|
7
10
|
|
|
8
11
|
def assert(ast)
|
|
@@ -55,6 +58,10 @@ module Z3
|
|
|
55
58
|
LowLevel.goal_to_string(self)
|
|
56
59
|
end
|
|
57
60
|
|
|
61
|
+
def to_dimacs(include_names=true)
|
|
62
|
+
LowLevel.goal_to_dimacs_string(self, include_names)
|
|
63
|
+
end
|
|
64
|
+
|
|
58
65
|
class << self
|
|
59
66
|
def new(models=false, unsat_cores=false, proofs=false)
|
|
60
67
|
super LowLevel.mk_goal(!!models, !!unsat_cores, !!proofs)
|