34
35:- module(near_utils,
36 [fact_near/1,
37 fact_near/2,
38 retract_near/1,
39 retractall_near/1,
40 real_near/2,
41 real_compare/3,
42 near_compare/3,
43 unify_near/2,
44 equiv_near/2,
45 repsilon/1,
46 repsilon/2]). 47
48:- use_module(library(apply)). 49:- use_module(library(call_ref)). 50:- use_module(library(mapargs)). 51:- use_module(library(compare_eq)). 52
53:- meta_predicate
54 fact_near(0 ),
55 fact_near(0, -),
56 retract_near(0 ),
57 retractall_near(0 ). 58
60
61fact_near(M:Call) :-
62 freeze_near(Call, Mask),
63 M:Mask,
64 frozen_near(Mask).
65
66fact_near(Call, Ref) :-
67 freeze_near(Call, Mask),
68 call_ref(Mask, Ref),
69 frozen_near(Mask).
70
71retract_near(Call) :-
72 fact_near(Call, Ref),
73 erase(Ref).
74
75retractall_near(Call) :-
76 forall(( freeze_near(Call, Mask),
77 call_ref(Mask, Ref)
78 ),
79 erase(Ref)).
80
81real(R) :-
82 ( R == 1.5NaN
83 ->fail
84 ; float(R)
85 ->true
86 ; rational(R),
87 \+ integer(R)
88 ).
89
90rnum(R) :-
91 ( R == 1.5NaN
92 ->fail
93 ; float(R)
94 ->true
95 ; rational(R)
96 ).
97
98attr_unify_hook(near(Arg1), Arg) :-
99 rnum(Arg),
100 real_near(Arg1, Arg).
101
102put_near(Arg1, Arg) :-
103 ( nonvar(Arg1)
104 ->put_attr(Arg, near_utils, near(Arg1))
105 ; Arg = Arg1
106 ).
107
108freeze_near(Arg1, Arg) :-
109 ( real(Arg1)
110 ->put_near(Arg1, Arg)
111 112 113 114 115 116 117 118 119 120 121 ; var(Arg1)
122 ->Arg = Arg1
123 ; mapargs(freeze_near, Arg1, Arg)
124 ).
125
126frozen_near(Mask) :-
127 term_attvars(Mask, Vars),
128 maplist(frozen_near_1, Vars).
129
130frozen_near_1(Var) :-
131 ( get_attr(Var, near_utils, near(Val))
132 ->del_attr(Var, near_utils),
133 Var = Val
134 ; true
135 ).
136
137real_near(A, B) :- near_compare(=, A, B).
138
139real_compare(A, C, B) :- near_compare(C, A, B).
140
141repsilon(E) :- E is 1024*epsilon.
142
143repsilon(N, E) :-
144 ( N =:= inf
145 ->E = 0
146 ; repsilon(R),
147 E is R*N
148 ).
149
150near_compare(Comparator, A, B) :-
151 ( A =:= B
152 ->compare_eq(Comparator)
153 ; repsilon(max(abs(A), abs(B)), E),
154 compare(Comparator, A, B, E)
155 ).
156
157compare(=, A, B, E) :- abs(A - B) =< E.
158compare(=<, A, B, E) :- A - B =< E.
159compare(>=, A, B, E) :- B - A =< E.
160compare(<, A, B, E) :- B - A > E.
161compare(>, A, B, E) :- A - B > E.
162compare(\=, A, B, E) :- abs(A - B) > E.
163
165unify_near(Arg1, Arg2) :-
166 ( ( var(Arg1)
167 ; var(Arg2)
168 ; integer(Arg1),
169 integer(Arg2)
170 )
171 ->Arg1 = Arg2
172 ; rnum(Arg1),
173 rnum(Arg2)
174 ->real_near(Arg1, Arg2)
175 ; mapargs(unify_near, Arg1, Arg2)
176 ).
177
179equiv_near(Arg1, Arg2) :-
180 ( ( var(Arg1)
181 ; var(Arg2)
182 ; integer(Arg1),
183 integer(Arg2)
184 )
185 ->Arg1 == Arg2
186 ; rnum(Arg1),
187 rnum(Arg2)
188 ->real_near(Arg1, Arg2)
189 ; mapargs(equiv_near, Arg1, Arg2)
190 )