z3 0.0.20160427 → 0.0.20161008

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.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +2 -0
  3. data/Rakefile +56 -0
  4. data/examples/bit_tricks +21 -38
  5. data/examples/circuit_problems +170 -0
  6. data/lib/z3/ast.rb +21 -3
  7. data/lib/z3/context.rb +9 -7
  8. data/lib/z3/exception.rb +1 -2
  9. data/lib/z3/expr/arith_expr.rb +29 -11
  10. data/lib/z3/expr/array_expr.rb +5 -0
  11. data/lib/z3/expr/bitvec_expr.rb +293 -13
  12. data/lib/z3/expr/bool_expr.rb +30 -6
  13. data/lib/z3/expr/expr.rb +155 -2
  14. data/lib/z3/expr/float_expr.rb +185 -0
  15. data/lib/z3/expr/int_expr.rb +20 -5
  16. data/lib/z3/expr/real_expr.rb +1 -3
  17. data/lib/z3/expr/rounding_mode_expr.rb +5 -0
  18. data/lib/z3/expr/set_expr.rb +66 -0
  19. data/lib/z3/func_decl.rb +5 -5
  20. data/lib/z3/goal.rb +64 -0
  21. data/lib/z3/interface.rb +21 -222
  22. data/lib/z3/low_level.rb +84 -58
  23. data/lib/z3/low_level_auto.rb +1509 -1563
  24. data/lib/z3/model.rb +39 -37
  25. data/lib/z3/printer.rb +54 -12
  26. data/lib/z3/probe.rb +69 -0
  27. data/lib/z3/solver.rb +20 -20
  28. data/lib/z3/sort/array_sort.rb +24 -0
  29. data/lib/z3/sort/bitvec_sort.rb +1 -1
  30. data/lib/z3/sort/float_sort.rb +92 -0
  31. data/lib/z3/sort/rounding_mode_sort.rb +41 -0
  32. data/lib/z3/sort/set_sort.rb +31 -0
  33. data/lib/z3/sort/sort.rb +39 -5
  34. data/lib/z3/tactic.rb +69 -0
  35. data/lib/z3/very_low_level.rb +33 -29
  36. data/lib/z3/very_low_level_auto.rb +505 -517
  37. data/lib/z3.rb +13 -0
  38. data/spec/array_expr_spec.rb +18 -0
  39. data/spec/array_sort_spec.rb +11 -0
  40. data/spec/bitvec_expr_spec.rb +196 -44
  41. data/spec/bitvec_sort_spec.rb +29 -27
  42. data/spec/bool_expr_spec.rb +57 -55
  43. data/spec/bool_sort_spec.rb +17 -15
  44. data/spec/coverage_helper.rb +11 -0
  45. data/spec/expr_spec.rb +151 -147
  46. data/spec/float_expr_spec.rb +167 -0
  47. data/spec/float_sort_spec.rb +44 -0
  48. data/spec/goal_spec.rb +17 -0
  49. data/spec/int_expr_spec.rb +76 -63
  50. data/spec/int_sort_spec.rb +16 -14
  51. data/spec/integration/algebra_problems_spec.rb +4 -4
  52. data/spec/integration/cicruit_problem_spec.rb +23 -0
  53. data/spec/integration/geometry_problem_spec.rb +4 -4
  54. data/spec/integration/kinematics_problems_spec.rb +3 -3
  55. data/spec/model_spec.rb +39 -37
  56. data/spec/printer_spec.rb +49 -18
  57. data/spec/probe_spec.rb +17 -0
  58. data/spec/real_expr_spec.rb +59 -51
  59. data/spec/real_sort_spec.rb +22 -20
  60. data/spec/rounding_mode_expr_spec.rb +16 -0
  61. data/spec/rounding_mode_sort_spec.rb +13 -0
  62. data/spec/set_expr_spec.rb +61 -0
  63. data/spec/set_sort_spec.rb +27 -0
  64. data/spec/solver_spec.rb +37 -27
  65. data/spec/sort_spec.rb +38 -36
  66. data/spec/spec_helper.rb +59 -2
  67. data/spec/tactic_spec.rb +9 -0
  68. metadata +44 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b373cf9a8caebd1c5a05420660ac2301528613eb
4
- data.tar.gz: 4c45e3aa7326aeaefddee63a17c8a4eeb1fe57e0
3
+ metadata.gz: f77923728739173352acc32c2b86d15d158df0aa
4
+ data.tar.gz: 6d14bf2597324dfaeb56fef62126466a80312b59
5
5
  SHA512:
6
- metadata.gz: 6a2bd8245fcb32c67f0c609b477842a6f804fcc45d514f7d8d7a8ec047c8e6e70875167562aef1c51d04b637c900f001d4ad8e35368005f9aa3c7990239ab841
7
- data.tar.gz: 73efd05c6292e8ef129c8a711a7de4b5a377c585991a11f4fe6930763c9e9e9ead23cc36fa98caba35966d9d7e5f897509ee7bb5bf003ff355d3ad2001b731f0
6
+ metadata.gz: 5c298ac6d9809173f284ac05ae13e19a52cebd56cff557f36894a6b8e5168f68bcfee71e1652ae3848d7009a2572bcdc3663e858e66f808b8c8a112f8a1a25bf
7
+ data.tar.gz: cf216b75b22a6c172f06613972a8d1c0644efee56ea1462df24d040aa189b58558d594d84156ba1e3ebc3e23b24fc4371faa661f519aecd8e2fa0afe47c98da9
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/Rakefile ADDED
@@ -0,0 +1,56 @@
1
+ require "json"
2
+
3
+ task "default" => "spec"
4
+ task "test" => "spec"
5
+ task "test:integration" => "spec:integration"
6
+ task "test:unit" => "spec:unit"
7
+
8
+ desc "Regenerate API"
9
+ task "api" do
10
+ system "./api/gen_api api/definitions.h"
11
+ end
12
+
13
+ desc "Clean up"
14
+ task "clean" do
15
+ system "trash z3-*.gem coverage"
16
+ end
17
+
18
+ desc "Run tests"
19
+ task "spec" do
20
+ system "rspec"
21
+ end
22
+
23
+ desc "Run unit tests"
24
+ task "spec:unit" do
25
+ system "rspec spec/*_spec.rb"
26
+ end
27
+
28
+ desc "Run integration tests"
29
+ task "spec:integration" do
30
+ system "rspec spec/integration/*_spec.rb"
31
+ end
32
+
33
+ desc "Build gem"
34
+ task "gem:build" do
35
+ system "gem build z3.gemspec"
36
+ end
37
+
38
+ desc "Upload gem"
39
+ task "gem:push" => "gem:build" do
40
+ gem_file = Dir["z3-*.gem"][-1] or raise "No gem found"
41
+ system "gem", "push", gem_file
42
+ end
43
+
44
+ desc "Report missing APIs"
45
+ task "coverage:missing" do
46
+ system "COVERAGE=1 rake test"
47
+ data = JSON.load(open("coverage/.resultset.json"))["RSpec"]["coverage"]
48
+ lla_path = data.keys.find{|k| k.end_with?("lib/z3/low_level_auto.rb")}
49
+ coverage = data[lla_path].zip(File.readlines(lla_path).map(&:strip))
50
+ missing = coverage.each_cons(2).map(&:flatten).select{|_,_,bc,_| bc == 0}.map{|_,a,_,_| a.sub(/\Adef /, "")}
51
+ # Also missing is everything that uses too fancy calling convention for automated generation
52
+ # That's currently 60 functions
53
+ open("missing_apis.txt", "w") do |file|
54
+ file.puts missing
55
+ end
56
+ end
data/examples/bit_tricks CHANGED
@@ -2,15 +2,21 @@
2
2
 
3
3
  require_relative "../lib/z3"
4
4
 
5
+ def c_boolean(expr)
6
+ one = Z3::BitvecSort.new(32).from_const(1)
7
+ zero = Z3::BitvecSort.new(32).from_const(0)
8
+ expr.ite(one, zero)
9
+ end
10
+
5
11
  def validate_sign_by_shift!
6
12
  """
7
13
  sign = v >> (sizeof(int) * CHAR_BIT - 1);
8
14
  """
