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 repsilon(R),
145 E is R*N.
146
147near_compare(Comparator, A, B) :-
148 ( A =:= B
149 ->compare_eq(Comparator)
150 ; repsilon(max(abs(A), abs(B)), E),
151 compare(Comparator, A, B, E)
152 ).
153
154compare(=, A, B, E) :- abs(A - B) =< E.
155compare(=<, A, B, E) :- A - B =< E.
156compare(>=, A, B, E) :- B - A =< E.
157compare(<, A, B, E) :- B - A > E.
158compare(>, A, B, E) :- A - B > E.
159compare(\=, A, B, E) :- abs(A - B) > E.
160
162unify_near(Arg1, Arg2) :-
163 ( ( var(Arg1)
164 ; var(Arg2)
165 ; integer(Arg1),
166 integer(Arg2)
167 )
168 ->Arg1 = Arg2
169 ; rnum(Arg1),
170 rnum(Arg2)
171 ->real_near(Arg1, Arg2)
172 ; mapargs(unify_near, Arg1, Arg2)
173 ).
174
176equiv_near(Arg1, Arg2) :-
177 ( ( var(Arg1)
178 ; var(Arg2)
179 ; integer(Arg1),
180 integer(Arg2)
181 )
182 ->Arg1 == Arg2
183 ; rnum(Arg1),
184 rnum(Arg2)
185 ->real_near(Arg1, Arg2)
186 ; mapargs(equiv_near, Arg1, Arg2)
187 )