diff options
author | 2019-05-08 14:28:54 -0400 | |
---|---|---|
committer | 2019-05-08 14:29:59 -0400 | |
commit | a30e258a60c6619830dff8d17aed4af4763af2c6 (patch) | |
tree | fe5eb53233174e84743271a1fa02fd7310bc4691 /Solvers/VIATRA-Solver | |
parent | Interval arithmetic WIP (diff) | |
download | VIATRA-Generator-a30e258a60c6619830dff8d17aed4af4763af2c6.tar.gz VIATRA-Generator-a30e258a60c6619830dff8d17aed4af4763af2c6.tar.zst VIATRA-Generator-a30e258a60c6619830dff8d17aed4af4763af2c6.zip |
Interval arithmetic WIP
Diffstat (limited to 'Solvers/VIATRA-Solver')
3 files changed, 319 insertions, 328 deletions
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/META-INF/MANIFEST.MF b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/META-INF/MANIFEST.MF index 23e3ad13..2bc35ae6 100644 --- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/META-INF/MANIFEST.MF +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/META-INF/MANIFEST.MF | |||
@@ -4,6 +4,7 @@ Bundle-Name: Logic2viatra | |||
4 | Bundle-SymbolicName: hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatraquery;singleton:=true | 4 | Bundle-SymbolicName: hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatraquery;singleton:=true |
5 | Bundle-Version: 1.0.0.qualifier | 5 | Bundle-Version: 1.0.0.qualifier |
6 | Export-Package: hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra, | 6 | Export-Package: hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra, |
7 | hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.interval, | ||
7 | hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.patterns, | 8 | hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.patterns, |
8 | hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.queries | 9 | hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.queries |
9 | Require-Bundle: hu.bme.mit.inf.dslreasoner.logic.model;bundle-version="1.0.0", | 10 | Require-Bundle: hu.bme.mit.inf.dslreasoner.logic.model;bundle-version="1.0.0", |
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/interval/Interval.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/interval/Interval.xtend new file mode 100644 index 00000000..5b839fbd --- /dev/null +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/interval/Interval.xtend | |||
@@ -0,0 +1,318 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.interval | ||
2 | |||
3 | import java.math.BigDecimal | ||
4 | import java.math.MathContext | ||
5 | import java.math.RoundingMode | ||
6 | import org.eclipse.xtend.lib.annotations.Data | ||
7 | |||
8 | abstract class Interval { | ||
9 | static val PRECISION = 32 | ||
10 | static val ROUND_DOWN = new MathContext(PRECISION, RoundingMode.FLOOR) | ||
11 | static val ROUND_UP = new MathContext(PRECISION, RoundingMode.CEILING) | ||
12 | |||
13 | private new() { | ||
14 | } | ||
15 | |||
16 | abstract def boolean isZero() | ||
17 | |||
18 | def operator_plus() { | ||
19 | this | ||
20 | } | ||
21 | |||
22 | abstract def Interval operator_minus() | ||
23 | |||
24 | abstract def Interval operator_plus(Interval other) | ||
25 | |||
26 | abstract def Interval operator_minus(Interval other) | ||
27 | |||
28 | abstract def Interval operator_multiply(Interval other) | ||
29 | |||
30 | abstract def Interval operator_divide(Interval other) | ||
31 | |||
32 | public static val EMPTY = new Interval { | ||
33 | override isZero() { | ||
34 | false | ||
35 | } | ||
36 | |||
37 | override operator_minus() { | ||
38 | EMPTY | ||
39 | } | ||
40 | |||
41 | override operator_plus(Interval other) { | ||
42 | EMPTY | ||
43 | } | ||
44 | |||
45 | override operator_minus(Interval other) { | ||
46 | EMPTY | ||
47 | } | ||
48 | |||
49 | override operator_multiply(Interval other) { | ||
50 | EMPTY | ||
51 | } | ||
52 | |||
53 | override operator_divide(Interval other) { | ||
54 | EMPTY | ||
55 | } | ||
56 | } | ||
57 | |||
58 | public static val Interval ZERO = new NonEmpty(BigDecimal.ZERO, BigDecimal.ZERO) | ||
59 | |||
60 | public static val Interval UNBOUNDED = new NonEmpty(null, null) | ||
61 | |||
62 | @Data | ||
63 | static class NonEmpty extends Interval { | ||
64 | val BigDecimal lower | ||
65 | val BigDecimal upper | ||
66 | |||
67 | /** | ||
68 | * Construct a new non-empty interval. | ||
69 | * | ||
70 | * @param lower The lower bound of the interval. Use <code>null</code> for negative infinity. | ||
71 | * @param upper The upper bound of the interval. Use <code>null</code> for positive infinity. | ||
72 | */ | ||
73 | new(BigDecimal lower, BigDecimal upper) { | ||
74 | if (lower !== null && upper !== null && lower > upper) { | ||
75 | throw new IllegalArgumentException("Lower bound of interval must not be larger than upper bound") | ||
76 | } | ||
77 | this.lower = lower | ||
78 | this.upper = upper | ||
79 | } | ||
80 | |||
81 | override isZero() { | ||
82 | upper == BigDecimal.ZERO && lower == BigDecimal.ZERO | ||
83 | } | ||
84 | |||
85 | override operator_minus() { | ||
86 | new NonEmpty(upper?.negate(ROUND_DOWN), lower?.negate(ROUND_UP)) | ||
87 | } | ||
88 | |||
89 | override operator_plus(Interval other) { | ||
90 | switch (other) { | ||
91 | case EMPTY: EMPTY | ||
92 | NonEmpty: operator_plus(other) | ||
93 | default: throw new IllegalArgumentException("") | ||
94 | } | ||
95 | } | ||
96 | |||
97 | def operator_plus(NonEmpty other) { | ||
98 | new NonEmpty( | ||
99 | lower.tryAdd(other.lower, ROUND_DOWN), | ||
100 | upper.tryAdd(other.upper, ROUND_UP) | ||
101 | ) | ||
102 | } | ||
103 | |||
104 | private static def tryAdd(BigDecimal a, BigDecimal b, MathContext mc) { | ||
105 | if (b === null) { | ||
106 | null | ||
107 | } else { | ||
108 | a?.add(b, mc) | ||
109 | } | ||
110 | } | ||
111 | |||
112 | override operator_minus(Interval other) { | ||
113 | switch (other) { | ||
114 | case EMPTY: EMPTY | ||
115 | NonEmpty: operator_minus(other) | ||
116 | default: throw new IllegalArgumentException("") | ||
117 | } | ||
118 | } | ||
119 | |||
120 | def operator_minus(NonEmpty other) { | ||
121 | new NonEmpty( | ||
122 | lower.trySubtract(other.upper, ROUND_DOWN), | ||
123 | upper.trySubtract(other.lower, ROUND_UP) | ||
124 | ) | ||
125 | } | ||
126 | |||
127 | private static def trySubtract(BigDecimal a, BigDecimal b, MathContext mc) { | ||
128 | if (b === null) { | ||
129 | null | ||
130 | } else { | ||
131 | a?.subtract(b, mc) | ||
132 | } | ||
133 | } | ||
134 | |||
135 | override operator_multiply(Interval other) { | ||
136 | switch (other) { | ||
137 | case EMPTY: EMPTY | ||
138 | NonEmpty: operator_multiply(other) | ||
139 | default: throw new IllegalArgumentException("") | ||
140 | } | ||
141 | } | ||
142 | |||
143 | def operator_multiply(NonEmpty other) { | ||
144 | if (nonpositive) { | ||
145 | if (other.nonpositive) { | ||
146 | new NonEmpty( | ||
147 | upper.multiply(other.upper, ROUND_DOWN), | ||
148 | lower.tryMultiply(other.lower, ROUND_UP) | ||
149 | ) | ||
150 | } else if (other.nonnegative) { | ||
151 | new NonEmpty( | ||
152 | lower.tryMultiply(other.upper, ROUND_DOWN), | ||
153 | upper.multiply(other.lower, ROUND_UP) | ||
154 | ) | ||
155 | } else { | ||
156 | new NonEmpty( | ||
157 | lower.tryMultiply(other.upper, ROUND_DOWN), | ||
158 | upper.tryMultiply(other.lower, ROUND_UP) | ||
159 | ) | ||
160 | } | ||
161 | } else if (nonnegative) { | ||
162 | if (other.nonpositive) { | ||
163 | new NonEmpty( | ||
164 | upper.tryMultiply(other.lower, ROUND_DOWN), | ||
165 | lower.multiply(other.upper, ROUND_UP) | ||
166 | ) | ||
167 | } else if (other.nonnegative) { | ||
168 | new NonEmpty( | ||
169 | lower.multiply(other.lower, ROUND_DOWN), | ||
170 | upper.tryMultiply(other.upper, ROUND_UP) | ||
171 | ) | ||
172 | } else { | ||
173 | new NonEmpty( | ||
174 | upper.tryMultiply(other.lower, ROUND_DOWN), | ||
175 | upper.tryMultiply(other.upper, ROUND_UP) | ||
176 | ) | ||
177 | } | ||
178 | } else { | ||
179 | if (other.nonpositive) { | ||
180 | new NonEmpty( | ||
181 | upper.tryMultiply(other.lower, ROUND_DOWN), | ||
182 | lower.tryMultiply(other.lower, ROUND_UP) | ||
183 | ) | ||
184 | } else if (other.nonnegative) { | ||
185 | new NonEmpty( | ||
186 | lower.tryMultiply(other.upper, ROUND_DOWN), | ||
187 | upper.tryMultiply(other.upper, ROUND_UP) | ||
188 | ) | ||
189 | } else { | ||
190 | new NonEmpty( | ||
191 | lower.tryMultiply(other.upper, ROUND_DOWN).tryMin(upper.tryMultiply(other.lower, ROUND_DOWN)), | ||
192 | lower.tryMultiply(other.lower, ROUND_UP).tryMax(upper.tryMultiply(other.upper, ROUND_UP)) | ||
193 | ) | ||
194 | } | ||
195 | } | ||
196 | } | ||
197 | |||
198 | private def isNonpositive() { | ||
199 | upper !== null && upper <= BigDecimal.ZERO | ||
200 | } | ||
201 | |||
202 | private def isNonnegative() { | ||
203 | lower !== null && lower >= BigDecimal.ZERO | ||
204 | } | ||
205 | |||
206 | private static def tryMultiply(BigDecimal a, BigDecimal b, MathContext mc) { | ||
207 | if (b === null) { | ||
208 | null | ||
209 | } else { | ||
210 | a?.multiply(b, mc) | ||
211 | } | ||
212 | } | ||
213 | |||
214 | private static def tryMin(BigDecimal a, BigDecimal b) { | ||
215 | if (b === null) { | ||
216 | null | ||
217 | } else { | ||
218 | a?.min(b) | ||
219 | } | ||
220 | } | ||
221 | |||
222 | private static def tryMax(BigDecimal a, BigDecimal b) { | ||
223 | if (b === null) { | ||
224 | null | ||
225 | } else { | ||
226 | a?.max(b) | ||
227 | } | ||
228 | } | ||
229 | |||
230 | override operator_divide(Interval other) { | ||
231 | switch (other) { | ||
232 | case EMPTY: EMPTY | ||
233 | NonEmpty: operator_divide(other) | ||
234 | default: throw new IllegalArgumentException("") | ||
235 | } | ||
236 | } | ||
237 | |||
238 | def operator_divide(NonEmpty other) { | ||
239 | if (other.strictlyNegative) { | ||
240 | if (nonpositive) { | ||
241 | new NonEmpty( | ||
242 | upper.tryDivide(other.lower, ROUND_DOWN), | ||
243 | lower.tryDivide(other.upper, ROUND_UP) | ||
244 | ) | ||
245 | } else if (nonnegative) { | ||
246 | new NonEmpty( | ||
247 | upper.tryDivide(other.upper, ROUND_DOWN), | ||
248 | lower.tryDivide(other.lower, ROUND_UP) | ||
249 | ) | ||
250 | } else { // lower < 0 < upper | ||
251 | new NonEmpty( | ||
252 | upper.tryDivide(other.upper, ROUND_DOWN), | ||
253 | lower.tryDivide(other.upper, ROUND_UP) | ||
254 | ) | ||
255 | } | ||
256 | } else if (other.strictlyPositive) { | ||
257 | if (nonpositive) { | ||
258 | new NonEmpty( | ||
259 | lower.tryDivide(other.lower, ROUND_DOWN), | ||
260 | upper.tryDivide(other.upper, ROUND_UP) | ||
261 | ) | ||
262 | } else if (nonnegative) { | ||
263 | new NonEmpty( | ||
264 | lower.tryDivide(other.upper, ROUND_DOWN), | ||
265 | upper.tryDivide(other.lower, ROUND_UP) | ||
266 | ) | ||
267 | } else { // lower < 0 < upper | ||
268 | new NonEmpty( | ||
269 | lower.tryDivide(other.lower, ROUND_DOWN), | ||
270 | upper.tryDivide(other.lower, ROUND_UP) | ||
271 | ) | ||
272 | } | ||
273 | } else { // other contains 0 | ||
274 | if (other.lower == BigDecimal.ZERO) { | ||
275 | if (other.upper == BigDecimal.ZERO) { // [0, 0] | ||
276 | EMPTY | ||
277 | } else { // 0 == other.lower < other.upper | ||
278 | if (nonpositive) { | ||
279 | new NonEmpty(null, upper.tryDivide(other.upper, ROUND_UP)) | ||
280 | } else if (nonnegative) { | ||
281 | new NonEmpty(lower.tryDivide(other.upper, ROUND_DOWN), null) | ||
282 | } else { // lower < 0 < upper | ||
283 | UNBOUNDED | ||
284 | } | ||
285 | } | ||
286 | } else { | ||
287 | if (other.upper == BigDecimal.ZERO) { // other.lower < other.upper == 0 | ||
288 | if (nonpositive) { | ||
289 | new NonEmpty(upper.tryDivide(other.lower, ROUND_DOWN), null) | ||
290 | } else if (nonnegative) { | ||
291 | new NonEmpty(null, lower.tryDivide(other.lower, ROUND_UP)) | ||
292 | } else { // lower < 0 < upper | ||
293 | UNBOUNDED | ||
294 | } | ||
295 | } else { // other.lower < 0 < other.upper | ||
296 | UNBOUNDED | ||
297 | } | ||
298 | } | ||
299 | } | ||
300 | } | ||
301 | |||
302 | private def isStrictlyNegative() { | ||
303 | upper !== null && upper < BigDecimal.ZERO | ||
304 | } | ||
305 | |||
306 | private def isStrictlyPositive() { | ||
307 | lower !== null && lower > BigDecimal.ZERO | ||
308 | } | ||
309 | |||
310 | private static def tryDivide(BigDecimal a, BigDecimal b, MathContext mc) { | ||
311 | if (b === null) { | ||
312 | BigDecimal.ZERO | ||
313 | } else { | ||
314 | a?.divide(b, mc) | ||
315 | } | ||
316 | } | ||
317 | } | ||
318 | } | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/interval/Interval.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/interval/Interval.xtend deleted file mode 100644 index 6d77e77a..00000000 --- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/interval/Interval.xtend +++ /dev/null | |||
@@ -1,328 +0,0 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.interval | ||
2 | |||
3 | import java.math.BigDecimal | ||
4 | import java.math.MathContext | ||
5 | import java.math.RoundingMode | ||
6 | import org.eclipse.xtend.lib.annotations.Data | ||
7 | |||
8 | abstract class Interval { | ||
9 | static val PRECISION = 32 | ||
10 | static val ROUND_DOWN = new MathContext(PRECISION, RoundingMode.FLOOR) | ||
11 | static val ROUND_UP = new MathContext(PRECISION, RoundingMode.CEILING) | ||
12 | |||
13 | private new() { | ||
14 | } | ||
15 | |||
16 | def abstract boolean isEmpty() | ||
17 | |||
18 | def abstract boolean hasPositivePart() | ||
19 | |||
20 | def abstract boolean hasNegativePart() | ||
21 | |||
22 | def operator_plus() { | ||
23 | this | ||
24 | } | ||
25 | |||
26 | abstract def Interval operator_minus() | ||
27 | |||
28 | abstract def Interval operator_plus(Interval other) | ||
29 | |||
30 | def operator_minus(Interval other) { | ||
31 | this + (-other) | ||
32 | } | ||
33 | |||
34 | abstract def Interval operator_multiply(Interval other) | ||
35 | |||
36 | abstract def Interval operator_divide(Interval other) | ||
37 | |||
38 | static val EMPTY = new Interval { | ||
39 | override boolean isEmpty() { | ||
40 | true | ||
41 | } | ||
42 | |||
43 | override boolean hasPositivePart() { | ||
44 | false | ||
45 | } | ||
46 | |||
47 | override boolean hasNegativePart() { | ||
48 | false | ||
49 | } | ||
50 | |||
51 | override operator_minus() { | ||
52 | EMPTY | ||
53 | } | ||
54 | |||
55 | override operator_plus(Interval other) { | ||
56 | EMPTY | ||
57 | } | ||
58 | |||
59 | override operator_multiply(Interval other) { | ||
60 | EMPTY | ||
61 | } | ||
62 | |||
63 | override operator_divide(Interval other) { | ||
64 | EMPTY | ||
65 | } | ||
66 | } | ||
67 | |||
68 | static val ZERO = new Bounded(BigDecimal.ZERO, BigDecimal.ZERO) | ||
69 | |||
70 | static val UNBOUNDED = new Interval { | ||
71 | override boolean isEmpty() { | ||
72 | true | ||
73 | } | ||
74 | |||
75 | override boolean hasPositivePart() { | ||
76 | true | ||
77 | } | ||
78 | |||
79 | override boolean hasNegativePart() { | ||
80 | true | ||
81 | } | ||
82 | |||
83 | override operator_minus() { | ||
84 | UNBOUNDED | ||
85 | } | ||
86 | |||
87 | override operator_plus(Interval other) { | ||
88 | if (other.empty) { | ||
89 | EMPTY | ||
90 | } else { | ||
91 | UNBOUNDED | ||
92 | } | ||
93 | } | ||
94 | |||
95 | override operator_multiply(Interval other) { | ||
96 | if (other.empty) { | ||
97 | EMPTY | ||
98 | } else if (other.hasPositivePart || other.hasNegativePart) { | ||
99 | UNBOUNDED | ||
100 | } else { | ||
101 | ZERO | ||
102 | } | ||
103 | } | ||
104 | |||
105 | override operator_divide(Interval other) { | ||
106 | if (other.hasPositivePart || other.hasNegativePart) { | ||
107 | UNBOUNDED | ||
108 | } else { | ||
109 | EMPTY | ||
110 | } | ||
111 | } | ||
112 | } | ||
113 | |||
114 | @Data | ||
115 | static class BoundedFromBelow extends Interval { | ||
116 | val BigDecimal lower | ||
117 | |||
118 | override isEmpty() { | ||
119 | false | ||
120 | } | ||
121 | |||
122 | override hasPositivePart() { | ||
123 | true | ||
124 | } | ||
125 | |||
126 | override hasNegativePart() { | ||
127 | lower < BigDecimal.ZERO | ||
128 | } | ||
129 | |||
130 | override operator_minus() { | ||
131 | new BoundedFromAbove(lower.negate(ROUND_UP)) | ||
132 | } | ||
133 | |||
134 | override operator_plus(Interval other) { | ||
135 | switch (other) { | ||
136 | BoundedFromBelow: | ||
137 | new BoundedFromBelow(lower.add(other.lower, ROUND_DOWN)) | ||
138 | BoundedFromAbove: | ||
139 | UNBOUNDED | ||
140 | Bounded: | ||
141 | new BoundedFromBelow(lower.add(other.lower, ROUND_DOWN)) | ||
142 | default: | ||
143 | other + this | ||
144 | } | ||
145 | } | ||
146 | |||
147 | override operator_multiply(Interval other) { | ||
148 | switch (other) { | ||
149 | BoundedFromBelow: | ||
150 | if (hasNegativePart || other.hasNegativePart) { | ||
151 | UNBOUNDED | ||
152 | } else { | ||
153 | new BoundedFromBelow(lower.multiply(other.lower, ROUND_DOWN)) | ||
154 | } | ||
155 | BoundedFromAbove: | ||
156 | if (hasNegativePart || other.hasPositivePart) { | ||
157 | UNBOUNDED | ||
158 | } else { | ||
159 | new BoundedFromAbove(lower.multiply(other.upper, ROUND_UP)) | ||
160 | } | ||
161 | Bounded: | ||
162 | if (other.hasNegativePart) { | ||
163 | if (other.hasPositivePart) { | ||
164 | UNBOUNDED | ||
165 | } else { | ||
166 | if (lower < BigDecimal.ZERO) { | ||
167 | new BoundedFromAbove(lower.multiply(other.lower, ROUND_UP)) | ||
168 | } else { | ||
169 | new BoundedFromAbove(lower.multiply(other.upper, ROUND_UP)) | ||
170 | } | ||
171 | } | ||
172 | } else { | ||
173 | if (other.hasPositivePart) { | ||
174 | if (lower < BigDecimal.ZERO) { | ||
175 | new BoundedFromBelow(lower.multiply(other.lower, ROUND_DOWN)) | ||
176 | } else { | ||
177 | new BoundedFromBelow(lower.multiply(other.upper, ROUND_DOWN)) | ||
178 | } | ||
179 | } else { | ||
180 | ZERO | ||
181 | } | ||
182 | } | ||
183 | default: | ||
184 | other * this | ||
185 | } | ||
186 | } | ||
187 | |||
188 | override operator_divide(Interval other) { | ||
189 | throw new UnsupportedOperationException("TODO: auto-generated method stub") | ||
190 | } | ||
191 | |||
192 | } | ||
193 | |||
194 | @Data | ||
195 | static class BoundedFromAbove extends Interval { | ||
196 | val BigDecimal upper | ||
197 | |||
198 | override isEmpty() { | ||
199 | false | ||
200 | } | ||
201 | |||
202 | override hasPositivePart() { | ||
203 | upper > BigDecimal.ZERO | ||
204 | } | ||
205 | |||
206 | override hasNegativePart() { | ||
207 | true | ||
208 | } | ||
209 | |||
210 | override operator_minus() { | ||
211 | new BoundedFromBelow(upper.negate(ROUND_DOWN)) | ||
212 | } | ||
213 | |||
214 | override operator_plus(Interval other) { | ||
215 | switch (other) { | ||
216 | BoundedFromAbove: | ||
217 | UNBOUNDED | ||
218 | Bounded: | ||
219 | new BoundedFromAbove(upper.add(other.upper, ROUND_UP)) | ||
220 | default: | ||
221 | other + this | ||
222 | } | ||
223 | } | ||
224 | |||
225 | override operator_multiply(Interval other) { | ||
226 | switch (other) { | ||
227 | BoundedFromAbove: | ||
228 | if (hasPositivePart || other.hasPositivePart) { | ||
229 | UNBOUNDED | ||
230 | } else { | ||
231 | new BoundedFromBelow(upper.multiply(other.upper, ROUND_DOWN)) | ||
232 | } | ||
233 | Bounded: | ||
234 | if (other.hasPositivePart) { | ||
235 | if (other.hasNegativePart) { | ||
236 | UNBOUNDED | ||
237 | } else { | ||
238 | if (upper < BigDecimal.ZERO) { | ||
239 | new BoundedFromAbove(upper.multiply(other.lower, ROUND_UP)) | ||
240 | } else { | ||
241 | new BoundedFromAbove(upper.multiply(other.upper, ROUND_UP)) | ||
242 | } | ||
243 | } | ||
244 | } else { | ||
245 | if (other.hasNegativePart) { | ||
246 | if (upper < BigDecimal.ZERO) { | ||
247 | new BoundedFromBelow(upper.multiply(other.lower, ROUND_DOWN)) | ||
248 | } else { | ||
249 | new BoundedFromBelow(upper.multiply(other.upper, ROUND_DOWN)) | ||
250 | } | ||
251 | } else { | ||
252 | ZERO | ||
253 | } | ||
254 | } | ||
255 | default: | ||
256 | other * this | ||
257 | } | ||
258 | } | ||
259 | |||
260 | override operator_divide(Interval other) { | ||
261 | throw new UnsupportedOperationException("TODO: auto-generated method stub") | ||
262 | } | ||
263 | |||
264 | } | ||
265 | |||
266 | @Data | ||
267 | static class Bounded extends Interval { | ||
268 | val BigDecimal lower | ||
269 | val BigDecimal upper | ||
270 | |||
271 | new(BigDecimal lower, BigDecimal upper) { | ||
272 | if (lower === null) { | ||
273 | throw new IllegalArgumentException("Lower bound must be a number") | ||
274 | } | ||
275 | if (upper === null) { | ||
276 | throw new IllegalArgumentException("Upper bound must be a number") | ||
277 | } | ||
278 | if (lower > upper) { | ||
279 | throw new IllegalArgumentException("Lower bound of interval must not be larger than upper bound") | ||
280 | } | ||
281 | this.lower = lower | ||
282 | this.upper = upper | ||
283 | } | ||
284 | |||
285 | override boolean isEmpty() { | ||
286 | false | ||
287 | } | ||
288 | |||
289 | override boolean hasPositivePart() { | ||
290 | upper > BigDecimal.ZERO | ||
291 | } | ||
292 | |||
293 | override boolean hasNegativePart() { | ||
294 | lower < BigDecimal.ZERO | ||
295 | } | ||
296 | |||
297 | override operator_minus() { | ||
298 | new Bounded(upper.negate(ROUND_DOWN), lower.negate(ROUND_UP)) | ||
299 | } | ||
300 | |||
301 | override operator_plus(Interval other) { | ||
302 | if (other instanceof Bounded) { | ||
303 | new Bounded(lower.add(other.lower, ROUND_DOWN), upper.add(other.upper, ROUND_UP)) | ||
304 | } else { | ||
305 | other + this | ||
306 | } | ||
307 | } | ||
308 | |||
309 | override operator_multiply(Interval other) { | ||
310 | if (other instanceof Bounded) { | ||
311 | // TODO | ||
312 | } else { | ||
313 | other * this | ||
314 | } | ||
315 | } | ||
316 | |||
317 | override operator_divide(Interval other) { | ||
318 | switch (other) { | ||
319 | case EMPTY: | ||
320 | EMPTY | ||
321 | Interval.Bounded: | ||
322 | throw new UnsupportedOperationException("TODO") | ||
323 | default: | ||
324 | throw new IllegalArgumentException("Unknown interval: " + other) | ||
325 | } | ||
326 | } | ||
327 | } | ||
328 | } | ||