9
15
  solver = Z3::Solver.new
10
16
  v = Z3.Bitvec("v", 32)
11
- s = v >> 31
17
+ s = v.signed_rshift(31)
12
18
  puts "Validating sign trick:"
13
- solver.prove! ((v < 0) & (s == -1)) | ((v >= 0) & (s == 0))
19
+ solver.prove! (v.signed_lt(0) & (s == -1)) | (v.signed_ge(0) & (s == 0))
14
20
  end
15
21
 
16
22
  def validate_opposite_sign_by_xor!
@@ -21,15 +27,15 @@ def validate_opposite_sign_by_xor!
21
27
  solver = Z3::Solver.new
22
28
  x = Z3.Bitvec("x", 32)
23
29
  y = Z3.Bitvec("y", 32)
24
- f = (x^y) < 0
30
+ f = (x^y).signed_lt(0)
25
31
 
26
32
  puts "Validating sign trick:"
27
33
  solver.prove!(
28
34
  Z3.Or(
29
- Z3.And(x >= 0, y >= 0, f == false),
30
- Z3.And(x < 0, y < 0, f == false),
31
- Z3.And(x >= 0, y < 0, f == true),
32
- Z3.And(x < 0, y >= 0, f == true),
35
+ Z3.And(x.signed_ge(0), y.signed_ge(0), f == false),
36
+ Z3.And(x.signed_lt(0), y.signed_lt(0), f == false),
37
+ Z3.And(x.signed_ge(0), y.signed_lt(0), f == true),
38
+ Z3.And(x.signed_lt(0), y.signed_ge(0), f == true),
33
39
  )
34
40
  )
35
41
  end
@@ -43,14 +49,11 @@ def validate_abs_without_branching_1!
43
49
  """
44
50
  solver = Z3::Solver.new
45
51
  v = Z3.Bitvec("v", 32)
46
- mask = v >> 31
52
+ mask = v.signed_rshift(31)
47
53
  r = (v + mask) ^ mask
48
54
  puts "Validating abs without branching, version 1"
49
55
  solver.prove!(
50
- Z3.Or(
51
- Z3.And(v >= 0, r==v),
52
- Z3.And(v < 0, r==-v)
53
- )
56
+ v.signed_ge(0).ite(r == v, r == -v)
54
57
  )
55
58
  end
56
59
 
@@ -63,28 +66,14 @@ def validate_abs_without_branching_2!
63
66
  """
64
67
  solver = Z3::Solver.new
65
68
  v = Z3.Bitvec("v", 32)
66
- mask = v >> 31
69
+ mask = v.signed_rshift(31)
67
70
  r = (v^mask) - mask
68
71
  puts "Validating abs without branching, version 2"
69
72
  solver.prove!(
70
- Z3.Or(
71
- Z3.And(v >= 0, r==v),
72
- Z3.And(v < 0, r==-v)
73
- )
73
+ v.signed_ge(0).ite(r == v, r == -v)
74
74
  )
75
75
  end
76
76
 
77
- def c_boolean(solver, bool_expr, name)
78
- expr_val = Z3.Bitvec(name, 32)
79
- solver.assert(
80
- Z3.Or(
81
- Z3.And(bool_expr, expr_val == 1),
82
- Z3.And(~bool_expr, expr_val == 0),
83
- )
84
- )
85
- expr_val
86
- end
87
-
88
77
  def validate_min_without_branching!
