34
35:- module(varnumbers,
36 [ numbervars/1, 37 varnumbers/2, 38 max_var_number/3, 39 varnumbers/3, 40 varnumbers_names/3 41 ]). 42:- autoload(library(apply),[maplist/3]). 43:- autoload(library(assoc),
44 [empty_assoc/1,assoc_to_list/2,get_assoc/3,put_assoc/4]). 45:- autoload(library(error),[must_be/2]).
78numbervars(Term) :-
79 numbervars(Term, 0, _).
86varnumbers(Term, Copy) :-
87 varnumbers(Term, 0, Copy).
99varnumbers(Term, Min, Copy) :-
100 must_be(acyclic, Term),
101 MaxStart is Min-1,
102 max_var_number(Term, MaxStart, Max),
103 NVars is Max-MaxStart,
104 ( NVars == 0
105 -> Copy = Term
106 ; roundup_next_power_two(NVars, Len),
107 functor(Vars, v, Len),
108 varnumbers(Term, MaxStart, Vars, Copy)
109 ).
110
111varnumbers(Var, _, _, Copy) :-
112 var(Var),
113 !,
114 Copy = Var.
115varnumbers(Var, _, _, Copy) :-
116 atomic(Var),
117 !,
118 Copy = Var.
119varnumbers('$VAR'(I), Min, Vars, Copy) :-
120 integer(I),
121 I > Min,
122 !,
123 Index is I-Min,
124 arg(Index, Vars, Copy).
125varnumbers(Term, Min, Vars, Copy) :-
126 functor(Term, Name, Arity),
127 functor(Copy, Name, Arity),
128 varnumbers_args(1, Arity, Term, Min, Vars, Copy).
129
130varnumbers_args(I, Arity, Term, Min, Vars, Copy) :-
131 I =< Arity,
132 !,
133 arg(I, Term, AT),
134 arg(I, Copy, CT),
135 varnumbers(AT, Min, Vars, CT),
136 I2 is I + 1,
137 varnumbers_args(I2, Arity, Term, Min, Vars, Copy).
138varnumbers_args(_, _, _, _, _, _).
144roundup_next_power_two(1, 1) :- !.
145roundup_next_power_two(N, L) :-
146 L is 1<<(msb(N-1)+1).
156max_var_number(V, Max, Max) :-
157 var(V),
158 !.
159max_var_number('$VAR'(I), Max0, Max) :-
160 integer(I),
161 !,
162 Max is max(I,Max0).
163max_var_number(S, Max0, Max) :-
164 functor(S, _, Ar),
165 max_var_numberl(Ar, S, Max0, Max).
166
167max_var_numberl(0, _, Max, Max) :- !.
168max_var_numberl(I, T, Max0, Max) :-
169 arg(I, T, Arg),
170 I2 is I-1,
171 max_var_number(Arg, Max0, Max1),
172 max_var_numberl(I2, T, Max1, Max).
185varnumbers_names(Term, Copy, Bindings) :-
186 must_be(acyclic, Term),
187 empty_assoc(Named),
188 varnumbers_names(Term, Named, BindingAssoc, Copy),
189 assoc_to_list(BindingAssoc, BindingPairs),
190 maplist(pair_equals, BindingPairs, Bindings).
191
192pair_equals(N-V, N=V).
193
194varnumbers_names(Var, Bindings, Bindings, Copy) :-
195 var(Var),
196 !,
197 Copy = Var.
198varnumbers_names(Var, Bindings, Bindings, Copy) :-
199 atomic(Var),
200 !,
201 Copy = Var.
202varnumbers_names('$VAR'(Name), Bindings0, Bindings, Copy) :-
203 !,
204 ( get_assoc(Name, Bindings0, Copy)
205 -> Bindings = Bindings0
206 ; put_assoc(Name, Bindings0, Copy, Bindings)
207 ).
208varnumbers_names(Term, Bindings0, Bindings, Copy) :-
209 functor(Term, Name, Arity),
210 functor(Copy, Name, Arity),
211 varnumbers_names_args(1, Arity, Term, Bindings0, Bindings, Copy).
212
213varnumbers_names_args(I, Arity, Term, Bindings0, Bindings, Copy) :-
214 I =< Arity,
215 !,
216 arg(I, Term, AT),
217 arg(I, Copy, CT),
218 varnumbers_names(AT, Bindings0, Bindings1, CT),
219 I2 is I + 1,
220 varnumbers_names_args(I2, Arity, Term, Bindings1, Bindings, Copy).
221varnumbers_names_args(_, _, _, Bindings, Bindings, _)
Utilities for numbered terms
This library provides the inverse functionality of the built-in numbervars/3. Note that this library suffers from the known issues that '$VAR'(X) is a normal Prolog term and, -unlike the built-in numbervars-, the inverse predicates do not process cyclic terms. The following predicate is true for any acyclic term that contains no '$VAR'(X),
integer(X)
terms and no constraint variables: