OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 import 'package:compiler/src/cps_ir/octagon.dart'; |
| 6 import 'package:expect/expect.dart'; |
| 7 |
| 8 Octagon octagon; |
| 9 SignedVariable v1, v2, v3, v4; |
| 10 |
| 11 setup() { |
| 12 octagon = new Octagon(); |
| 13 v1 = octagon.makeVariable(); |
| 14 v2 = octagon.makeVariable(); |
| 15 v3 = octagon.makeVariable(); |
| 16 v4 = octagon.makeVariable(); |
| 17 } |
| 18 |
| 19 Constraint pushConstraint(SignedVariable w1, SignedVariable w2, int k) { |
| 20 Constraint c = new Constraint(w1, w2, k); |
| 21 octagon.pushConstraint(c); |
| 22 return c; |
| 23 } |
| 24 |
| 25 void popConstraint(Constraint c) { |
| 26 octagon.popConstraint(c); |
| 27 } |
| 28 |
| 29 negative_loop1() { |
| 30 setup(); |
| 31 // Create the contradictory constraint: |
| 32 // v1 <= v2 <= v1 - 1 (loop weight = -1) |
| 33 // |
| 34 // As difference bounds: |
| 35 // v1 - v2 <= 0 |
| 36 // v2 - v1 <= -1 |
| 37 pushConstraint(v1, v2.negated, 0); |
| 38 Expect.isTrue(octagon.isSolvable, 'v1 <= v2: should be solvable'); |
| 39 var c = pushConstraint(v2, v1.negated, -1); |
| 40 Expect.isTrue(octagon.isUnsolvable, 'v2 <= v1 - 1: should become unsolvable'); |
| 41 |
| 42 // Check that pop restores solvability. |
| 43 popConstraint(c); |
| 44 Expect.isTrue(octagon.isSolvable, 'Should be solvable without v2 <= v1 - 1'); |
| 45 } |
| 46 |
| 47 negative_loop2() { |
| 48 setup(); |
| 49 // Create a longer contradiction, and add the middle constraint last: |
| 50 // v1 <= v2 <= v3 <= v1 - 1 |
| 51 pushConstraint(v1, v2.negated, 0); |
| 52 Expect.isTrue(octagon.isSolvable, 'v1 <= v2: should be solvable'); |
| 53 pushConstraint(v3, v1.negated, -1); |
| 54 Expect.isTrue(octagon.isSolvable, 'v3 <= v1 - 1: should be solvable'); |
| 55 var c = pushConstraint(v2, v3.negated, 0); |
| 56 Expect.isTrue(octagon.isUnsolvable, 'v2 <= v3: should become unsolvable'); |
| 57 |
| 58 // Check that pop restores solvability. |
| 59 popConstraint(c); |
| 60 Expect.isTrue(octagon.isSolvable, 'Should be solvable without v2 <= v3'); |
| 61 } |
| 62 |
| 63 negative_loop3() { |
| 64 setup(); |
| 65 // Add a circular constraint with offsets and negative weight: |
| 66 // v1 <= v2 - 1 <= v3 + 2 <= v1 - 1 |
| 67 // As difference bounds: |
| 68 // v1 - v2 <= -1 |
| 69 // v2 - v3 <= 3 |
| 70 // v3 - v1 <= -3 |
| 71 pushConstraint(v1, v2.negated, -1); |
| 72 Expect.isTrue(octagon.isSolvable, 'v1 <= v2 - 1: should be solvable'); |
| 73 pushConstraint(v2, v3.negated, 3); |
| 74 Expect.isTrue(octagon.isSolvable, 'v2 - 1 <= v3 + 2: should be solvable'); |
| 75 var c = pushConstraint(v3, v1.negated, -3); |
| 76 Expect.isTrue(octagon.isUnsolvable, 'v3 + 2 <= v1 - 1: should become unsolvabl
e'); |
| 77 |
| 78 // Check that pop restores solvability. |
| 79 popConstraint(c); |
| 80 Expect.isTrue(octagon.isSolvable, 'Should be solvable without v3 + 2 <= v1 - 1
'); |
| 81 } |
| 82 |
| 83 zero_loop1() { |
| 84 setup(); |
| 85 // Add the circular constraint with zero weight: |
| 86 // v1 <= v2 <= v3 <= v1 |
| 87 pushConstraint(v1, v2.negated, 0); |
| 88 Expect.isTrue(octagon.isSolvable, 'v1 <= v2: should be solvable'); |
| 89 pushConstraint(v2, v3.negated, 0); |
| 90 Expect.isTrue(octagon.isSolvable, 'v2 <= v3: should be solvable'); |
| 91 pushConstraint(v3, v1.negated, 0); |
| 92 Expect.isTrue(octagon.isSolvable, 'v3 <= v1: should be solvable'); |
| 93 } |
| 94 |
| 95 zero_loop2() { |
| 96 setup(); |
| 97 // Add a circular constraint with offsets: |
| 98 // v1 <= v2 - 1 <= v3 + 2 <= v1 |
| 99 // As difference bounds: |
| 100 // v1 - v2 <= -1 |
| 101 // v2 - v3 <= 3 |
| 102 // v3 - v1 <= -2 |
| 103 pushConstraint(v1, v2.negated, -1); |
| 104 Expect.isTrue(octagon.isSolvable, 'v1 <= v2 - 1: should be solvable'); |
| 105 pushConstraint(v2, v3.negated, 3); |
| 106 Expect.isTrue(octagon.isSolvable, 'v2 - 1 <= v3 + 2: should be solvable'); |
| 107 pushConstraint(v3, v1.negated, -2); |
| 108 Expect.isTrue(octagon.isSolvable, 'v3 + 2 <= v1: should be solvable'); |
| 109 } |
| 110 |
| 111 positive_loop1() { |
| 112 setup(); |
| 113 // Add constraints with some slack (positive-weight loop): |
| 114 // v1 <= v2 <= v3 <= v1 + 1 |
| 115 pushConstraint(v1, v2.negated, 0); |
| 116 Expect.isTrue(octagon.isSolvable, 'v1 <= v2: should be solvable'); |
| 117 pushConstraint(v2, v3.negated, 0); |
| 118 Expect.isTrue(octagon.isSolvable, 'v2 <= v3: should be solvable'); |
| 119 pushConstraint(v3, v1.negated, 1); |
| 120 Expect.isTrue(octagon.isSolvable, 'v3 <= v1 + 1: should be solvable'); |
| 121 } |
| 122 |
| 123 positive_loop2() { |
| 124 setup(); |
| 125 // Add constraints with offsets and slack at the end: |
| 126 // v1 <= v2 - 1 <= v3 + 2 <= v1 + 1 |
| 127 // As difference bounds: |
| 128 // v1 - v2 <= -1 |
| 129 // v2 - v3 <= 3 |
| 130 // v3 - v1 <= -1 |
| 131 pushConstraint(v1, v2.negated, -1); |
| 132 Expect.isTrue(octagon.isSolvable, 'v1 <= v2 - 1: should be solvable'); |
| 133 pushConstraint(v2, v3.negated, 3); |
| 134 Expect.isTrue(octagon.isSolvable, 'v2 - 1 <= v3 + 2: should be solvable'); |
| 135 pushConstraint(v3, v1.negated, -1); |
| 136 Expect.isTrue(octagon.isSolvable, 'v3 + 2 <= v1: should be solvable'); |
| 137 } |
| 138 |
| 139 positive_and_negative_loops1() { |
| 140 setup(); |
| 141 // v1 <= v2 <= v3 <= v1 + 1 |
| 142 // v2 <= v3 - 2 (unsolvable: v3 - 2 <= (v1 + 1) - 2 = v1 - 1) |
| 143 pushConstraint(v1, v2.negated, 0); |
| 144 pushConstraint(v2, v3.negated, 0); |
| 145 pushConstraint(v3, v1.negated, 1); |
| 146 Expect.isTrue(octagon.isSolvable, 'should be solvable'); |
| 147 pushConstraint(v2, v3.negated, -2); |
| 148 Expect.isTrue(octagon.isUnsolvable, 'v2 <= v3 - 2: should become unsolvable'); |
| 149 } |
| 150 |
| 151 positive_and_negative_loops2() { |
| 152 setup(); |
| 153 // Same as above, but constraints are added in a different order. |
| 154 pushConstraint(v2, v3.negated, -2); |
| 155 pushConstraint(v2, v3.negated, 0); |
| 156 pushConstraint(v3, v1.negated, 1); |
| 157 Expect.isTrue(octagon.isSolvable, 'should be solvable'); |
| 158 pushConstraint(v1, v2.negated, 0); |
| 159 Expect.isTrue(octagon.isUnsolvable, 'v1 <= v2: should become unsolvable'); |
| 160 } |
| 161 |
| 162 positive_and_negative_loops3() { |
| 163 setup(); |
| 164 // Same as above, but constraints are added in a different order. |
| 165 pushConstraint(v2, v3.negated, 0); |
| 166 pushConstraint(v2, v3.negated, -2); |
| 167 pushConstraint(v3, v1.negated, 1); |
| 168 Expect.isTrue(octagon.isSolvable, 'should be solvable'); |
| 169 pushConstraint(v1, v2.negated, 0); |
| 170 Expect.isTrue(octagon.isUnsolvable, 'v1 <= v2: should become unsolvable'); |
| 171 } |
| 172 |
| 173 plus_minus1() { |
| 174 setup(); |
| 175 // Given: |
| 176 // v1 = v2 + 1 (modeled as: v1 <= v2 + 1 <= v1) |
| 177 // v3 = v4 + 1 |
| 178 // v1 <= v3 |
| 179 // prove: |
| 180 // v2 <= v4 |
| 181 pushConstraint(v1, v2.negated, 1); // v1 <= v2 + 1 |
| 182 pushConstraint(v2, v1.negated, -1); // v2 <= v1 - 1 |
| 183 pushConstraint(v3, v4.negated, 1); // v3 <= v4 + 1 |
| 184 pushConstraint(v4, v3.negated, -1); // v4 <= v3 - 1 |
| 185 pushConstraint(v1, v3.negated, 0); // v1 <= v3 |
| 186 Expect.isTrue(octagon.isSolvable, 'should be solvable'); |
| 187 // Push the negated constraint: v2 > v4 <=> v4 - v2 <= -1 |
| 188 pushConstraint(v4, v2.negated, -1); |
| 189 Expect.isTrue(octagon.isUnsolvable, 'should be unsolvable'); |
| 190 } |
| 191 |
| 192 constant1() { |
| 193 setup(); |
| 194 // Given: |
| 195 // v1 = 10 |
| 196 // v2 <= v3 |
| 197 // v3 + v1 <= 3 (i.e. v2 <= v3 <= -v1 + 3 = 7) |
| 198 // prove: |
| 199 // v2 <= 7 (modeled as: v2 + v2 <= 14) |
| 200 pushConstraint(v1, v1, 20); // v1 + v1 <= 20 |
| 201 pushConstraint(v1.negated, v1.negated, -20); // -v1 - v1 <= -20 |
| 202 pushConstraint(v2, v3.negated, 0); // v2 <= v3 |
| 203 pushConstraint(v3, v1, 3); // v3 + v1 <= 3 |
| 204 Expect.isTrue(octagon.isSolvable, 'should be solvable'); |
| 205 // Push the negated constraint: v2 + v2 > 14 <=> -v2 - v2 <= -15 |
| 206 var c = pushConstraint(v2.negated, v2.negated, -15); |
| 207 Expect.isTrue(octagon.isUnsolvable, 'should be unsolvable'); |
| 208 popConstraint(c); |
| 209 // Push the thing we are trying to prove. |
| 210 pushConstraint(v2, v2, 14); |
| 211 Expect.isTrue(octagon.isSolvable, 'v2 + v2 <= 14: should be solvable'); |
| 212 } |
| 213 |
| 214 contradict1() { |
| 215 setup(); |
| 216 // v1 < v1 (v1 - v1 <= -1) |
| 217 pushConstraint(v1, v1.negated, -1); |
| 218 Expect.isTrue(octagon.isUnsolvable, 'v1 < v1: should be unsolvable'); |
| 219 } |
| 220 |
| 221 contradict2() { |
| 222 setup(); |
| 223 // v1 = 2 |
| 224 // v2 = 0 |
| 225 // v1 <= v2 |
| 226 pushConstraint(v1, v1, 2); |
| 227 pushConstraint(v1.negated, v1.negated, -2); |
| 228 pushConstraint(v2, v2, 0); |
| 229 pushConstraint(v2.negated, v2.negated, 0); |
| 230 Expect.isTrue(octagon.isSolvable, 'should be solvable'); |
| 231 pushConstraint(v1, v2.negated, 0); |
| 232 Expect.isTrue(octagon.isUnsolvable, 'v1 <= v2: should be unsolvable'); |
| 233 } |
| 234 |
| 235 lower_bounds_check() { |
| 236 SignedVariable w = octagon.makeVariable(0, 1000); |
| 237 pushConstraint(w, w, -1); |
| 238 Expect.isTrue(octagon.isUnsolvable, 'Value in range 0..1000 is not <= -1'); |
| 239 } |
| 240 |
| 241 upper_bounds_check() { |
| 242 SignedVariable w = octagon.makeVariable(0, 1000); |
| 243 pushConstraint(w.negated, w.negated, -5000); |
| 244 Expect.isTrue(octagon.isUnsolvable, 'Value in range 0..1000 is not >= 5000'); |
| 245 } |
| 246 |
| 247 void main() { |
| 248 negative_loop1(); |
| 249 negative_loop2(); |
| 250 negative_loop3(); |
| 251 zero_loop1(); |
| 252 zero_loop2(); |
| 253 positive_loop1(); |
| 254 positive_loop2(); |
| 255 positive_and_negative_loops1(); |
| 256 positive_and_negative_loops2(); |
| 257 positive_and_negative_loops3(); |
| 258 plus_minus1(); |
| 259 constant1(); |
| 260 contradict1(); |
| 261 contradict2(); |
| 262 lower_bounds_check(); |
| 263 upper_bounds_check(); |
| 264 } |
OLD | NEW |