z3 0.0.20160221 → 0.0.20160323

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 (48) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -1
  3. data/examples/algebra_problems +24 -24
  4. data/examples/basic_int_math +8 -8
  5. data/examples/basic_logic +8 -8
  6. data/examples/bit_tricks +161 -0
  7. data/examples/bridges_solver +1 -1
  8. data/examples/clogic_puzzle_solver +135 -0
  9. data/examples/four_hackers_puzzle +194 -0
  10. data/examples/geometry_problem +11 -11
  11. data/examples/kakuro_solver +3 -3
  12. data/examples/kinematics_problems +37 -37
  13. data/examples/letter_connections_solver +11 -11
  14. data/examples/light_up_solver +5 -5
  15. data/examples/minisudoku_solver +4 -4
  16. data/examples/selfref_solver +35 -35
  17. data/examples/sudoku_solver +4 -4
  18. data/examples/verbal_arithmetic +2 -2
  19. data/lib/z3/exception.rb +25 -0
  20. data/lib/z3/func_decl.rb +7 -7
  21. data/lib/z3/interface.rb +255 -0
  22. data/lib/z3/low_level.rb +4 -6
  23. data/lib/z3/low_level_auto.rb +1551 -1547
  24. data/lib/z3/model.rb +3 -2
  25. data/lib/z3/solver.rb +65 -54
  26. data/lib/z3/sort/bitvec_sort.rb +40 -0
  27. data/lib/z3/sort/bool_sort.rb +31 -0
  28. data/lib/z3/sort/int_sort.rb +21 -0
  29. data/lib/z3/sort/real_sort.rb +36 -0
  30. data/lib/z3/sort/sort.rb +76 -0
  31. data/lib/z3/value/arith_value.rb +53 -0
  32. data/lib/z3/value/bitvec_value.rb +67 -0
  33. data/lib/z3/value/bool_value.rb +29 -0
  34. data/lib/z3/value/int_value.rb +7 -0
  35. data/lib/z3/value/real_value.rb +7 -0
  36. data/lib/z3/value/value.rb +48 -0
  37. data/lib/z3/very_low_level.rb +28 -45
  38. data/lib/z3/very_low_level_auto.rb +518 -516
  39. data/lib/z3.rb +23 -33
  40. data/spec/integration/bit_tricks_spec.rb +21 -0
  41. data/spec/model_spec.rb +9 -9
  42. data/spec/solver_spec.rb +2 -2
  43. data/spec/sort_spec.rb +38 -13
  44. data/spec/{ast_spec.rb → value_spec.rb} +60 -57
  45. metadata +21 -6
  46. data/lib/z3/ast.rb +0 -302
  47. data/lib/z3/sort.rb +0 -33
  48. /data/spec/integration/{bagic_int_math_spec.rb → basic_int_math_spec.rb} +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 73f23f4e1511fe002de7b2e1d3d91945bc6f8be6
4
- data.tar.gz: e6662d712ccaedd2b76a9c560dac242228d51311
3
+ metadata.gz: 3ec7feb43474477a1c3a7220fbbd5c6e11246cd2
4
+ data.tar.gz: 687aedb2c8aaeca944108d4361459bba5ba08eb5
5
5
  SHA512:
6
- metadata.gz: 206d8cb1e08173e3013da2426359a922c72631c28e84957ac8b94ce1219e5295960436fbd78513eb128cd0eb1b396bdf4f534247b183848ecb92df4d16d9e452
7
- data.tar.gz: 04f74e3844e9e017bb6636cd26b96fd0cc79e05e59a86650c66fe18b271a3bc9798ee8481fb9979ec134cb298354f03c2b097b14f9c531166bf0f0ac87ea0ce6
6
+ metadata.gz: 9e641cf575e0810de111a96f394747b1316dc2f9cebd63c7a52390c2439c7836abf1660d67b52998f5e4a048fea74a569121e7f9fd9e4a2e32bce82367082362
7
+ data.tar.gz: 9d1c79300d21645a5ed1e121a8f069fd0a4504c5731ff07c5e5f6a6727647c94ae64fb885c4f4e5bfb2b4641183b2e697f8128d3f66f784cdc9ab6dcce3361fe
data/README.md CHANGED
@@ -8,10 +8,12 @@ It's in extremely early stages of development. Pull requests always welcome.
8
8
 
9
9
  The rest of `Z3` is high level API, but the interface is extremely unstable at this point, and it's pretty much guaranteed to change many times. Check specs or `examples/` directory for usage.
10
10
 
11
- You can use most Ruby operators to construct ASTs, but use `~ | &` instead of `! || &&` for boolean operators.
11
+ 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
12
 
13
13
  As for API internals, attributes starting with `_` are FFI internals you shouldn't touch, other attributes are generally legitimate Ruby objects.
14
14
 
15
+ Bit vectors are treated as signed by default. [well, mostly, more systematic treatment of this is on TODO list]
16
+
15
17
  ### Requirements
16
18
 
17
19
  To use it, you'll need to install `z3`. On OSX that would be:
@@ -22,7 +22,7 @@ end
22
22
 
23
23
  class AlgebraProblem01 < AlgebraProblem
24
24
  def solve!
25
- x = Z3::Ast.real("x")
25
+ x = Z3.Real("x")
26
26
  solver.assert 5*(-3*x - 2) - (x - 3) == -4*(4*x + 5) + 13
27
27
  print_solution! "01"
28
28
  # No nice way to say x is unconstrained
@@ -31,17 +31,17 @@ end
31
31
 
32
32
  class AlgebraProblem03 < AlgebraProblem
33
33
  def declare_abs(var, expr)
34
- solver.assert Z3::Ast.or(
35
- Z3::Ast.and(var == expr, expr >= 0),
36
- Z3::Ast.and(var == -expr, expr <= 0)
34
+ solver.assert Z3.Or(
35
+ Z3.And(var == expr, expr >= 0),
36
+ Z3.And(var == -expr, expr <= 0)
37
37
  )
38
38
  end
39
39
 
40
40
  def solve!
41
- x = Z3::Ast.real("x")
42
- xm2abs = Z3::Ast.real("|x-2|")
41
+ x = Z3.Real("x")
42
+ xm2abs = Z3.Real("|x-2|")
43
43
  declare_abs(xm2abs, x-2)
44
- m6abs = Z3::Ast.real("|-6|")
44
+ m6abs = Z3.Real("|-6|")
45
45
  declare_abs(m6abs, -6)
46
46
  solver.assert x < 2
47
47
  solver.assert xm2abs == 4*m6abs
@@ -56,11 +56,11 @@ class AlgebraProblem04 < AlgebraProblem
56
56
  end
57
57
 
58
58
  def solve!
59
- ax = Z3::Ast.real("ax")
60
- ay = Z3::Ast.real("ay")
61
- bx = Z3::Ast.real("bx")
62
- by = Z3::Ast.real("by")
63
- a_b = Z3::Ast.real("|a-b|")
59
+ ax = Z3.Real("ax")
60
+ ay = Z3.Real("ay")
61
+ bx = Z3.Real("bx")
62
+ by = Z3.Real("by")
63
+ a_b = Z3.Real("|a-b|")
64
64
  declare_distance(a_b, ax, ay, bx, by)
65
65
  solver.assert ax == -4
66
66
  solver.assert ay == -5
@@ -72,8 +72,8 @@ end
72
72
 
73
73
  class AlgebraProblem05 < AlgebraProblem
74
74
  def solve!
75
- x = Z3::Ast.real("x")
76
- y = Z3::Ast.real("y")
75
+ x = Z3.Real("x")
76
+ y = Z3.Real("y")
77
77
  solver.assert 2*x - 4*y == 9
78
78
  solver.assert y == 0
79
79
  print_solution! "05"
@@ -86,11 +86,11 @@ class AlgebraProblem06 < AlgebraProblem
86
86
  end
87
87
 
88
88
  def solve!
89
- x1 = Z3::Ast.real("x1")
90
- y1 = Z3::Ast.real("y1")
91
- x2 = Z3::Ast.real("x2")
92
- y2 = Z3::Ast.real("y2")
93
- answer = Z3::Ast.real("answer")
89
+ x1 = Z3.Real("x1")
90
+ y1 = Z3.Real("y1")
91
+ x2 = Z3.Real("x2")
92
+ y2 = Z3.Real("y2")
93
+ answer = Z3.Real("answer")
94
94
  solver.assert x2 == 2
95
95
  solver.assert x1 == 1
96
96
  declare_f(x1, y1)
@@ -102,15 +102,15 @@ end
102
102
 
103
103
  class AlgebraProblem10 < AlgebraProblem
104
104
  def declare_abs(var, expr)
105
- solver.assert Z3::Ast.or(
106
- Z3::Ast.and(var == expr, expr >= 0),
107
- Z3::Ast.and(var == -expr, expr <= 0)
105
+ solver.assert Z3.Or(
106
+ Z3.And(var == expr, expr >= 0),
107
+ Z3.And(var == -expr, expr <= 0)
108
108
  )
109
109
  end
110
110
 
111
111
  def solve!
112
- x = Z3::Ast.real("x")
113
- y = Z3::Ast.real("|-2x + 2|")
112
+ x = Z3.Real("x")
113
+ y = Z3.Real("|-2x + 2|")
114
114
  declare_abs(y, -2*x + 2)
115
115
  solver.assert y - 3 == -3
116
116
  print_solution! "10"
@@ -3,8 +3,8 @@
3
3
  require_relative "../lib/z3"
4
4
 
5
5
  def check_multiplication_laws_1
6
- a = Z3::Ast.int("a")
7
- b = Z3::Ast.int("b")
6
+ a = Z3.Int("a")
7
+ b = Z3.Int("b")
8
8
  solver = Z3::Solver.new
9
9
  puts "Checking if (a+b)(a-b)==a*a-b*b"
10
10
  solver.prove!(
@@ -13,17 +13,17 @@ def check_multiplication_laws_1
13
13
  end
14
14
 
15
15
  def check_inequalities
16
- a = Z3::Ast.int("a")
17
- b = Z3::Ast.int("b")
16
+ a = Z3.Int("a")
17
+ b = Z3.Int("b")
18
18
  solver = Z3::Solver.new
19
19
  puts "Checking if a+b >= a"
20
- solver.prove!(a+b >= a)
20
+ solver.prove! a+b >= a
21
21
 
22
22
  solver = Z3::Solver.new
23
- solver.assert(a >= 0)
24
- solver.assert(b >= 0)
23
+ solver.assert a >= 0
24
+ solver.assert b >= 0
25
25
  puts "Checking if a+b >= a if a,b >= 0"
26
- solver.prove!(a+b >= a)
26
+ solver.prove! a+b >= a
27
27
  end
28
28
 
29
29
  check_multiplication_laws_1
data/examples/basic_logic CHANGED
@@ -3,16 +3,16 @@
3
3
  require_relative "../lib/z3"
4
4
 
5
5
  def check_if_true_is_true
6
- a = Z3::Ast.true
7
- b = Z3::Ast.true
6
+ a = Z3.True
7
+ b = Z3.True
8
8
  solver = Z3::Solver.new
9
9
  puts "Checking if true == true"
10
10
  solver.prove!(a == b)
11
11
  end
12
12
 
13
13
  def check_if_true_is_false
14
- a = Z3::Ast.true
15
- b = Z3::Ast.false
14
+ a = Z3.True
15
+ b = Z3.False
16
16
  solver = Z3::Solver.new
17
17
  puts "Checking if true == false"
18
18
  solver.prove!(a==b)
@@ -20,16 +20,16 @@ end
20
20
 
21
21
  # We prove it by checking that negation is unsatisfiable
22
22
  def check_de_morgan_law_1
23
- a = Z3::Ast::bool("a")
24
- b = Z3::Ast::bool("b")
23
+ a = Z3.Bool("a")
24
+ b = Z3.Bool("b")
25
25
  solver = Z3::Solver.new
26
26
  puts "Proving ~(a & b) == (~a | ~b)"
27
27
  solver.prove!(~(a & b) == (~a | ~b))
28
28
  end
29
29
 
30
30
  def check_de_morgan_law_2
31
- a = Z3::Ast::bool("a")
32
- b = Z3::Ast::bool("b")
31
+ a = Z3.Bool("a")
32
+ b = Z3.Bool("b")
33
33
  solver = Z3::Solver.new
34
34
  puts "Proving ~(a | b) == (~a & ~b)"
35
35
  solver.prove!(~(a | b) == (~a & ~b))
@@ -0,0 +1,161 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative "../lib/z3"
4
+
5
+ def validate_sign_by_shift!
6
+ """
7
+ sign = v >> (sizeof(int) * CHAR_BIT - 1);
8
+ """
9
+ solver = Z3::Solver.new
10
+ v = Z3.Bitvec("v", 32)
11
+ s = v >> 31
12
+ puts "Validating sign trick:"
13
+ solver.prove! ((v < 0) & (s == -1)) | ((v >= 0) & (s == 0))
14
+ end
15
+
16
+ def validate_opposite_sign_by_xor!
17
+ """
18
+ int x, y; // input values to compare signs
19
+ bool f = ((x ^ y) < 0); // true iff x and y have opposite signs
20
+ """
21
+ solver = Z3::Solver.new
22
+ x = Z3.Bitvec("x", 32)
23
+ y = Z3.Bitvec("y", 32)
24
+ f = (x^y) < 0
25
+
26
+ puts "Validating sign trick:"
27
+ solver.prove!(
28
+ 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),
33
+ )
34
+ )
35
+ end
36
+
37
+ def validate_abs_without_branching_1!
38
+ """
39
+ int v; // we want to find the absolute value of v
40
+ unsigned int r; // the result goes here
41
+ int const mask = v >> sizeof(int) * CHAR_BIT - 1;
42
+ r = (v + mask) ^ mask;
43
+ """
44
+ solver = Z3::Solver.new
45
+ v = Z3.Bitvec("v", 32)
46
+ mask = v >> 31
47
+ r = (v + mask) ^ mask
48
+ puts "Validating abs without branching, version 1"
49
+ solver.prove!(
50
+ Z3.Or(
51
+ Z3.And(v >= 0, r==v),
52
+ Z3.And(v < 0, r==-v)
53
+ )
54
+ )
55
+ end
56
+
57
+ def validate_abs_without_branching_2!
58
+ """
59
+ int v; // we want to find the absolute value of v
60
+ unsigned int r; // the result goes here
61
+ int const mask = v >> sizeof(int) * CHAR_BIT - 1;
62
+ r = (v ^ mask) - mask;
63
+ """
64
+ solver = Z3::Solver.new
65
+ v = Z3.Bitvec("v", 32)
66
+ mask = v >> 31
67
+ r = (v^mask) - mask
68
+ puts "Validating abs without branching, version 2"
69
+ solver.prove!(
70
+ Z3.Or(
71
+ Z3.And(v >= 0, r==v),
72
+ Z3.And(v < 0, r==-v)
73
+ )
74
+ )
75
+ end
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
+ def validate_min_without_branching!
89
+ """
90
+ int x; // we want to find the minimum of x and y
91
+ int y;
92
+ int r; // the result goes here
93
+ r = y ^ ((x ^ y) & -(x < y)); // min(x, y)
94
+ """
95
+ solver = Z3::Solver.new
96
+ x = Z3.Bitvec("x", 32)
97
+ y = Z3.Bitvec("y", 32)
98
+ r = y ^ ((x ^ y) & -c_boolean(solver, x < y, "t"))
99
+ puts "Validating min without branching"
100
+ solver.prove!(
101
+ Z3.Or(
102
+ Z3.And(x <= y, r == x),
103
+ Z3.And(y <= y, r == y),
104
+ )
105
+ )
106
+ end
107
+
108
+ def validate_max_without_branching!
109
+ """
110
+ int x; // we want to find the minimum of x and y
111
+ int y;
112
+ int r; // the result goes here
113
+ r = x ^ ((x ^ y) & -(x < y)); // max(x, y)
114
+ """
115
+ solver = Z3::Solver.new
116
+ x = Z3.Bitvec("x", 32)
117
+ y = Z3.Bitvec("y", 32)
118
+ r = x ^ ((x ^ y) & -c_boolean(solver, x < y, "t"))
119
+ puts "Validating max without branching"
120
+ solver.prove!(
121
+ Z3.Or(
122
+ Z3.And(x >= y, r == x),
123
+ Z3.And(y >= y, r == y),
124
+ )
125
+ )
126
+ end
127
+
128
+ def validate_is_power_of_two!
129
+ """
130
+ unsigned int v; // we want to see if v is a power of 2
131
+ bool f; // the result goes here
132
+
133
+ f = (v & (v - 1)) == 0;
134
+ """
135
+ solver = Z3::Solver.new
136
+ v = Z3.Bitvec("v", 32)
137
+ f = (v & (v - 1)) == 0
138
+
139
+ powers_of_two = (0..31).map{|i| 2**i}
140
+ naive_is_f_power_of_two = Z3.Or(*powers_of_two.map{|k| v == k})
141
+
142
+ puts "Validating is power of two"
143
+ solver.prove!(
144
+ Z3.Or(
145
+ f == naive_is_f_power_of_two,
146
+ v == 0,
147
+ )
148
+ )
149
+ end
150
+
151
+ validate_sign_by_shift!
152
+ validate_opposite_sign_by_xor!
153
+ validate_abs_without_branching_1!
154
+ validate_abs_without_branching_2!
155
+ validate_min_without_branching!
156
+ validate_max_without_branching!
157
+ validate_is_power_of_two!
158
+
159
+ """
160
+ Based on https://graphics.stanford.edu/~seander/bithacks.html
161
+ """
@@ -112,7 +112,7 @@ class Bridges
112
112
  end
113
113
 
114
114
  def int012(x, y, d)
115
- v = Z3::Ast.int("#{x},#{y},#{d}")
115
+ v = Z3.Int("#{x},#{y},#{d}")
116
116
  @solver.assert v >= 0
117
117
  @solver.assert v <= 2
118
118
  v
@@ -0,0 +1,135 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # NOTE: This is not part of integration test suite as it's fairly slow (30s or so on my machine)
4
+
5
+ require_relative "../lib/z3"
6
+
7
+ class CLogicPuzzleSolver
8
+ attr_reader :solver, :wv
9
+ def initialize
10
+ @solver = Z3::Solver.new
11
+ @digits = ["b", "c", "d", "f", "g", "h", "i", "j", "l", "n", "o", "q", "s", "t", "u", "v", "w", "x", "y", "z"]
12
+ @digit_vars = Hash[@digits.map{|v| [v, digit_var(v)]}]
13
+ @words = [
14
+ "bytwycju",
15
+ "bzuwtwol",
16
+ "cgyoyfjg",
17
+ "ctvtwysu",
18
+ "dhcqxtfw",
19
+ "diffhlnl",
20
+ "fjivucti",
21
+ "htwizvwi",
22
+ "jqxizzxq",
23
+ "niiqztgs",
24
+ "nshtztns",
25
+ "nttuhlnq",
26
+ "oigsjgoj",
27
+ "oncycbxh",
28
+ "oqbctlzh",
29
+ "oqcnwbsd",
30
+ "sfgsoxdd",
31
+ "sugvqgww",
32
+ "syhjizjq",
33
+ "szblgodf",
34
+ "thhwohwn",
35
+ "ttligxut",
36
+ "uclfqvdu",
37
+ "udluvhcz",
38
+ "ugdztnwv",
39
+ "uxztiywn",
40
+ "vugljtyn",
41
+ "vyhyjivb",
42
+ "wwnnnqbw",
43
+ "xbfziozy",
44
+ "xsvuojtx",
45
+ "yjjowdqh",
46
+ "yzdgotby",
47
+ "yzvyjjdy",
48
+ "zoljwdfl",
49
+ ]
50
+ @wv = Hash[@words.map{|w| [w, word_var(w)]}]
51
+ end
52
+
53
+ def digit_var(name)
54
+ v = Z3.Bitvec(name, 32)
55
+ solver.assert v >= 0
56
+ solver.assert v <= 9
57
+ v
58
+ end
59
+
60
+ def word_var(name)
61
+ v = Z3.Bitvec(name, 32)
62
+ digits = name.chars.map{|c| @digit_vars[c] }
63
+ val_v = digits.inject(0){|a,b| a*10+b}
64
+ solver.assert val_v == v
65
+ v
66
+ end
67
+
68
+ def solve!
69
+ # Everyone occurs twice, this is not quite that
70
+ solver.assert Z3.Add(*@digit_vars.values) == 90
71
+
72
+ # ^| operator precedence is not like Python's for some reason
73
+
74
+ solver.assert wv["bytwycju"] + wv["yzvyjjdy"] ^ wv["vugljtyn"] + wv["ugdztnwv"] | wv["xbfziozy"] == wv["bzuwtwol"]
75
+ solver.assert wv["wwnnnqbw"] - wv["uclfqvdu"] & wv["oncycbxh"] |(wv["oqcnwbsd"] ^ wv["cgyoyfjg"])== wv["vyhyjivb"]
76
+ solver.assert wv["yzdgotby"] | wv["oigsjgoj"] | wv["ttligxut"] - wv["dhcqxtfw"] & wv["szblgodf"] == wv["sfgsoxdd"]
77
+ solver.assert wv["yjjowdqh"] & wv["niiqztgs"] + wv["ctvtwysu"] & wv["diffhlnl"] - wv["thhwohwn"] == wv["xsvuojtx"]
78
+ solver.assert wv["nttuhlnq"] ^ wv["oqbctlzh"] - wv["nshtztns"] ^ wv["htwizvwi"] + wv["udluvhcz"] == wv["syhjizjq"]
79
+
80
+ solver.assert wv["bytwycju"] ^ wv["wwnnnqbw"] & wv["yzdgotby"] + wv["yjjowdqh"] - wv["nttuhlnq"] == wv["fjivucti"]
81
+ solver.assert wv["yzvyjjdy"] ^ wv["uclfqvdu"] & wv["oigsjgoj"] + wv["niiqztgs"] - wv["oqbctlzh"] == wv["zoljwdfl"]
82
+ solver.assert wv["vugljtyn"] ^ wv["oncycbxh"] & wv["ttligxut"] + wv["ctvtwysu"] - wv["nshtztns"] == wv["sugvqgww"]
83
+ solver.assert wv["ugdztnwv"] ^ wv["oqcnwbsd"] & wv["dhcqxtfw"] + wv["diffhlnl"] - wv["htwizvwi"] == wv["uxztiywn"]
84
+ solver.assert wv["xbfziozy"] ^ wv["cgyoyfjg"] & wv["szblgodf"] + wv["thhwohwn"] - wv["udluvhcz"] == wv["jqxizzxq"]
85
+
86
+ key = %W[iw hu fv lu dv cy og lc gy fq od lo fq is ig gu hs hi ds cy oo os iu fs gu lh dq lv gu iw hv gu di hs cy oc iw gc]
87
+
88
+ if solver.check == :sat
89
+ model = solver.model
90
+ model_vars = {}
91
+ model.each do |k,v|
92
+ v = v.to_s.sub(/\A#x/, "").to_i(16)
93
+ model_vars[k] = v
94
+ puts "#{k.to_s}=#{v.to_s}"
95
+ end
96
+ result = key.map do |ab|
97
+ a,b = ab.chars
98
+ av = model_vars[a]
99
+ bv = model_vars[b]
100
+ (10*av+bv).chr
101
+ end
102
+ puts "Result: #{result.join}"
103
+ else
104
+ puts "failed to solve"
105
+ end
106
+ end
107
+ end
108
+
109
+ CLogicPuzzleSolver.new.solve!
110
+
111
+ # The puzzle:
112
+ """
113
+ We've captured a strange message. It looks like it is encrypted somehow ...
114
+ iw, hu, fv, lu, dv, cy, og, lc, gy, fq, od, lo, fq, is, ig, gu, hs, hi, ds, cy, oo, os, iu, fs, gu, lh, dq, lv, gu, iw, hv, gu, di, hs, cy, oc, iw, gc
115
+
116
+
117
+ We've also intercepted what seems to be a hint to the key:
118
+ bytwycju + yzvyjjdy ^ vugljtyn + ugdztnwv | xbfziozy = bzuwtwol
119
+ ^ ^ ^ ^ ^
120
+ wwnnnqbw - uclfqvdu & oncycbxh | oqcnwbsd ^ cgyoyfjg = vyhyjivb
121
+ & & & & &
122
+ yzdgotby | oigsjgoj | ttligxut - dhcqxtfw & szblgodf = sfgsoxdd
123
+ + + + + +
124
+ yjjowdqh & niiqztgs + ctvtwysu & diffhlnl - thhwohwn = xsvuojtx
125
+ - - - - -
126
+ nttuhlnq ^ oqbctlzh - nshtztns ^ htwizvwi + udluvhcz = syhjizjq
127
+ = = = = =
128
+ fjivucti zoljwdfl sugvqgww uxztiywn jqxizzxq
129
+
130
+ Note:
131
+ assume q != 0
132
+ a letter is a decimal digit is a letter
133
+ each digit has exactly two different letter representations
134
+ C-like operator precedence
135
+ """