1:- module(interval, [interval/2, op(150, xfx, ...)]). 2
3:- multifile int_hook/2. 4:- multifile eval_hook/2. 5:- multifile mono/2. 6
7:- discontiguous interval/2. 8:- discontiguous int_hook/2. 9
10:- set_prolog_flag(float_overflow, infinity). 11:- set_prolog_flag(float_undefined, nan). 12:- set_prolog_flag(float_zero_div, infinity).
40interval(L...U, Res)
41 => Res = L...U.
42
48
49interval(atomic(A), Res)
50 => eval(A, R),
51 Res = atomic(R).
52
63interval(Expr, Res),
64 compound(Expr),
65 compound_name_arguments(Expr, Name, Args),
66 int_hook(Name, Mask),
67 compound_name_arguments(Mask, Fun, Args1),
68 maplist(instantiate, Args1, Args2),
69 maplist(interval, Args, Args2)
70 => compound_name_arguments(Goal, Fun, Args2),
71 call(Goal, Res).
72
73instantiate(atomic, atomic(_)).
74instantiate(..., _..._).
75instantiate(ci, ci(_, _)).
84mono((+)/1, [+]).
85mono((+)/2, [+, +]).
86mono((-)/1, [-]).
87mono((-)/2, [+, -]).
88mono((*)/2, **).
89mono((^)/2, [*, /]).
90
92interval(Expr, Res),
93 compound(Expr),
94 compound_name_arity(Expr, Name, Arity),
95 mono(Name/Arity, **)
96 => compound_name_arguments(Expr, Name, Args),
97 maplist(interval, Args, Args1),
98 findall(R, both(Name, Args1, R), Bounds),
99 min_list(Bounds, L),
100 max_list(Bounds, U),
101 Res = L...U.
102
104interval(Expr, Res),
105 compound(Expr),
106 compound_name_arity(Expr, Name, Arity),
107 mono(Name/Arity, Dir)
108 => compound_name_arguments(Expr, Name, Args),
109 maplist(interval, Args, Args1),
110 findall(R, lower(Dir, Name, Args1, R), Lower),
111 min_list(Lower, L),
112 findall(R, upper(Dir, Name, Args1, R), Upper),
113 max_list(Upper, U),
114 Res = L...U.
115
116lower(Dir, Name, Args, Res) :-
117 maplist(lower, Dir, Args, Lower),
118 Expr =.. [Name | Lower],
119 eval(Expr, Res).
120
121upper(Dir, Name, Args, Res) :-
122 maplist(upper, Dir, Args, Upper),
123 Expr =.. [Name | Upper],
124 eval(Expr, Res).
125
126both(Name, Args, Res) :-
127 maplist(lower(*), Args, Lower),
128 Expr =.. [Name | Lower],
129 eval(Expr, Res).
130
132lower(+, A..._, L)
133 => L = A.
134
135lower(-, _...A, L)
136 => L = A.
137
138lower(*, A...B, L)
139 => L = A ; L = B.
140
141lower(_, A, L) 142 => L = A.
143
144upper(+, _...B, U)
145 => U = B.
146
147upper(-, A..._, U)
148 => U = A.
149
150upper(*, A...B, U)
151 => U = A ; U = B.
152
153upper(_, A, U)
154 => U = A.
155
161eval(Expr, Res),
162 eval_hook(Expr, R)
163 => Res = R.
164
165eval(X, Res)
166 => Res is X.
167
171int_hook(<, less1(atomic, atomic)).
172
173less1(atomic(A), atomic(B), Res) :-
174 A < B,
175 !,
176 Res = true.
177
178less1(atomic(_) < atomic(_), Res) :-
179 !,
180 Res = false.
181
182int_hook(<, less2(..., ...)).
183
184less2(_...A2, B1..._, Res) :-
185 A2 < B1,
186 !,
187 Res = true.
188
189less2(_..._, _..._, false2).
190
191int_hook(=<, less_eq(..., ...)).
192
193less_eq(A1..._, _...B2, Res) :-
194 A1 =< B2,
195 !,
196 Res = true.
197
198less_eq(_..._, _..._, false).
199
200int_hook(>, great(..., ...)).
201great(A1..._, _...B2, Res) :-
202 A1 > B2,
203 !,
204 Res = true.
205
206great(_..._, _..._, false).
207
208int_hook(>=, great_eq(..., ...)).
209great_eq(_...A2, B1..._, Res) :-
210 A2 >= B1,
211 !,
212 Res = true.
213
214great_eq(_..._, _..._, false).
215
216
217int_hook(=\=, not_eq(..., ...)).
218not_eq(A...B, C...D, Res) :-
219 ( less2(A...B, C...D, true)
220 ; great(A...B, C...D, true)
221 ), !,
222 Res = true.
223
224not_eq(_..._, _..._, false).
225
226
227int_hook(=:=, eq(..., ...)).
228eq(A...B, C...D, Res) :-
229 less_eq(A...B, C...D, true),
230 great_eq(A...B, C...D, true),
231 !,
232 Res = true.
233
234eq(_..._, _..._, false).
235
239int_hook(/, div1(..., ...)).
240div1(A...B, C...D, Res) :-
241 !,
242 div(A...B, C...D, Res).
243
244int_hook(/, div2(..., atomic)).
245div2(A1...A2, atomic(B), Res) :-
246 !,
247 div(A1...A2, B...B, Res).
248
249int_hook(/, div3(atomic, ...)).
250div3(atomic(A), B1...B2, Res) :-
251 !,
252 div(A...A, B1...B2, Res).
253
254int_hook(/, div4(atomic, atomic)).
255div4(atomic(A), atomic(B), Res) :-
256 Res is A / B.
257
259mixed(L, U) :-
260 L < 0,
261 U > 0.
262
263positive(L, U) :-
264 L >= 0,
265 U > 0.
266
267zeropos(L, U) :-
268 L =:= 0,
269 U > 0.
270
271strictpos(L, _) :-
272 L > 0.
273
274negative(L, U) :-
275 L < 0,
276 U =< 0.
277
278zeroneg(L, U) :-
279 L < 0,
280 U =:= 0.
281
282strictneg(_, U) :-
283 U < 0.
284
289div(A...B, C...D, Res),
290 strictpos(A, B),
291 zeropos(C, D)
292 => eval(A / D, L),
293 Res = L...1.0Inf.
294
295div(A...B, C...D, Res),
296 strictpos(A, B),
297 positive(C, D)
298 => eval(A / D, L),
299 eval(B / C, U),
300 Res = L...U.
301
303div(A...B, 0.0...D, Res),
304 zeropos(A, B),
305 positive(0.0, D)
306 => Res = 0.0...1.0Inf.
307
308div(A...B, C...D, Res),
309 zeropos(A, B),
310 positive(C, D)
311 => eval(B / C, U),
312 Res = 0.0...U.
313
315div(A...B, 0.0...D, Res),
316 mixed(A, B),
317 positive(0.0, D)
318 => Res = -1.0Inf...1.0Inf.
319
320div(A...B, C...D, Res),
321 mixed(A, B),
322 positive(C, D)
323 => eval(A / C, L),
324 eval(B / C, U),
325 Res = L...U.
326
328div(A...B, 0.0...D, Res),
329 zeroneg(A, B),
330 positive(0.0, D)
331 => Res = -1.0Inf...0.0.
332
333div(A...B, C...D, Res),
334 zeroneg(A, B),
335 positive(C, D)
336 => eval(A / C, L),
337 Res = L...0.0.
338
340div(A...B, 0.0...D, Res),
341 strictneg(A, B),
342 positive(0.0, D)
343 => eval(B / D, U),
344 Res = -1.0Inf...U.
345
346div(A...B, C...D, Res),
347 strictneg(A, B),
348 positive(C, D)
349 => eval(A / C, L),
350 eval(B / D, U),
351 Res = L...U.
352
354div(A...B, C...D, Res),
355 strictpos(A, B),
356 mixed(C, D)
357 => ( eval(A / C, U),
358 Res = -1.0Inf...U
359 ; eval(A / D, L),
360 Res = L...1.0Inf
361 ).
362
364div(A...B, C...D, Res),
365 zeropos(A, B),
366 mixed(C, D)
367 => Res = -1.0Inf...1.0Inf.
368
370div(A...B, C...D, Res),
371 mixed(A, B),
372 mixed(C, D)
373 => Res = -1.0Inf...1.0Inf.
374
376div(A...B, C...D, Res),
377 zeroneg(A, B),
378 mixed(C, D)
379 => Res = -1.0Inf...1.0Inf.
380
382div(A...B, C...D, Res),
383 strictneg(A, B),
384 mixed(C, D)
385 => ( eval(B / D, U),
386 Res = -1.0Inf...U
387 ; eval(B / C, L),
388 Res = L...1.0Inf
389 ).
390
392div(A...B, C...0.0, Res),
393 strictpos(A, B),
394 negative(C, 0.0)
395 => eval(A / C, U),
396 Res = -1.0Inf...U.
397
398div(A...B, C...D, Res),
399 strictpos(A, B),
400 negative(C, D)
401 => eval(B / D, L),
402 eval(A / C, U),
403 Res = L...U.
404
406div(A...B, C...0.0, Res),
407 zeropos(A, B),
408 negative(C, 0.0)
409 => Res = -1.0Inf...0.0.
410
411div(A...B, C...D, Res),
412 zeropos(A, B),
413 negative(C, D)
414 => eval(B / D, L),
415 Res = L...0.0.
416
418div(A...B, C...0.0, Res),
419 mixed(A, B),
420 negative(C, 0.0)
421 => Res = -1.0Inf...1.0Inf.
422
423div(A...B, C...D, Res),
424 mixed(A, B),
425 negative(C, D)
426 => eval(B / D, L),
427 eval(A / D, U),
428 Res = L...U.
429
431div(A...B, C...0.0, Res),
432 zeroneg(A, B),
433 negative(C, 0.0)
434 => Res = 0.0...1.0Inf.
435
436div(A...B, C...D, Res),
437 zeroneg(A, B),
438 negative(C, D)
439 => eval(A / D, U),
440 Res = 0.0...U.
441
443div(A...B, C...0.0, Res),
444 strictneg(A, B),
445 negative(C, 0.0)
446 => eval(B / C, L),
447 Res = L...1.0Inf.
448
449div(A...B, C...D, Res),
450 strictneg(A, B),
451 negative(C, D)
452 => eval(B / C, L),
453 eval(A / D, U),
454 Res = L...U.
455
462mono(sqrt/1, [+]).
463
464int_hook(sqrt1, sqrt1(...)).
465sqrt1(A...B, Res) :-
466 strictneg(A, B),
467 !,
468 Res = 1.5NaN.
469
470sqrt1(A...B, Res) :-
471 zeroneg(A, B),
472 !,
473 Res = 0.0.
474
475sqrt1(A...B, Res) :-
476 mixed(A, B),
477 !,
478 eval(sqrt(B), U),
479 Res = 0.0...U.
484int_hook((^), pow(..., atomic)).
485pow(L...U, atomic(Exp), Res),
486 negative(L, U),
487 even(Exp),
488 natural(Exp)
489 => eval(U^Exp, L^Exp, Res).
490
492pow(L...U, atomic(Exp), Res),
493 mixed(L, U),
494 even(Exp),
495 natural(Exp)
496 => eval(max(L^Exp, U^Exp), Upper),
497 Res = 0...Upper.
498
500pow(L...U, atomic(Exp), Res),
501 natural(Exp)
502 => eval(L^Exp, U^Exp, Res).
503
505even(A) :-
506 A mod 2 =:= 0.
507
508natural(A) :-
509 A >=0,
510 integer(A).
511
515int_hook(abs, abs1(...)).
516abs1(A...B, Res) :-
517 positive(A, B),
518 !,
519 Res = A...B.
520
521abs1(A...B, Res) :-
522 negative(A, B),
523 !,
524 eval(abs(A), U),
525 eval(abs(B), L),
526 Res = L...U.
527
529abs1(A...B, Res) :-
530 !,
531 L = 0.0,
532 U is max(abs(A), abs(B)),
533 Res = L...U.
534
538int_hook(round, round1(..., atomic)).
539round1(A...B, atomic(Dig), Res) :-
540 eval(floor(A, Dig), A1),
541 eval(ceiling(B, Dig), B1),
542 Res = A1...B1.
543
544eval_hook(floor(A, Dig), Res) :-
545 Mul is 10^Dig,
546 Res is floor(A * Mul) / Mul.
547
548eval_hook(ceiling(A, Dig), Res) :-
549 Mul is 10^Dig,
550 Res is ceiling(A * Mul) / Mul.
551
553eval(Expr1, Expr2, L ... U) :-
554 interval:eval(Expr1, L),
555 interval:eval(Expr2, U)