z3 0.0.20160427 → 0.0.20161008

Sign up to get free protection for your applications and to get access to all the features.
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