89
78
  """
90
79
  int x; // we want to find the minimum of x and y
@@ -95,13 +84,10 @@ def validate_min_without_branching!
95
84
  solver = Z3::Solver.new
96
85
  x = Z3.Bitvec("x", 32)
97
86
  y = Z3.Bitvec("y", 32)
98
- r = y ^ ((x ^ y) & -c_boolean(solver, x < y, "t"))
87
+ r = y ^ ((x ^ y) & -c_boolean(x.signed_lt(y)))
99
88
  puts "Validating min without branching"
100
89
  solver.prove!(
101
- Z3.Or(
102
- Z3.And(x <= y, r == x),
103
- Z3.And(y <= y, r == y),
104
- )
90
+ x.signed_le(y).ite(r == x, r == y)
105
91
  )
106
92
  end
107
93
 
@@ -115,13 +101,10 @@ def validate_max_without_branching!
115
101
  solver = Z3::Solver.new
116
102
  x = Z3.Bitvec("x", 32)
117
103
  y = Z3.Bitvec("y", 32)
118
- r = x ^ ((x ^ y) & -c_boolean(solver, x < y, "t"))
104
+ r = x ^ ((x ^ y) & -c_boolean(x.signed_lt(y)))
119
105
  puts "Validating max without branching"
120
106
  solver.prove!(
121
- Z3.Or(
122
- Z3.And(x >= y, r == x),
123
- Z3.And(y >= y, r == y),
124
- )
107
+ x.signed_ge(y).ite(r == x, r == y)
125
108
  )
126
109
  end
127
110
 
@@ -0,0 +1,170 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative "../lib/z3"
4
+
5
+ # It's totally possible everything is backwards
6
+ class CircuitProblem
7
+ def initialize
8
+ @solver = Z3::Solver.new
9
+ @pins = {}
10
+ end
11
+
12
+ def battery(name, battery_voltage)
13
+ plus = create_pin("#{name}+")
14
+ minus = create_pin("#{name}-")
15
+ current = create_current("#{name}", "#{name}+", "#{name}-")
16
+ @solver.assert plus[:voltage] - minus[:voltage] == battery_voltage
17
+ end
18
+
19
+ def resistor(name, resistance)
20
+ a = create_pin("#{name}a")
21
+ b = create_pin("#{name}b")
22
+ current = create_current("#{name}", "#{name}a", "#{name}b")
23
+ # dV = RI
24
+ @solver.assert (a[:voltage] - b[:voltage]) == current * resistance
25
+ end
26
+
27
+ # This is super simple diode model
28
+ def diode(name)
29
+ a = create_pin("#{name}+")
30
+ b = create_pin("#{name}-")
31
+ current = create_current("#{name}", "#{name}+", "#{name}-")
32
+ # * current can't flow backwards
33
+ # * if voltage is reversed, current is stopped (infinite resistance)
34
+ # * if current is flowing, voltage is equalized (zero resistance)
35
+ # * voltage is same or current is zero
36
+ @solver.assert current >= 0
37
+ @solver.assert a[:voltage] <= b[:voltage]
38
+ # @solver.assert Z3.Implies(current > 0, a[:voltage] == b[:voltage])
39
+ # @solver.assert Z3.Implies(a[:voltage] < b[:voltage], current == 0)
40
+ @solver.assert Z3.Or(a[:voltage] == b[:voltage], current == 0)
41
+ end
42
+
43
+ def connect(a, b)
44
+ create_current("Wire #{a} #{b}", a, b)
45
+ @solver.assert @pins[a][:voltage] == @pins[b][:voltage]
46
+ end
47
+
48
+ def solve!(*vars)
49
+ setup_flow_rules!
50
+ with_solved_model do |model|
51
+ model.each do |n,v|
52
+ next unless vars.include?(n.to_s)
53
+ puts "* #{n} = #{v}"
54
+ end
55
+ end
56
+ end
57
+
58
+ def debug!
59
+ setup_flow_rules!
60
+ with_solved_model do |model|
61
+ model.each do |n,v|
62
+ puts "* #{n} = #{v}"
63
+ end
64
+ end
65
+ end
66
+
67
+ def ground(name)
68
+ @solver.assert @pins[name][:voltage] == 0
69
+ end
70
+
71
+ private
72
+
73
+ def with_solved_model
74
+ if @solver.check == :sat
75
+ yield @solver.model
76
+ else
77
+ puts "Can't solve the problem"
78
+ end
79
+ end
80
+
81
+ def setup_flow_rules!
82
+ @pins.each do |name, pin|
83
+ # All current flows are equal
84
+ @solver.assert Z3.Add(*pin[:current]) == 0
85
+ end
86
+ end
87
+
88
+ def create_pin(name)
89
+ raise "Pin named #{name} already exists" if @pins[name]
90
+ @pins[name] = {
91
+ voltage: Z3.Real("V #{name}"),
92
+ current: [],
93
+ }
94
+ end
95
+
96
+ def create_current(name, source, sink)
97
+ raise "No such pin: #{source}" unless @pins[source]
98
+ raise "No such pin: #{sink}" unless @pins[sink]
99
+ current = Z3.Real("I #{name}")
100
+ @pins[source][:current] << current
101
+ @pins[sink][:current] << -current
102
+ current
103
+ end
104
+ end
105
+
106
+ # http://physics.info/circuits-r/practice.shtml
107
+ def problem_1!
108
+ problem = CircuitProblem.new
109
+ problem.battery "V", 125
110
+ problem.ground "V-"
111
+ problem.resistor "R1", 20
112
+ problem.resistor "R2", 30
113
+ problem.resistor "R3", 50
114
+ problem.connect "V-", "R1a"
115
+ problem.connect "R1b", "R2a"
116
+ problem.connect "R2b", "R3a"
117
+ problem.connect "R3b", "V+"
118
+ problem.solve! "I V"
119
+ end
120
+
121
+ def problem_2!
122
+ problem = CircuitProblem.new
123
+ problem.battery "V", 125
124
+ problem.ground "V-"
125
+ problem.resistor "R1", 20
126
+ problem.resistor "R2", 100
127
+ problem.resistor "R3", 50
128
+ problem.connect "V-", "R1a"
129
+ problem.connect "V-", "R2a"
130
+ problem.connect "V-", "R3a"
131
+ problem.connect "V+", "R1b"
132
+ problem.connect "V+", "R2b"
133
+ problem.connect "V+", "R3b"
134
+ problem.solve! "I V"
135
+ end
136
+
137
+ def problem_3!
138
+ # V+ [ D1 -> ] La
139
+ # V- [ D2 -> ] La
140
+ # V+ [ D3 <- ] Lb
141
+ # V- [ D4 <- ] Lb
142
+ [100, 50, 0, -50, -100].each do |v|
143
+ problem = CircuitProblem.new
144
+ problem.battery "V", v
145
+ problem.ground "V-"
146
+ problem.resistor "L", 100
147
+ problem.diode "D1"
148
+ problem.diode "D2"
149
+ problem.diode "D3"
150
+ problem.diode "D4"
151
+ problem.connect "D1-", "V+"
152
+ problem.connect "D1+", "La"
153
+ problem.connect "D2-", "V-"
154
+ problem.connect "D2+", "La"
155
+ problem.connect "D3-", "Lb"
156
+ problem.connect "D3+", "V+"
157
+ problem.connect "D4-", "Lb"
158
+ problem.connect "D4+", "V-"
159
+ problem.solve! "I V", "I L"
160
+ end
161
+ end
162
+
163
+ puts "Problem 1"
164
+ problem_1!
165
+ puts ""
166
+ puts "Problem 2"
167
+ problem_2!
168
+ puts ""
169
+ puts "Problem 3"
170
+ problem_3!
data/lib/z3/ast.rb CHANGED
@@ -16,16 +16,34 @@ module Z3
16
16
  5 => :func_decl,
17
17
  1000 => :unknown,
18
18
  }
19
- kind_id = Z3::LowLevel.get_ast_kind(self)
19
+ kind_id = LowLevel.get_ast_kind(self)
20
20
  ast_kind_lookup[kind_id] or raise Z3::Exception, "Unknown AST kind #{kind_id}"
21
21
  end
22
22
 
23
+ def func_decl
24
+ raise Z3::Exception, "Only app ASTs can have func decls" unless ast_kind == :app
25
+ FuncDecl.new(LowLevel::get_app_decl(self))
26
+ end
27
+
28
+ def arguments
29
+ raise Z3::Exception, "Only app ASTs can have arguments" unless ast_kind == :app
30
+ num = LowLevel::get_app_num_args(self)
31
+ (0...num).map do |i|
32
+ _ast = LowLevel::get_app_arg(self, i)
33
+ Expr.new_from_pointer(_ast)
34
+ end
35
+ end
36
+
23
37
  def to_s
24
- Z3::Printer.new.format(self)
38
+ Printer.new.format(self)
25
39
  end
26
40
 
27
41
  def sexpr
28
- Z3::LowLevel.ast_to_string(self)
42
+ LowLevel.ast_to_string(self)
43
+ end
44
+
45
+ def simplify
46
+ sort.new(LowLevel.simplify(self))
29
47
  end
30
48
 
31
49
  private_class_method :new
data/lib/z3/context.rb CHANGED
@@ -1,10 +1,12 @@
1
- class Z3::Context
2
- attr_reader :_context
3
- def initialize
4
- @_context = Z3::LowLevel.mk_context
5
- end
1
+ module Z3
2
+ class Context
3
+ attr_reader :_context
4
+ def initialize
5
+ @_context = LowLevel.mk_context
6
+ end
6
7
 
7
- def self.instance
8
- @instance ||= new
8
+ def self.instance
9
+ @instance ||= new
10
+ end
9
11
  end
10
12
  end
data/lib/z3/exception.rb CHANGED
@@ -2,8 +2,7 @@ module Z3
2
2
  class Exception < StandardError
3
3
  end
4
4
 
5
-
6
- Z3::LowLevel.set_error_handler do |ctx, error|
5
+ LowLevel.set_error_handler do |ctx, error|
7
6
  error_codes_enum = %W[
8
7
  Z3_OK
9
8
  Z3_SORT_ERROR
@@ -1,40 +1,39 @@
1
1
  module Z3
2
- # IntExpr / RealExpr
3
- module ArithExpr
2
+ class ArithExpr < Expr
4
3
  def +(other)
5
- ::Z3.Add(self, other)
4
+ Expr.Add(self, other)
6
5
  end
7
6
 
8
7
  def -(other)
9
- ::Z3.Sub(self, other)
8
+ Expr.Sub(self, other)
10
9
  end
11
10
 
12
11
  def *(other)
13
- ::Z3.Mul(self, other)
12
+ Expr.Mul(self, other)
14
13
  end
15
14
 
16
15
  def /(other)
17
- ::Z3.Div(self, other)
16
+ ArithExpr.Div(self, other)
18
17
  end
19
18
 
20
19
  def **(other)
21
- ::Z3.Power(self, other)
20
+ ArithExpr.Power(self, other)
22
21
  end
23
22
 
24
23
  def >(other)
25
- ::Z3.Gt(self, other)
24
+ Expr.Gt(self, other)
26
25
  end
27
26
 
28
27
  def >=(other)
29
- ::Z3.Ge(self, other)
28
+ Expr.Ge(self, other)
30
29
  end
31
30
 
32
31
  def <=(other)
33
- ::Z3.Le(self, other)
32
+ Expr.Le(self, other)
34
33
  end
35
34
 
36
35
  def <(other)
37
- ::Z3.Lt(self, other)
36
+ Expr.Lt(self, other)
38
37
  end
39
38
 
40
39
  def -@
@@ -49,5 +48,24 @@ module Z3
49
48
  max_sort = [sort, other_sort].max
50
49
  [max_sort.from_const(other), max_sort.from_value(self)]
51
50
  end
51
+
52
+ class << self
53
+ def coerce_to_same_arith_sort(*args)
54
+ args = coerce_to_same_sort(*args)
55
+ raise Z3::Exception, "Int or Real value expected" unless args[0].is_a?(IntExpr) or args[0].is_a?(RealExpr)
56
+ args
57
+ end
58
+
59
+ def Div(a,b)
60
+ a, b = coerce_to_same_arith_sort(a, b)
61
+ a.sort.new(LowLevel.mk_div(a, b))
62
+ end
63
+
64
+ def Power(a, b)
65
+ # Wait, is this even legitimate that it's I**I and R**R?
66
+ a, b = coerce_to_same_arith_sort(a, b)
67
+ a.sort.new(LowLevel.mk_power(a, b))
68
+ end
69
+ end
52
70
  end
53
71
  end
@@ -0,0 +1,5 @@
1
+ module Z3
2
+ class ArrayExpr < Expr
3
+ public_class_method :new
4
+ end
5
+ end