Merge branch 'rebis-dev' into 0.9.0 release
This commit is contained in:
@@ -94,12 +94,6 @@ number_to_rational(Eps0, Real0, Fraction) :-
|
||||
),
|
||||
!.
|
||||
|
||||
number(X) :-
|
||||
( integer(X)
|
||||
; float(X)
|
||||
; rational(X)
|
||||
).
|
||||
|
||||
stern_brocot_(Qnn/Qnd, Qpn/Qpd, A/B, C/D, Fraction) :-
|
||||
Fn1 is A + C,
|
||||
Fd1 is B + D,
|
||||
|
||||
@@ -24,30 +24,42 @@
|
||||
'$absent_from_list'(Ls, Attr).
|
||||
|
||||
'$absent_from_list'(X, Attr) :-
|
||||
( var(X) -> true
|
||||
; X = [L|Ls], L \= Attr -> '$absent_from_list'(Ls, Attr)
|
||||
( var(X) ->
|
||||
true
|
||||
; X = [L|Ls],
|
||||
L \= Attr ->
|
||||
'$absent_from_list'(Ls, Attr)
|
||||
).
|
||||
|
||||
'$get_attr'(V, Attr) :-
|
||||
'$get_attr_list'(V, Ls), nonvar(Ls), '$get_from_list'(Ls, V, Attr).
|
||||
'$get_attr_list'(V, Ls),
|
||||
nonvar(Ls),
|
||||
'$get_from_list'(Ls, V, Attr).
|
||||
|
||||
'$get_from_list'([L|Ls], V, Attr) :-
|
||||
nonvar(L),
|
||||
( L \= Attr -> nonvar(Ls), '$get_from_list'(Ls, V, Attr)
|
||||
; L = Attr, '$enqueue_attr_var'(V)
|
||||
( L \= Attr ->
|
||||
nonvar(Ls),
|
||||
'$get_from_list'(Ls, V, Attr)
|
||||
; L = Attr,
|
||||
'$enqueue_attr_var'(V)
|
||||
).
|
||||
|
||||
'$put_attr'(V, Attr) :-
|
||||
'$get_attr_list'(V, Ls), '$add_to_list'(Ls, V, Attr).
|
||||
'$get_attr_list'(V, Ls),
|
||||
'$add_to_list'(Ls, V, Attr).
|
||||
|
||||
'$add_to_list'(Ls, V, Attr) :-
|
||||
( var(Ls) ->
|
||||
Ls = [Attr | _], '$enqueue_attr_var'(V)
|
||||
; Ls = [_ | Ls0], '$add_to_list'(Ls0, V, Attr)
|
||||
( var(Ls) ->
|
||||
Ls = [Attr | _],
|
||||
'$enqueue_attr_var'(V)
|
||||
; Ls = [_ | Ls0],
|
||||
'$add_to_list'(Ls0, V, Attr)
|
||||
).
|
||||
|
||||
'$del_attr'(Ls0, _, _) :-
|
||||
var(Ls0), !.
|
||||
var(Ls0),
|
||||
!.
|
||||
'$del_attr'(Ls0, V, Attr) :-
|
||||
Ls0 = [Att | Ls1],
|
||||
nonvar(Att),
|
||||
@@ -134,22 +146,22 @@ put_attr(Name, Arity, Module) -->
|
||||
[(put_atts(V, +Attr) :-
|
||||
!,
|
||||
functor(Attr, Head, Arity),
|
||||
functor(AttrForm, Head, Arity),
|
||||
'$get_attr_list'(V, Ls),
|
||||
atts:'$del_attr'(Ls, V, Module:AttrForm),
|
||||
atts:'$put_attr'(V, Module:Attr)),
|
||||
functor(AttrForm, Head, Arity),
|
||||
'$get_attr_list'(V, Ls),
|
||||
atts:'$del_attr'(Ls, V, Module:AttrForm),
|
||||
atts:'$put_attr'(V, Module:Attr)),
|
||||
(put_atts(V, Attr) :-
|
||||
!,
|
||||
functor(Attr, Head, Arity),
|
||||
functor(AttrForm, Head, Arity),
|
||||
'$get_attr_list'(V, Ls),
|
||||
atts:'$del_attr'(Ls, V, Module:AttrForm),
|
||||
atts:'$put_attr'(V, Module:Attr)),
|
||||
functor(AttrForm, Head, Arity),
|
||||
'$get_attr_list'(V, Ls),
|
||||
atts:'$del_attr'(Ls, V, Module:AttrForm),
|
||||
atts:'$put_attr'(V, Module:Attr)),
|
||||
(put_atts(V, -Attr) :-
|
||||
!,
|
||||
functor(Attr, _, _),
|
||||
'$get_attr_list'(V, Ls),
|
||||
atts:'$del_attr'(Ls, V, Module:Attr))].
|
||||
'$get_attr_list'(V, Ls),
|
||||
atts:'$del_attr'(Ls, V, Module:Attr))].
|
||||
|
||||
get_attr(Name, Arity, Module) -->
|
||||
{ functor(Attr, Name, Arity) },
|
||||
|
||||
@@ -12,17 +12,18 @@ between(Lower, Upper, X) :-
|
||||
( nonvar(X) ->
|
||||
Lower =< X,
|
||||
X =< Upper
|
||||
; compare(Ord, Lower, Upper),
|
||||
between_(Ord, Lower, Upper, X)
|
||||
; Lower =< Upper,
|
||||
between_(Lower, Upper, X)
|
||||
).
|
||||
|
||||
between_(<, Lower0, Upper, X) :-
|
||||
( X = Lower0
|
||||
; Lower1 is Lower0 + 1,
|
||||
compare(Ord, Lower1, Upper),
|
||||
between_(Ord, Lower1, Upper, X)
|
||||
).
|
||||
between_(=, Upper, Upper, Upper).
|
||||
between_(Lower, Upper, Lower1) :-
|
||||
Lower < Upper,
|
||||
!,
|
||||
( Lower1 = Lower
|
||||
; Lower0 is Lower + 1,
|
||||
between_(Lower0, Upper, Lower1)
|
||||
).
|
||||
between_(Lower, Lower, Lower).
|
||||
|
||||
enumerate_nats(I, I).
|
||||
enumerate_nats(I0, N) :-
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
:- module(builtins, [(=)/2, (\=)/2, (\+)/1, (',')/2, (->)/2, (;)/2,
|
||||
:- module(builtins, [(=)/2, (\=)/2, (\+)/1, !/0, (',')/2, (->)/2, (;)/2,
|
||||
(=..)/2, (:)/2, (:)/3, (:)/4, (:)/5, (:)/6,
|
||||
(:)/7, (:)/8, (:)/9, (:)/10, (:)/11, (:)/12,
|
||||
abolish/1, asserta/1, assertz/1,
|
||||
@@ -59,65 +59,62 @@ call(G, A, B, C, D, E, F, G) :- '$call'(G, A, B, C, D, E, F, G).
|
||||
|
||||
call(G, A, B, C, D, E, F, G, H) :- '$call'(G, A, B, C, D, E, F, G, H).
|
||||
|
||||
|
||||
Module : Predicate :-
|
||||
( atom(Module) ->
|
||||
'$module_call'(Module, Predicate)
|
||||
;
|
||||
throw(error(type_error(atom, Module), (:)/2))
|
||||
).
|
||||
|
||||
|
||||
% dynamic module resolution.
|
||||
|
||||
Module : Predicate :-
|
||||
( atom(Module) -> '$module_call'(Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
).
|
||||
|
||||
:(Module, Predicate, A1) :-
|
||||
( atom(Module) -> '$module_call'(A1, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
( atom(Module) ->
|
||||
'$module_call'(A1, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
).
|
||||
|
||||
:(Module, Predicate, A1, A2) :-
|
||||
( atom(Module) -> '$module_call'(A1, A2, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
( atom(Module) -> '$module_call'(A1, A2, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
).
|
||||
|
||||
:(Module, Predicate, A1, A2, A3) :-
|
||||
( atom(Module) -> '$module_call'(A1, A2, A3, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
( atom(Module) -> '$module_call'(A1, A2, A3, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
).
|
||||
|
||||
:(Module, Predicate, A1, A2, A3, A4) :-
|
||||
( atom(Module) -> '$module_call'(A1, A2, A3, A4, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
( atom(Module) -> '$module_call'(A1, A2, A3, A4, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
).
|
||||
|
||||
:(Module, Predicate, A1, A2, A3, A4, A5) :-
|
||||
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
).
|
||||
|
||||
:(Module, Predicate, A1, A2, A3, A4, A5, A6) :-
|
||||
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
).
|
||||
|
||||
:(Module, Predicate, A1, A2, A3, A4, A5, A6, A7) :-
|
||||
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
).
|
||||
|
||||
:(Module, Predicate, A1, A2, A3, A4, A5, A6, A7, A8) :-
|
||||
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, A8, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, A8, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
).
|
||||
|
||||
:(Module, Predicate, A1, A2, A3, A4, A5, A6, A7, A8, A9) :-
|
||||
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, A8, A9, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, A8, A9, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
).
|
||||
|
||||
:(Module, Predicate, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) :-
|
||||
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
).
|
||||
|
||||
% flags.
|
||||
@@ -205,153 +202,184 @@ repeat.
|
||||
repeat :- repeat.
|
||||
|
||||
|
||||
:- meta_predicate ','(0,0).
|
||||
|
||||
:- meta_predicate ','(0, 0).
|
||||
:- meta_predicate ;(0,0).
|
||||
|
||||
:- meta_predicate ','(0, +, +).
|
||||
|
||||
:- meta_predicate ;(0, 0).
|
||||
|
||||
:- meta_predicate ;(0, 0, +).
|
||||
|
||||
:- meta_predicate ->(0, 0).
|
||||
|
||||
:- meta_predicate ->(0, 0, +).
|
||||
:- meta_predicate ->(0,0).
|
||||
|
||||
|
||||
','(G1, G2) :-
|
||||
'$get_b_value'(B),
|
||||
( '$call_with_default_policy'(var(G1)) ->
|
||||
throw(error(instantiation_error, (',')/2))
|
||||
; '$call_with_default_policy'(','(G1, G2, B))
|
||||
).
|
||||
G1 -> G2 :- control_entry_point((G1 -> G2)).
|
||||
|
||||
|
||||
';'(G1, G2) :-
|
||||
'$get_b_value'(B),
|
||||
( '$call_with_default_policy'(var(G1)) ->
|
||||
throw(error(instantiation_error, (';')/2))
|
||||
; '$call_with_default_policy'(';'(G1, G2, B))
|
||||
).
|
||||
:- non_counted_backtracking staggered_if_then/2.
|
||||
|
||||
staggered_if_then(G1, G2) :-
|
||||
'$get_staggered_cp'(B),
|
||||
call('$call'(G1)),
|
||||
'$set_cp'(B),
|
||||
call('$call'(G2)).
|
||||
|
||||
G1 ; G2 :- control_entry_point((G1 ; G2)).
|
||||
|
||||
|
||||
G1 -> G2 :-
|
||||
'$get_b_value'(B),
|
||||
( '$call_with_default_policy'(var(G1)) ->
|
||||
throw(error(instantiation_error, (->)/2))
|
||||
; '$call_with_default_policy'(->(G1, G2, B))
|
||||
).
|
||||
:- non_counted_backtracking staggered_sc/2.
|
||||
|
||||
staggered_sc(G, _) :- call('$call'(G)).
|
||||
staggered_sc(_, G) :- call('$call'(G)).
|
||||
|
||||
|
||||
:-non_counted_backtracking call_or_cut/3.
|
||||
!.
|
||||
|
||||
call_or_cut(G, B, ErrorPI) :-
|
||||
( '$call_with_default_policy'(var(G)) ->
|
||||
throw(error(instantiation_error, ErrorPI))
|
||||
; '$call_with_default_policy'(call_or_cut(G, B))
|
||||
).
|
||||
:- non_counted_backtracking set_cp/1.
|
||||
|
||||
set_cp(B) :- '$set_cp'(B).
|
||||
|
||||
','(G1, G2) :- control_entry_point((G1, G2)).
|
||||
|
||||
:- non_counted_backtracking control_entry_point/1.
|
||||
|
||||
control_entry_point(G) :-
|
||||
functor(G, Name, Arity),
|
||||
catch(builtins:control_entry_point_(G),
|
||||
dispatch_prep_error,
|
||||
builtins:throw(error(type_error(callable, G), Name/Arity))).
|
||||
|
||||
|
||||
:- non_counted_backtracking control_functor/1.
|
||||
:- non_counted_backtracking control_entry_point_/1.
|
||||
|
||||
control_functor(_:G) :- nonvar(G), control_functor(G).
|
||||
control_functor(call(_:C)) :- C == !.
|
||||
control_functor(!).
|
||||
control_functor((_,_)).
|
||||
control_functor((_;_)).
|
||||
control_functor((_->_)).
|
||||
control_entry_point_(G) :-
|
||||
'$get_cp'(B),
|
||||
dispatch_prep(G,B,Conts),
|
||||
dispatch_call_list(Conts).
|
||||
|
||||
|
||||
:- non_counted_backtracking call_or_cut/2.
|
||||
:- non_counted_backtracking cont_list_to_goal/2.
|
||||
|
||||
call_or_cut(G, B) :-
|
||||
( nonvar(G),
|
||||
'$call_with_default_policy'(control_functor(G)) ->
|
||||
'$call_with_default_policy'(call_or_cut_interp(G, B))
|
||||
; call(G)
|
||||
).
|
||||
cont_list_goal([Cont], Cont) :- !.
|
||||
cont_list_goal(Conts, builtins:dispatch_call_list(Conts)).
|
||||
|
||||
|
||||
:- non_counted_backtracking call_or_cut_interp/2.
|
||||
:- non_counted_backtracking module_qualified_cut/1.
|
||||
|
||||
call_or_cut_interp(_ : G, B) :-
|
||||
call_or_cut_interp(G, B).
|
||||
call_or_cut_interp(call(_ : !), B) :-
|
||||
!. % '$set_cp'(B).
|
||||
call_or_cut_interp(!, B) :-
|
||||
'$set_cp'(B).
|
||||
call_or_cut_interp((G1, G2), B) :-
|
||||
'$call_with_default_policy'(','(G1, G2, B)).
|
||||
call_or_cut_interp((G1 ; G2), B) :-
|
||||
'$call_with_default_policy'(';'(G1, G2, B)).
|
||||
call_or_cut_interp((G1 -> G2), B) :-
|
||||
'$call_with_default_policy'(->(G1, G2, B)).
|
||||
module_qualified_cut(Gs) :-
|
||||
( functor(Gs, call, 1) ->
|
||||
arg(1, Gs, G1)
|
||||
; Gs = G1
|
||||
),
|
||||
functor(G1, (:), 2),
|
||||
arg(2, G1, G2),
|
||||
G2 == !.
|
||||
|
||||
|
||||
:- non_counted_backtracking (',')/3.
|
||||
:- non_counted_backtracking dispatch_prep/3.
|
||||
|
||||
','(G1, G2, B) :-
|
||||
( nonvar(G1),
|
||||
'$call_with_default_policy'(control_functor(G1)) ->
|
||||
'$call_with_default_policy'(call_or_cut_interp(G1, B)),
|
||||
'$call_with_default_policy'(call_or_cut(G2, B, (',')/2))
|
||||
; call(G1),
|
||||
'$call_with_default_policy'(call_or_cut(G2, B, (',')/2))
|
||||
).
|
||||
|
||||
:- non_counted_backtracking (;)/3.
|
||||
|
||||
';'(G1, G2, B) :-
|
||||
( nonvar(G1),
|
||||
'$call_with_default_policy'(control_functor(G1)) ->
|
||||
'$call_with_default_policy'(';-interp'(G1, G2, B))
|
||||
; call(G1)
|
||||
; '$call_with_default_policy'(call_or_cut(G2, B, (;)/2))
|
||||
).
|
||||
|
||||
|
||||
:- non_counted_backtracking ';-interp'/3.
|
||||
|
||||
';-interp'((G1 -> G2), G3, B) :-
|
||||
!,
|
||||
( '$call_with_default_policy'(call_or_cut(G1, B, (->)/2)) ->
|
||||
'$call_with_default_policy'(call_or_cut(G2, B, (->)/2))
|
||||
; '$call_with_default_policy'(call_or_cut(G3, B, (;)/2))
|
||||
).
|
||||
';-interp'(_:(G1 -> G2), G3, B) :-
|
||||
!,
|
||||
( '$call_with_default_policy'(call_or_cut(G1, B, (->)/2)) ->
|
||||
'$call_with_default_policy'(call_or_cut(G2, B, (->)/2))
|
||||
; '$call_with_default_policy'(call_or_cut(G3, B, (;)/2))
|
||||
).
|
||||
';-interp'(G1, G2, B) :-
|
||||
( '$call_with_default_policy'(call_or_cut_interp(G1, B))
|
||||
; '$call_with_default_policy'(call_or_cut(G2, B, (;)/2))
|
||||
).
|
||||
|
||||
|
||||
:- non_counted_backtracking (->)/3.
|
||||
|
||||
->(G1, G2, B) :-
|
||||
( nonvar(G1),
|
||||
'$call_with_default_policy'(control_functor(G1)) ->
|
||||
( '$call_with_default_policy'(call_or_cut_interp(G1, B)) ->
|
||||
'$call_with_default_policy'(call_or_cut(G2, B, (->)/2))
|
||||
dispatch_prep(Gs, B, [Cont|Conts]) :-
|
||||
( callable(Gs) ->
|
||||
( functor(Gs, ',', 2) ->
|
||||
arg(1, Gs, G1),
|
||||
arg(2, Gs, G2),
|
||||
dispatch_prep(G1, B, IConts1),
|
||||
cont_list_goal(IConts1, Cont),
|
||||
dispatch_prep(G2, B, Conts)
|
||||
; functor(Gs, ';', 2) ->
|
||||
arg(1, Gs, G1),
|
||||
arg(2, Gs, G2),
|
||||
dispatch_prep(G1, B, IConts0),
|
||||
dispatch_prep(G2, B, IConts1),
|
||||
cont_list_goal(IConts0, Cont0),
|
||||
cont_list_goal(IConts1, Cont1),
|
||||
Cont = builtins:staggered_sc(Cont0, Cont1),
|
||||
Conts = []
|
||||
; functor(Gs, ->, 2) ->
|
||||
arg(1, Gs, G1),
|
||||
arg(2, Gs, G2),
|
||||
dispatch_prep(G1, B, IConts1),
|
||||
dispatch_prep(G2, B, IConts2),
|
||||
cont_list_goal(IConts1, Cont1),
|
||||
cont_list_goal(IConts2, Cont2),
|
||||
Cont = builtins:staggered_if_then(Cont1, Cont2),
|
||||
Conts = []
|
||||
; ( Gs == ! ; module_qualified_cut(Gs) ) ->
|
||||
Cont = builtins:set_cp(B),
|
||||
Conts = []
|
||||
; Cont = Gs,
|
||||
Conts = []
|
||||
)
|
||||
; call(G1) ->
|
||||
'$call_with_default_policy'(call_or_cut(G2, B, (->)/2))
|
||||
; var(Gs) ->
|
||||
Cont = Gs,
|
||||
Conts = []
|
||||
; throw(dispatch_prep_error)
|
||||
).
|
||||
|
||||
|
||||
:- non_counted_backtracking dispatch_call_list/1.
|
||||
|
||||
dispatch_call_list([]).
|
||||
dispatch_call_list([G1,G2,G3,G4,G5,G6,G7,G8|Gs]) :-
|
||||
!,
|
||||
'$call'(G1),
|
||||
'$call'(G2),
|
||||
'$call'(G3),
|
||||
'$call'(G4),
|
||||
'$call'(G5),
|
||||
'$call'(G6),
|
||||
'$call'(G7),
|
||||
'$call'(G8),
|
||||
'$call_with_default_policy'(dispatch_call_list(Gs)).
|
||||
dispatch_call_list([G1,G2,G3,G4,G5,G6,G7]) :-
|
||||
!,
|
||||
'$call'(G1),
|
||||
'$call'(G2),
|
||||
'$call'(G3),
|
||||
'$call'(G4),
|
||||
'$call'(G5),
|
||||
'$call'(G6),
|
||||
'$call'(G7).
|
||||
dispatch_call_list([G1,G2,G3,G4,G5,G6]) :-
|
||||
!,
|
||||
'$call'(G1),
|
||||
'$call'(G2),
|
||||
'$call'(G3),
|
||||
'$call'(G4),
|
||||
'$call'(G5),
|
||||
'$call'(G6).
|
||||
dispatch_call_list([G1,G2,G3,G4,G5]) :-
|
||||
!,
|
||||
'$call'(G1),
|
||||
'$call'(G2),
|
||||
'$call'(G3),
|
||||
'$call'(G4),
|
||||
'$call'(G5).
|
||||
dispatch_call_list([G1,G2,G3,G4]) :-
|
||||
!,
|
||||
'$call'(G1),
|
||||
'$call'(G2),
|
||||
'$call'(G3),
|
||||
'$call'(G4).
|
||||
dispatch_call_list([G1,G2,G3]) :-
|
||||
!,
|
||||
'$call'(G1),
|
||||
'$call'(G2),
|
||||
'$call'(G3).
|
||||
dispatch_call_list([G1,G2]) :-
|
||||
!,
|
||||
'$call'(G1),
|
||||
'$call'(G2).
|
||||
dispatch_call_list([G1]) :-
|
||||
'$call'(G1).
|
||||
|
||||
|
||||
% univ.
|
||||
|
||||
:- non_counted_backtracking univ_errors/3.
|
||||
univ_errors(Term, List, N) :-
|
||||
'$skip_max_list'(N, -1, List, R),
|
||||
( var(R) ->
|
||||
( var(Term),
|
||||
throw(error(instantiation_error, (=..)/2)) % 8.5.3.3 a)
|
||||
; true
|
||||
)
|
||||
'$skip_max_list'(N, _, List, R),
|
||||
( var(R) ->
|
||||
( var(Term),
|
||||
throw(error(instantiation_error, (=..)/2)) % 8.5.3.3 a)
|
||||
; true
|
||||
)
|
||||
; R \== [] ->
|
||||
throw(error(type_error(list, List), (=..)/2)) % 8.5.3.3 b)
|
||||
; List = [H|T] ->
|
||||
@@ -388,9 +416,10 @@ univ_worker(Term, List, _) :-
|
||||
!,
|
||||
'$call_with_default_policy'(List = [Term]).
|
||||
univ_worker(Term, [Name|Args], N) :-
|
||||
var(Term), !,
|
||||
var(Term),
|
||||
!,
|
||||
'$call_with_default_policy'(Arity is N-1),
|
||||
'$call_with_default_policy'(functor(Term, Name, Arity)),
|
||||
'$call_with_default_policy'(functor(Term, Name, Arity)), % Term = {var}, Name = nonvar, Arity = 0.
|
||||
'$call_with_default_policy'(get_args(Args, Term, 1, Arity)).
|
||||
univ_worker(Term, List, _) :-
|
||||
'$call_with_default_policy'(functor(Term, Name, Arity)),
|
||||
@@ -415,7 +444,7 @@ get_args([Arg|Args], Func, I0, N) :-
|
||||
:- meta_predicate parse_options_list(?, 0, ?, ?, ?).
|
||||
|
||||
parse_options_list(Options, Selector, DefaultPairs, OptionValues, Stub) :-
|
||||
'$skip_max_list'(_, -1, Options, Tail),
|
||||
'$skip_max_list'(_, _, Options, Tail),
|
||||
( Tail == [] ->
|
||||
true
|
||||
; var(Tail) ->
|
||||
@@ -468,7 +497,7 @@ parse_write_options_(max_depth(MaxDepth), max_depth-MaxDepth) :-
|
||||
).
|
||||
|
||||
must_be_var_names_list(VarNames) :-
|
||||
'$skip_max_list'(_, -1, VarNames, Tail),
|
||||
'$skip_max_list'(_, _, VarNames, Tail),
|
||||
( Tail == [] ->
|
||||
must_be_var_names_list_(VarNames, VarNames)
|
||||
; var(Tail) ->
|
||||
@@ -565,7 +594,7 @@ can_be_list(List, _) :-
|
||||
var(List),
|
||||
!.
|
||||
can_be_list(List, _) :-
|
||||
'$skip_max_list'(_, -1, List, Tail),
|
||||
'$skip_max_list'(_, _, List, Tail),
|
||||
( var(Tail) ->
|
||||
true
|
||||
; Tail == []
|
||||
@@ -620,9 +649,11 @@ throw(Ball) :-
|
||||
),
|
||||
'$unwind_stack'.
|
||||
|
||||
|
||||
:- non_counted_backtracking '$iterate_find_all'/4.
|
||||
|
||||
'$iterate_find_all'(Template, Goal, _, LhOffset) :-
|
||||
call(Goal),
|
||||
'$call'(Goal),
|
||||
'$copy_to_lh'(LhOffset, Template),
|
||||
'$fail'.
|
||||
'$iterate_find_all'(_, _, Solutions, LhOffset) :-
|
||||
@@ -636,7 +667,7 @@ truncate_lh_to(LhLength) :- '$truncate_lh_to'(LhLength).
|
||||
:- meta_predicate findall(?, 0, ?).
|
||||
|
||||
findall(Template, Goal, Solutions) :-
|
||||
error:can_be(list, Solutions),
|
||||
'$call_with_default_policy'(error:can_be(list, Solutions)),
|
||||
'$lh_length'(LhLength),
|
||||
'$call_with_default_policy'(
|
||||
catch(builtins:'$iterate_find_all'(Template, Goal, Solutions, LhLength),
|
||||
@@ -644,7 +675,6 @@ findall(Template, Goal, Solutions) :-
|
||||
( builtins:truncate_lh_to(LhLength), builtins:throw(Error) ))
|
||||
).
|
||||
|
||||
|
||||
:- non_counted_backtracking '$iterate_find_all_diff'/5.
|
||||
|
||||
'$iterate_find_all_diff'(Template, Goal, _, _, LhOffset) :-
|
||||
@@ -659,8 +689,8 @@ findall(Template, Goal, Solutions) :-
|
||||
:- meta_predicate findall(?, 0, ?, ?).
|
||||
|
||||
findall(Template, Goal, Solutions0, Solutions1) :-
|
||||
error:can_be(list, Solutions0),
|
||||
error:can_be(list, Solutions1),
|
||||
'$call_with_default_policy'(error:can_be(list, Solutions0)),
|
||||
'$call_with_default_policy'(error:can_be(list, Solutions1)),
|
||||
'$lh_length'(LhLength),
|
||||
'$call_with_default_policy'(
|
||||
catch(builtins:'$iterate_find_all_diff'(Template, Goal, Solutions0,
|
||||
@@ -679,9 +709,9 @@ set_difference([], _, []) :- !.
|
||||
set_difference(Xs, [], Xs).
|
||||
|
||||
group_by_variant([V2-S2 | Pairs], V1-S1, [S2 | Solutions], Pairs0) :-
|
||||
iso_ext:variant(V1, V2),
|
||||
V1 = V2, % \+ \+ (V1 = V2), % (2) % iso_ext:variant(V1, V2), % (1)
|
||||
!,
|
||||
V1 = V2,
|
||||
% V1 = V2, % (3)
|
||||
group_by_variant(Pairs, V2-S2, Solutions, Pairs0).
|
||||
group_by_variant(Pairs, _, [], Pairs).
|
||||
|
||||
@@ -713,15 +743,15 @@ rightmost_power(Term, FinalTerm, Xs) :-
|
||||
|
||||
findall_with_existential(Template, Goal, PairedSolutions, Witnesses0, Witnesses) :-
|
||||
( nonvar(Goal),
|
||||
( Goal = _ ^ _
|
||||
; Goal = _ : (_ ^ _)
|
||||
) ->
|
||||
rightmost_power(Goal, Goal1, ExistentialVars0),
|
||||
loader:strip_module(Goal, M, Goal1),
|
||||
( Goal1 = _ ^ _ ) ->
|
||||
rightmost_power(Goal1, Goal2, ExistentialVars0),
|
||||
term_variables(ExistentialVars0, ExistentialVars),
|
||||
sort(Witnesses0, Witnesses1),
|
||||
sort(ExistentialVars, ExistentialVars1),
|
||||
set_difference(Witnesses1, ExistentialVars1, Witnesses),
|
||||
findall(Witnesses-Template, Goal1, PairedSolutions)
|
||||
expand_goal(M:Goal2, M, Goal3),
|
||||
findall(Witnesses-Template, Goal3, PairedSolutions)
|
||||
; Witnesses = Witnesses0,
|
||||
findall(Witnesses-Template, Goal, PairedSolutions)
|
||||
).
|
||||
@@ -779,11 +809,11 @@ setof(Template, Goal, Solution) :-
|
||||
( var(H) ->
|
||||
throw(error(instantiation_error, clause/2))
|
||||
; callable(H), functor(H, Name, Arity) ->
|
||||
( '$head_is_dynamic'(Module, H) ->
|
||||
( '$no_such_predicate'(Module, H) ->
|
||||
'$fail'
|
||||
; '$head_is_dynamic'(Module, H) ->
|
||||
'$clause_body_is_valid'(B),
|
||||
Module:'$clause'(H, B)
|
||||
; '$no_such_predicate'(Module, H) ->
|
||||
'$fail'
|
||||
; throw(error(permission_error(access, private_procedure, Name/Arity),
|
||||
clause/2))
|
||||
)
|
||||
@@ -800,12 +830,11 @@ clause(H, B) :-
|
||||
arg(1, H, Module),
|
||||
arg(2, H, F),
|
||||
'$module_clause'(F, B, Module)
|
||||
; '$no_such_predicate'(user, H) ->
|
||||
'$fail'
|
||||
; '$head_is_dynamic'(user, H) ->
|
||||
'$clause_body_is_valid'(B),
|
||||
'$clause'(H, B)
|
||||
; '$no_such_predicate'(user, H) -> %% '$no_such_predicate' fails if
|
||||
%% H is not callable.
|
||||
'$fail'
|
||||
; throw(error(permission_error(access, private_procedure, Name/Arity),
|
||||
clause/2))
|
||||
)
|
||||
@@ -854,13 +883,14 @@ asserta_clause(Head, Body) :-
|
||||
|
||||
:- meta_predicate asserta(0).
|
||||
|
||||
asserta(Clause) :-
|
||||
asserta(Clause0) :-
|
||||
loader:strip_module(Clause0, Module, Clause),
|
||||
( Clause \= (_ :- _) ->
|
||||
Head = Clause,
|
||||
Body = true,
|
||||
asserta_clause(Head, Body)
|
||||
module_asserta_clause(Head, Body, Module)
|
||||
; Clause = (Head :- Body) ->
|
||||
asserta_clause(Head, Body)
|
||||
module_asserta_clause(Head, Body, Module)
|
||||
).
|
||||
|
||||
module_assertz_clause(Head, Body, Module) :-
|
||||
@@ -909,13 +939,14 @@ assertz_clause(Head, Body) :-
|
||||
|
||||
:- meta_predicate assertz(0).
|
||||
|
||||
assertz(Clause) :-
|
||||
assertz(Clause0) :-
|
||||
loader:strip_module(Clause0, Module, Clause),
|
||||
( Clause \= (_ :- _) ->
|
||||
Head = Clause,
|
||||
Body = true,
|
||||
assertz_clause(Head, Body)
|
||||
module_assertz_clause(Head, Body, Module)
|
||||
; Clause = (Head :- Body) ->
|
||||
assertz_clause(Head, Body)
|
||||
module_assertz_clause(Head, Body, Module)
|
||||
).
|
||||
|
||||
|
||||
@@ -999,13 +1030,14 @@ retract_clause(Head, Body) :-
|
||||
:- meta_predicate retract(0).
|
||||
|
||||
retract(Clause0) :-
|
||||
strip_module(Clause0, Module, Clause),
|
||||
( Clause = (Head :- Body) ->
|
||||
true
|
||||
; Head = Clause,
|
||||
Body = true
|
||||
),
|
||||
retract_clause(Module:Head, Body).
|
||||
loader:strip_module(Clause0, Module, Clause),
|
||||
( Clause \= (_ :- _) ->
|
||||
Head = Clause,
|
||||
Body = true,
|
||||
retract_module_clause(Head, Body, Module)
|
||||
; Clause = (Head :- Body) ->
|
||||
retract_module_clause(Head, Body, Module)
|
||||
).
|
||||
|
||||
|
||||
:- meta_predicate retractall(0).
|
||||
@@ -1022,8 +1054,10 @@ module_abolish(Pred, Module) :-
|
||||
; Pred = Name/Arity ->
|
||||
( var(Name) ->
|
||||
throw(error(instantiation_error, abolish/1))
|
||||
; var(Arity) ->
|
||||
throw(error(instantiation_error, abolish/1))
|
||||
; integer(Arity) ->
|
||||
( \+ atom(Name) ->
|
||||
(\+ atom(Name) ->
|
||||
throw(error(type_error(atom, Name), abolish/1))
|
||||
; Arity < 0 ->
|
||||
throw(error(domain_error(not_less_than_zero, Arity), abolish/1))
|
||||
@@ -1075,17 +1109,16 @@ abolish(Pred) :-
|
||||
; throw(error(type_error(predicate_indicator, Pred), abolish/1))
|
||||
).
|
||||
|
||||
'$iterate_db_refs'(Ref, Name/Arity) :-
|
||||
'$lookup_db_ref'(Ref, Name, Arity).
|
||||
'$iterate_db_refs'(Ref, Name/Arity) :-
|
||||
'$get_next_db_ref'(Ref, NextRef),
|
||||
'$iterate_db_refs'(NextRef, Name/Arity).
|
||||
|
||||
'$iterate_db_refs'(Name, Arity, Name/Arity). % :-
|
||||
% '$lookup_db_ref'(Ref, Name, Arity).
|
||||
'$iterate_db_refs'(RName, RArity, Name/Arity) :-
|
||||
'$get_next_db_ref'(RName, RArity, RRName, RRArity),
|
||||
'$iterate_db_refs'(RRName, RRArity, Name/Arity).
|
||||
|
||||
current_predicate(Pred) :-
|
||||
( var(Pred) ->
|
||||
'$get_next_db_ref'(Ref, _),
|
||||
'$iterate_db_refs'(Ref, Pred)
|
||||
'$get_next_db_ref'(RN, RA, _, _),
|
||||
'$iterate_db_refs'(RN, RA, Pred)
|
||||
; Pred \= _/_ ->
|
||||
throw(error(type_error(predicate_indicator, Pred), current_predicate/1))
|
||||
; Pred = Name/Arity,
|
||||
@@ -1094,15 +1127,14 @@ current_predicate(Pred) :-
|
||||
; integer(Arity), Arity < 0
|
||||
) ->
|
||||
throw(error(type_error(predicate_indicator, Pred), current_predicate/1))
|
||||
; '$get_next_db_ref'(Ref, _),
|
||||
'$iterate_db_refs'(Ref, Pred)
|
||||
; '$get_next_db_ref'(RN, RA, _, _),
|
||||
'$iterate_db_refs'(RN, RA, Pred)
|
||||
).
|
||||
|
||||
'$iterate_op_db_refs'(Ref, Priority, Spec, Op) :-
|
||||
'$lookup_op_db_ref'(Ref, Priority, Spec, Op).
|
||||
'$iterate_op_db_refs'(Ref, Priority, Spec, Op) :-
|
||||
'$get_next_op_db_ref'(Ref, NextRef),
|
||||
'$iterate_op_db_refs'(NextRef, Priority, Spec, Op).
|
||||
'$iterate_op_db_refs'(RPriority, RSpec, ROp, _, RPriority, RSpec, ROp).
|
||||
'$iterate_op_db_refs'(RPriority, RSpec, ROp, OssifiedOpDir, Priority, Spec, Op) :-
|
||||
'$get_next_op_db_ref'(RPriority, RSpec, ROp, OssifiedOpDir, RRPriority, RRSpec, RROp),
|
||||
'$iterate_op_db_refs'(RRPriority, RRSpec, RROp, OssifiedOpDir, Priority, Spec, Op).
|
||||
|
||||
can_be_op_priority(Priority) :- var(Priority).
|
||||
can_be_op_priority(Priority) :- op_priority(Priority).
|
||||
@@ -1114,8 +1146,8 @@ current_op(Priority, Spec, Op) :-
|
||||
( can_be_op_priority(Priority),
|
||||
can_be_op_specifier(Spec),
|
||||
error:can_be(atom, Op) ->
|
||||
'$get_next_op_db_ref'(Ref, _),
|
||||
'$iterate_op_db_refs'(Ref, Priority, Spec, Op)
|
||||
'$get_next_op_db_ref'(RPriority, RSpec, ROp, OssifiedOpDir, _, _, Op),
|
||||
'$iterate_op_db_refs'(RPriority, RSpec, ROp, OssifiedOpDir, Priority, Spec, Op)
|
||||
).
|
||||
|
||||
list_of_op_atoms(Var) :-
|
||||
@@ -1209,7 +1241,7 @@ atom_length(Atom, Length) :-
|
||||
).
|
||||
|
||||
atom_chars(Atom, List) :-
|
||||
'$skip_max_list'(_, -1, List, Tail),
|
||||
'$skip_max_list'(_, _, List, Tail),
|
||||
( ( Tail == [] ; var(Tail) ) ->
|
||||
true
|
||||
; throw(error(type_error(list, List), atom_chars/2))
|
||||
@@ -1227,7 +1259,7 @@ atom_chars(Atom, List) :-
|
||||
).
|
||||
|
||||
atom_codes(Atom, List) :-
|
||||
'$skip_max_list'(_, -1, List, Tail),
|
||||
'$skip_max_list'(_, _, List, Tail),
|
||||
( ( Tail == [] ; var(Tail) ) ->
|
||||
true
|
||||
; throw(error(type_error(list, List), atom_codes/2))
|
||||
@@ -1284,9 +1316,9 @@ sub_atom(Atom, Before, Length, After, Sub_atom) :-
|
||||
; atom_chars(Atom, AtomChars),
|
||||
lists:append(BeforeChars, LengthAndAfterChars, AtomChars),
|
||||
lists:append(LengthChars, AfterChars, LengthAndAfterChars),
|
||||
'$skip_max_list'(Before, -1, BeforeChars, []),
|
||||
'$skip_max_list'(Length, -1, LengthChars, []),
|
||||
'$skip_max_list'(After, -1, AfterChars, []),
|
||||
'$skip_max_list'(Before, _, BeforeChars, []),
|
||||
'$skip_max_list'(Length, _, LengthChars, []),
|
||||
'$skip_max_list'(After, _, AfterChars, []),
|
||||
atom_chars(Sub_atom, LengthChars)
|
||||
).
|
||||
|
||||
@@ -1481,7 +1513,8 @@ open(SourceSink, Mode, Stream, StreamOptions) :-
|
||||
atom(SourceSink) ->
|
||||
atom_chars(SourceSink, SourceSinkString)
|
||||
; SourceSink = SourceSinkString
|
||||
), '$open'(SourceSinkString, Mode, Stream, Alias, EOFAction, Reposition, Type)
|
||||
),
|
||||
'$open'(SourceSinkString, Mode, Stream, Alias, EOFAction, Reposition, Type)
|
||||
)
|
||||
).
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
:- module(charsio, [char_type/2,
|
||||
chars_utf8bytes/2,
|
||||
get_single_char/1,
|
||||
read_n_chars/3,
|
||||
get_n_chars/3,
|
||||
read_line_to_chars/3,
|
||||
read_term_from_chars/2,
|
||||
read_from_chars/2,
|
||||
write_term_to_chars/3,
|
||||
chars_base64/3]).
|
||||
|
||||
@@ -113,18 +113,8 @@ get_single_char(C) :-
|
||||
).
|
||||
|
||||
|
||||
read_term_from_chars(Chars, Term) :-
|
||||
( var(Chars) ->
|
||||
instantiation_error(read_term_from_chars/2)
|
||||
; nonvar(Term) ->
|
||||
throw(error(uninstantiation_error(Term), read_term_from_chars/2))
|
||||
; '$skip_max_list'(_, -1, Chars, Chars0),
|
||||
Chars0 == [],
|
||||
partial_string(Chars) ->
|
||||
true
|
||||
;
|
||||
type_error(complete_string, Chars, read_term_from_chars/2)
|
||||
),
|
||||
read_from_chars(Chars, Term) :-
|
||||
must_be(chars, Chars),
|
||||
'$read_term_from_chars'(Chars, Term).
|
||||
|
||||
|
||||
@@ -205,7 +195,7 @@ read_line_to_chars(Stream, Cs0, Cs) :-
|
||||
characters read.
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
read_n_chars(Stream, N, Cs) :-
|
||||
get_n_chars(Stream, N, Cs) :-
|
||||
can_be(integer, N),
|
||||
( var(N) ->
|
||||
read_to_eof(Stream, Cs),
|
||||
|
||||
@@ -6169,7 +6169,7 @@ distinct_goals_([flow_to(F,To)|Es], V) -->
|
||||
get_attr(To, lowlink, L2),
|
||||
L1 =\= L2 } ->
|
||||
{ get_attr(To, value, N) },
|
||||
[neq_num(V, N)]
|
||||
[clpz:neq_num(V, N)]
|
||||
; []
|
||||
),
|
||||
distinct_goals_(Es, V).
|
||||
@@ -6690,7 +6690,7 @@ gcc_edge_goal(arc_to(_,_,V,F), Val) -->
|
||||
get_attr(Val, lowlink, L2),
|
||||
L1 =\= L2,
|
||||
get_attr(Val, value, Value) } ->
|
||||
[neq_num(V, Value)]
|
||||
[clpz:neq_num(V, Value)]
|
||||
; []
|
||||
).
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Written 2020, 2021 by Markus Triska (triska@metalevel.at)
|
||||
Written 2020, 2021, 2022 by Markus Triska (triska@metalevel.at)
|
||||
Part of Scryer Prolog.
|
||||
|
||||
Predicates for cryptographic applications.
|
||||
@@ -46,6 +46,7 @@
|
||||
:- use_module(library(format)).
|
||||
:- use_module(library(charsio)).
|
||||
:- use_module(library(si)).
|
||||
:- use_module(library(iso_ext), [partial_string/3]).
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
hex_bytes(?Hex, ?Bytes) is det.
|
||||
@@ -594,7 +595,9 @@ crypto_data_decrypt(CipherText0, Algorithm, Key, IV, PlainText, Options) :-
|
||||
member(Encoding, [utf8,octet]),
|
||||
encoding_chars(octet, CipherText0, CipherText1),
|
||||
maplist(char_code, TagChars, Tag),
|
||||
append(CipherText1, TagChars, CipherText),
|
||||
% we append the tag very efficiently, retaining a compact
|
||||
% internal string representation of the ciphertext
|
||||
partial_string(CipherText1, CipherText, TagChars),
|
||||
( Algorithm = 'chacha20-poly1305' -> true
|
||||
; domain_error('chacha20-poly1305', Algorithm, crypto_data_decrypt/6)
|
||||
),
|
||||
|
||||
181
src/lib/dcgs.pl
181
src/lib/dcgs.pl
@@ -1,16 +1,26 @@
|
||||
:- module(dcgs,
|
||||
[op(1105, xfy, '|'),
|
||||
phrase/2,
|
||||
phrase/3,
|
||||
seq//1,
|
||||
seqq//1,
|
||||
... //0
|
||||
]).
|
||||
phrase/2,
|
||||
phrase/3,
|
||||
seq//1,
|
||||
seqq//1,
|
||||
... //0
|
||||
]).
|
||||
|
||||
:- use_module(library(error)).
|
||||
:- use_module(library(lists), [append/3]).
|
||||
:- use_module(library(lists), [append/3, member/2]).
|
||||
:- use_module(library(loader), [strip_module/3]).
|
||||
|
||||
load_context(GRBody, Module, GRBody0) :-
|
||||
strip_module(GRBody, Module, GRBody0),
|
||||
( nonvar(Module) ->
|
||||
true
|
||||
; prolog_load_context(module, Module) ->
|
||||
true
|
||||
; true
|
||||
).
|
||||
|
||||
|
||||
:- meta_predicate phrase(2, ?).
|
||||
|
||||
:- meta_predicate phrase(2, ?, ?).
|
||||
@@ -18,100 +28,44 @@
|
||||
phrase(GRBody, S0) :-
|
||||
phrase(GRBody, S0, []).
|
||||
|
||||
|
||||
phrase(GRBody, S0, S) :-
|
||||
( var(GRBody) ->
|
||||
throw(error(instantiation_error, phrase/3))
|
||||
; strip_module(GRBody, Module, GRBody0),
|
||||
dcg_constr(GRBody0) ->
|
||||
( var(Module) ->
|
||||
phrase_(GRBody0, S0, S)
|
||||
; phrase_(Module:GRBody0, S0, S)
|
||||
)
|
||||
; functor(GRBody, _, _) ->
|
||||
call(GRBody, S0, S)
|
||||
; throw(error(type_error(callable, GRBody), phrase/3))
|
||||
load_context(GRBody, Module, GRBody0),
|
||||
( var(GRBody0) ->
|
||||
instantiation_error(phrase/3)
|
||||
; dcg_body(GRBody0, S0, S, GRBody1, Module) ->
|
||||
call(GRBody1)
|
||||
; type_error(callable, GRBody0, phrase/3)
|
||||
).
|
||||
|
||||
phrase_([], S, S).
|
||||
phrase_(!, S, S).
|
||||
phrase_(_:[], S, S) :- !.
|
||||
phrase_(_:!, S, S) :- !.
|
||||
phrase_((A, B), S0, S) :-
|
||||
phrase(A, S0, S1), phrase(B, S1, S).
|
||||
phrase_(M:(A, B), S0, S) :-
|
||||
!,
|
||||
phrase(M:A, S0, S1), phrase(M:B, S1, S).
|
||||
phrase_((A -> B ; C), S0, S) :-
|
||||
!,
|
||||
( phrase(A, S0, S1) ->
|
||||
phrase(B, S1, S)
|
||||
; phrase(C, S0, S)
|
||||
|
||||
module_call_qualified(M, Call, Call1) :-
|
||||
( nonvar(M) -> Call1 = M:Call
|
||||
; Call = Call1
|
||||
).
|
||||
phrase_(M:(A -> B ; C), S0, S) :-
|
||||
!,
|
||||
( phrase(M:A, S0, S1) ->
|
||||
phrase(M:B, S1, S)
|
||||
; phrase(M:C, S0, S)
|
||||
).
|
||||
phrase_((A ; B), S0, S) :-
|
||||
( phrase(A, S0, S) ; phrase(B, S0, S) ).
|
||||
phrase_(M:(A ; B), S0, S) :-
|
||||
!,
|
||||
( phrase(M:A, S0, S) ; phrase(M:B, S0, S) ).
|
||||
phrase_((A | B), S0, S) :-
|
||||
( phrase(A, S0, S) ; phrase(B, S0, S) ).
|
||||
phrase_(M:(A | B), S0, S) :-
|
||||
!,
|
||||
( phrase(M:A, S0, S) ; phrase(M:B, S0, S) ).
|
||||
phrase_({G}, S0, S) :-
|
||||
( call(G), S0 = S ).
|
||||
phrase_(M:{G}, S0, S) :-
|
||||
!,
|
||||
( call(M:G), S0 = S ).
|
||||
phrase_(call(G), S0, S) :-
|
||||
call(G, S0, S).
|
||||
phrase_(M:call(G), S0, S) :-
|
||||
!,
|
||||
call(M:G, S0, S).
|
||||
phrase_((A -> B), S0, S) :-
|
||||
phrase((A -> B ; fail), S0, S).
|
||||
phrase_(M:(A -> B), S0, S) :-
|
||||
!,
|
||||
phrase((M:A -> M:B ; fail), S0, S).
|
||||
phrase_(phrase(NonTerminal), S0, S) :-
|
||||
phrase(NonTerminal, S0, S).
|
||||
phrase_(M:phrase(NonTerminal), S0, S) :-
|
||||
!,
|
||||
phrase(M:NonTerminal, S0, S).
|
||||
phrase_([T|Ts], S0, S) :-
|
||||
append([T|Ts], S, S0).
|
||||
phrase_(_:[T|Ts], S0, S) :-
|
||||
append([T|Ts], S, S0).
|
||||
|
||||
|
||||
% The same version of the below two dcg_rule clauses, but with module scoping.
|
||||
dcg_rule(( M:NonTerminal, Terminals --> GRBody ), ( M:Head :- Body )) :-
|
||||
dcg_non_terminal(NonTerminal, S0, S, Head),
|
||||
dcg_body(GRBody, S0, S1, Goal1),
|
||||
dcg_body(GRBody, S0, S1, Goal1, _),
|
||||
dcg_terminals(Terminals, S, S1, Goal2),
|
||||
Body = ( Goal1, Goal2 ).
|
||||
dcg_rule(( M:NonTerminal --> GRBody ), ( M:Head :- Body )) :-
|
||||
NonTerminal \= ( _, _ ),
|
||||
dcg_non_terminal(NonTerminal, S0, S, Head),
|
||||
dcg_body(GRBody, S0, S, Body).
|
||||
dcg_body(GRBody, S0, S, Body, _).
|
||||
|
||||
% This program uses append/3 as defined in the Prolog prologue.
|
||||
% Expands a DCG rule into a Prolog rule, when no error condition applies.
|
||||
dcg_rule(( NonTerminal, Terminals --> GRBody ), ( Head :- Body )) :-
|
||||
dcg_non_terminal(NonTerminal, S0, S, Head),
|
||||
dcg_body(GRBody, S0, S1, Goal1),
|
||||
dcg_body(GRBody, S0, S1, Goal1, _),
|
||||
dcg_terminals(Terminals, S, S1, Goal2),
|
||||
Body = ( Goal1, Goal2 ).
|
||||
dcg_rule(( NonTerminal --> GRBody ), ( Head :- Body )) :-
|
||||
NonTerminal \= ( _, _ ),
|
||||
dcg_non_terminal(NonTerminal, S0, S, Head),
|
||||
dcg_body(GRBody, S0, S, Body).
|
||||
dcg_body(GRBody, S0, S, Body, _).
|
||||
|
||||
dcg_non_terminal(NonTerminal, S0, S, Goal) :-
|
||||
NonTerminal =.. NonTerminalUniv,
|
||||
@@ -121,18 +75,20 @@ dcg_non_terminal(NonTerminal, S0, S, Goal) :-
|
||||
dcg_terminals(Terminals, S0, S, S0 = List) :-
|
||||
append(Terminals, S, List).
|
||||
|
||||
dcg_body(Var, S0, S, Body) :-
|
||||
dcg_body(Var, S0, S, Body, M) :-
|
||||
var(Var),
|
||||
Body = phrase(Var, S0, S).
|
||||
dcg_body(GRBody, S0, S, Body) :-
|
||||
module_call_qualified(M, Var, Var1),
|
||||
Body = phrase(Var1, S0, S).
|
||||
dcg_body(GRBody, S0, S, Body, M) :-
|
||||
nonvar(GRBody),
|
||||
dcg_constr(GRBody),
|
||||
dcg_cbody(GRBody, S0, S, Body).
|
||||
dcg_body(NonTerminal, S0, S, Goal) :-
|
||||
dcg_cbody(GRBody, S0, S, Body, M).
|
||||
dcg_body(NonTerminal, S0, S, Goal1, M) :-
|
||||
nonvar(NonTerminal),
|
||||
\+ dcg_constr(NonTerminal),
|
||||
NonTerminal \= ( _ -> _ ),
|
||||
NonTerminal \= ( \+ _ ),
|
||||
module_call_qualified(M, Goal, Goal1),
|
||||
dcg_non_terminal(NonTerminal, S0, S, Goal).
|
||||
|
||||
% The following constructs in a grammar rule body
|
||||
@@ -151,37 +107,40 @@ dcg_constr((_->_)). % 7.14.12 - if-then (existence implementation dep.)
|
||||
|
||||
% The principal functor of the first argument indicates
|
||||
% the construct to be expanded.
|
||||
dcg_cbody([], S0, S, S0 = S).
|
||||
dcg_cbody([T|Ts], S0, S, Goal) :-
|
||||
dcg_cbody([], S0, S, S0 = S, _M).
|
||||
dcg_cbody([T|Ts], S0, S, Goal, _M) :-
|
||||
must_be(list, [T|Ts]),
|
||||
dcg_terminals([T|Ts], S0, S, Goal).
|
||||
dcg_cbody(( GRFirst, GRSecond ), S0, S, ( First, Second )) :-
|
||||
dcg_body(GRFirst, S0, S1, First),
|
||||
dcg_body(GRSecond, S1, S, Second).
|
||||
dcg_cbody(( GREither ; GROr ), S0, S, ( Either ; Or )) :-
|
||||
dcg_cbody(( GRFirst, GRSecond ), S0, S, ( First, Second ), M) :-
|
||||
dcg_body(GRFirst, S0, S1, First, M),
|
||||
dcg_body(GRSecond, S1, S, Second, M).
|
||||
dcg_cbody(( GREither ; GROr ), S0, S, ( Either ; Or ), M) :-
|
||||
\+ subsumes_term(( _ -> _ ), GREither),
|
||||
dcg_body(GREither, S0, S, Either),
|
||||
dcg_body(GROr, S0, S, Or).
|
||||
dcg_cbody(( GRCond ; GRElse ), S0, S, ( Cond ; Else )) :-
|
||||
dcg_body(GREither, S0, S, Either, M),
|
||||
dcg_body(GROr, S0, S, Or, M).
|
||||
dcg_cbody(( GRCond ; GRElse ), S0, S, ( Cond ; Else ), M) :-
|
||||
subsumes_term(( _GRIf -> _GRThen ), GRCond),
|
||||
dcg_cbody(GRCond, S0, S, Cond),
|
||||
dcg_body(GRElse, S0, S, Else).
|
||||
dcg_cbody(( GREither '|' GROr ), S0, S, ( Either ; Or )) :-
|
||||
dcg_body(GREither, S0, S, Either),
|
||||
dcg_body(GROr, S0, S, Or).
|
||||
dcg_cbody({Goal}, S0, S, ( Goal, S0 = S )).
|
||||
dcg_cbody(call(Cont), S0, S, call(Cont, S0, S)).
|
||||
dcg_cbody(phrase(Body), S0, S, phrase(Body, S0, S)).
|
||||
dcg_cbody(!, S0, S, ( !, S0 = S )).
|
||||
dcg_cbody(\+ GRBody, S0, S, ( \+ phrase(GRBody,S0,_), S0 = S )).
|
||||
dcg_cbody(( GRIf -> GRThen ), S0, S, ( If -> Then )) :-
|
||||
dcg_body(GRIf, S0, S1, If),
|
||||
dcg_body(GRThen, S1, S, Then).
|
||||
dcg_cbody(GRCond, S0, S, Cond, M),
|
||||
dcg_body(GRElse, S0, S, Else, M).
|
||||
dcg_cbody(( GREither '|' GROr ), S0, S, ( Either ; Or ), M) :-
|
||||
dcg_body(GREither, S0, S, Either, M),
|
||||
dcg_body(GROr, S0, S, Or, M).
|
||||
dcg_cbody({Goal}, S0, S, ( Goal1, S0 = S ), M) :-
|
||||
module_call_qualified(M, Goal, Goal1).
|
||||
dcg_cbody(call(Cont), S0, S, call(Cont1, S0, S), M) :-
|
||||
module_call_qualified(M, Cont, Cont1).
|
||||
dcg_cbody(phrase(Body), S0, S, phrase(Body1, S0, S), M) :-
|
||||
module_call_qualified(M, Body, Body1).
|
||||
dcg_cbody(!, S0, S, ( !, S0 = S ), _M).
|
||||
dcg_cbody(\+ GRBody, S0, S, ( \+ phrase(GRBody1,S0,_), S0 = S ), M) :-
|
||||
module_call_qualified(M, GRBody, GRBody1).
|
||||
dcg_cbody(( GRIf -> GRThen ), S0, S, ( If -> Then ), M) :-
|
||||
dcg_body(GRIf, S0, S1, If, M),
|
||||
dcg_body(GRThen, S1, S, Then, M).
|
||||
|
||||
user:term_expansion(Term0, Term) :-
|
||||
nonvar(Term0),
|
||||
dcg_rule(Term0, (Head :- Body)),
|
||||
Term = (Head :- Body).
|
||||
dcg_rule(Term0, Term).
|
||||
|
||||
% Describes a sequence
|
||||
seq([]) --> [].
|
||||
@@ -193,3 +152,13 @@ seqq([Es|Ess]) --> seq(Es), seqq(Ess).
|
||||
|
||||
% Describes an arbitrary number of elements
|
||||
... --> [] | [_], ... .
|
||||
|
||||
user:goal_expansion(phrase(GRBody, S, S0), GRBody1) :-
|
||||
load_context(GRBody, M, GRBody0),
|
||||
nonvar(GRBody0),
|
||||
catch(dcgs:dcg_body(GRBody0, S, S0, GRBody1, M),
|
||||
error(E, must_be/2),
|
||||
( GRBody1 = throw(error(E, must_be/2)) )
|
||||
).
|
||||
|
||||
user:goal_expansion(phrase(GRBody, S), phrase(GRBody, S, [])).
|
||||
|
||||
@@ -80,7 +80,7 @@ character(C) :-
|
||||
atom_length(C, 1).
|
||||
|
||||
ilist(Ls) :-
|
||||
'$skip_max_list'(_, -1, Ls, Rs),
|
||||
'$skip_max_list'(_, _, Ls, Rs),
|
||||
( var(Rs) ->
|
||||
instantiation_error(must_be/2)
|
||||
; Rs == []
|
||||
@@ -124,7 +124,7 @@ can_(list, Term) :- list_or_partial_list(Term).
|
||||
can_(boolean, Term) :- boolean(Term).
|
||||
|
||||
list_or_partial_list(Ls) :-
|
||||
'$skip_max_list'(_, -1, Ls, Rs),
|
||||
'$skip_max_list'(_, _, Ls, Rs),
|
||||
( var(Rs) -> true
|
||||
; Rs == []
|
||||
).
|
||||
|
||||
@@ -174,7 +174,7 @@ file_creation_time(File, T) :-
|
||||
file_time_(File, Which, T) :-
|
||||
file_must_exist(File, file_time_/3),
|
||||
'$file_time'(File, Which, T0),
|
||||
read_term_from_chars(T0, T).
|
||||
read_from_chars(T0, T).
|
||||
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Written 2020, 2021 by Markus Triska (triska@metalevel.at)
|
||||
Written 2020, 2021, 2022 by Markus Triska (triska@metalevel.at)
|
||||
Part of Scryer Prolog.
|
||||
|
||||
This library provides the nonterminal format_//2 to describe
|
||||
@@ -28,6 +28,9 @@
|
||||
if N is 0 or omitted, no decimal point is used.
|
||||
~ND like ~Nd, separating digits to the left of the decimal point
|
||||
in groups of three, using the character "," (comma)
|
||||
~NU like ~ND, using "_" (underscore) to separate groups of digits
|
||||
~NL format an integer so that at most N digits appear on a line.
|
||||
If N is 0 or omitted, it defaults to 72.
|
||||
~Nr where N is an integer between 2 and 36: format the
|
||||
next argument, which must be an integer, in radix N.
|
||||
The characters "a" to "z" are used for radices 10 to 36.
|
||||
@@ -200,14 +203,22 @@ cells([~|Fs0], Args0, Tab, Es, VNs) -->
|
||||
cells([~|Fs0], Args0, Tab, Es, VNs) -->
|
||||
{ numeric_argument(Fs0, Num, ['D'|Fs], Args0, [Arg|Args]) },
|
||||
!,
|
||||
{ number_chars(Num, NCs),
|
||||
phrase(("~",seq(NCs),"d"), FStr),
|
||||
phrase(format_(FStr, [Arg]), Cs0),
|
||||
phrase(upto_what(Bs0, .), Cs0, Ds),
|
||||
reverse(Bs0, Bs1),
|
||||
phrase(groups_of_three(Bs1), Bs2),
|
||||
reverse(Bs2, Bs),
|
||||
append(Bs, Ds, Cs) },
|
||||
{ separate_digits_fractional(Arg, ',', Num, Cs) },
|
||||
cells(Fs, Args, Tab, [chars(Cs)|Es], VNs).
|
||||
cells([~|Fs0], Args0, Tab, Es, VNs) -->
|
||||
{ numeric_argument(Fs0, Num, ['U'|Fs], Args0, [Arg|Args]) },
|
||||
!,
|
||||
{ separate_digits_fractional(Arg, '_', Num, Cs) },
|
||||
cells(Fs, Args, Tab, [chars(Cs)|Es], VNs).
|
||||
cells([~|Fs0], Args0, Tab, Es, VNs) -->
|
||||
{ numeric_argument(Fs0, Num0, ['L'|Fs], Args0, [Arg|Args]) },
|
||||
!,
|
||||
{ ( Num0 =:= 0 ->
|
||||
Num = 72
|
||||
; Num = Num0
|
||||
),
|
||||
phrase(format_("~d", [Arg]), Cs0),
|
||||
phrase(split_lines_width(Cs0, Num), Cs) },
|
||||
cells(Fs, Args, Tab, [chars(Cs)|Es], VNs).
|
||||
cells([~,i|Fs], [_|Args], Tab, Es, VNs) --> !,
|
||||
cells(Fs, Args, Tab, Es, VNs).
|
||||
@@ -312,12 +323,30 @@ Cs = [a,b,c], Rest = [~,t,e,s,t].
|
||||
Cs = [a,b,c], Rest = [].
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
separate_digits_fractional(Arg, Sep, Num, Cs) :-
|
||||
number_chars(Num, NCs),
|
||||
phrase(("~",seq(NCs),"d"), FStr),
|
||||
phrase(format_(FStr, [Arg]), Cs0),
|
||||
phrase(upto_what(Bs0, .), Cs0, Ds),
|
||||
reverse(Bs0, Bs1),
|
||||
phrase(groups_of_three(Bs1,Sep), Bs2),
|
||||
reverse(Bs2, Bs),
|
||||
append(Bs, Ds, Cs).
|
||||
|
||||
upto_what([], W), [W] --> [W], !.
|
||||
upto_what([C|Cs], W) --> [C], !, upto_what(Cs, W).
|
||||
upto_what([], _) --> [].
|
||||
|
||||
groups_of_three([A,B,C,D|Rs]) --> !, [A,B,C], ",", groups_of_three([D|Rs]).
|
||||
groups_of_three(Ls) --> seq(Ls).
|
||||
groups_of_three([A,B,C,D|Rs], Sep) --> !, [A,B,C,Sep], groups_of_three([D|Rs], Sep).
|
||||
groups_of_three(Ls, _) --> seq(Ls).
|
||||
|
||||
split_lines_width(Cs, Num) -->
|
||||
( { length(Prefix, Num),
|
||||
append(Prefix, [R|Rs], Cs) } ->
|
||||
seq(Prefix), "_\n",
|
||||
split_lines_width([R|Rs], Num)
|
||||
; seq(Cs)
|
||||
).
|
||||
|
||||
cell(From, To, Es0) -->
|
||||
( { Es0 == [] } -> []
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
partial_string_tail/2,
|
||||
setup_call_cleanup/3,
|
||||
call_nth/2,
|
||||
variant/2,
|
||||
% variant/2,
|
||||
copy_term_nat/2]).
|
||||
|
||||
:- use_module(library(error), [can_be/2,
|
||||
@@ -22,10 +22,7 @@
|
||||
instantiation_error/1,
|
||||
type_error/3]).
|
||||
|
||||
|
||||
:- meta_predicate(call_cleanup(0, 0)).
|
||||
|
||||
:- meta_predicate(setup_call_cleanup(0, 0, 0)).
|
||||
:- use_module(library(lists), [maplist/3]).
|
||||
|
||||
:- meta_predicate(forall(0, 0)).
|
||||
|
||||
@@ -55,14 +52,17 @@ bb_get(Key, Value) :-
|
||||
).
|
||||
|
||||
|
||||
% setup_call_cleanup.
|
||||
|
||||
:- meta_predicate(call_cleanup(0, 0)).
|
||||
|
||||
call_cleanup(G, C) :- setup_call_cleanup(true, G, C).
|
||||
|
||||
|
||||
% setup_call_cleanup.
|
||||
:- meta_predicate(setup_call_cleanup(0, 0, 0)).
|
||||
|
||||
setup_call_cleanup(S, G, C) :-
|
||||
'$get_b_value'(B),
|
||||
call(S),
|
||||
'$call'(S),
|
||||
'$set_cp_by_default'(B),
|
||||
'$get_current_block'(Bb),
|
||||
( C = _:CC,
|
||||
@@ -71,6 +71,8 @@ setup_call_cleanup(S, G, C) :-
|
||||
; '$call_with_default_policy'(scc_helper(C, G, Bb))
|
||||
).
|
||||
|
||||
:- meta_predicate(scc_helper(?,0,?)).
|
||||
|
||||
:- non_counted_backtracking scc_helper/3.
|
||||
scc_helper(C, G, Bb) :-
|
||||
'$get_cp'(Cp),
|
||||
@@ -96,7 +98,8 @@ scc_helper(_, _, _) :-
|
||||
|
||||
:- non_counted_backtracking run_cleaners_with_handling/0.
|
||||
run_cleaners_with_handling :-
|
||||
'$get_scc_cleaner'(C), '$get_level'(B),
|
||||
'$get_scc_cleaner'(C),
|
||||
'$get_level'(B),
|
||||
'$call_with_default_policy'(catch(C, _, true)),
|
||||
'$set_cp_by_default'(B),
|
||||
'$call_with_default_policy'(run_cleaners_with_handling).
|
||||
@@ -134,16 +137,31 @@ handle_ile(B, E, _) :-
|
||||
:- meta_predicate(call_with_inference_limit(0, ?, ?)).
|
||||
|
||||
call_with_inference_limit(G, L, R) :-
|
||||
( integer(L) ->
|
||||
( L < 0 ->
|
||||
domain_error(not_less_than_zero, L, call_with_inference_limit/3)
|
||||
; true
|
||||
)
|
||||
; var(L) ->
|
||||
instantiation_error(call_with_inference_limit/3)
|
||||
; type_error(integer, L, call_with_inference_limit/3)
|
||||
),
|
||||
'$get_current_block'(Bb),
|
||||
'$get_b_value'(B),
|
||||
'$call_with_default_policy'(call_with_inference_limit(G, L, R, Bb, B)),
|
||||
'$remove_call_policy_check'(B).
|
||||
|
||||
install_inference_counter(B, L, Count0) :-
|
||||
'$install_inference_counter'(B, L, Count0).
|
||||
|
||||
:- meta_predicate(call_with_inference_limit(0,?,?,?,?)).
|
||||
|
||||
:- non_counted_backtracking call_with_inference_limit/5.
|
||||
|
||||
call_with_inference_limit(G, L, R, Bb, B) :-
|
||||
'$install_new_block'(NBb),
|
||||
'$install_inference_counter'(B, L, Count0),
|
||||
call(G),
|
||||
'$call'(G),
|
||||
'$inference_level'(R, B),
|
||||
'$remove_inference_counter'(B, Count1),
|
||||
'$call_with_default_policy'(is(Diff, L - (Count1 - Count0))),
|
||||
@@ -160,14 +178,12 @@ call_with_inference_limit(_, _, R, Bb, B) :-
|
||||
'$erase_ball',
|
||||
'$call_with_default_policy'(handle_ile(B, Ball, R)).
|
||||
|
||||
variant(X, Y) :- '$variant'(X, Y).
|
||||
|
||||
partial_string(String, L, L0) :-
|
||||
( String == [] ->
|
||||
L = L0
|
||||
; catch(atom_chars(Atom, String),
|
||||
error(E, _),
|
||||
throw(error(E, partial_string/3))),
|
||||
error(E, _),
|
||||
throw(error(E, partial_string/3))),
|
||||
'$create_partial_string'(Atom, L, L0)
|
||||
).
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
maplist/3, maplist/4, maplist/5, maplist/6,
|
||||
maplist/7, maplist/8, maplist/9, same_length/2, nth0/3,
|
||||
sum_list/2, transpose/2, list_to_set/2, list_max/2,
|
||||
list_min/2, permutation/2]).
|
||||
list_min/2, permutation/2]).
|
||||
|
||||
/* Author: Mark Thom, Jan Wielemaker, and Richard O'Keefe
|
||||
Copyright (c) 2018-2021, Mark Thom
|
||||
@@ -50,24 +50,20 @@
|
||||
:- meta_predicate foldl(3, ?, ?, ?).
|
||||
:- meta_predicate foldl(4, ?, ?, ?, ?).
|
||||
|
||||
|
||||
length(Xs, N) :-
|
||||
var(N),
|
||||
!,
|
||||
'$skip_max_list'(M, -1, Xs, Xs0),
|
||||
( Xs0 == [] -> N = M
|
||||
; var(Xs0) -> length_addendum(Xs0, N, M)).
|
||||
length(Xs, N) :-
|
||||
integer(N),
|
||||
N >= 0, !,
|
||||
'$skip_max_list'(M, N, Xs, Xs0),
|
||||
( Xs0 == [] -> N = M
|
||||
; var(Xs0) -> R is N-M, length_rundown(Xs0, R)).
|
||||
length(Xs0, N) :-
|
||||
'$skip_max_list'(M, N, Xs0,Xs),
|
||||
!,
|
||||
( Xs == [] -> N = M
|
||||
; nonvar(Xs) -> var(N), Xs = [_|_], throw(error(resource_error(finite_memory),length/2))
|
||||
; nonvar(N) -> R is N-M, length_rundown(Xs, R)
|
||||
; N == Xs -> throw(error(resource_error(finite_memory),length/2))
|
||||
; length_addendum(Xs, N, M)
|
||||
).
|
||||
length(_, N) :-
|
||||
integer(N), !,
|
||||
domain_error(not_less_than_zero, N, length/2).
|
||||
integer(N), !,
|
||||
domain_error(not_less_than_zero, N, length/2).
|
||||
length(_, N) :-
|
||||
type_error(integer, N, length/2).
|
||||
type_error(integer, N, length/2).
|
||||
|
||||
length_addendum([], N, N).
|
||||
length_addendum([_|Xs], N, M) :-
|
||||
@@ -285,8 +281,8 @@ list_min_(N, Min0, Min) :-
|
||||
% or partial list.
|
||||
|
||||
permutation(Xs, Ys) :-
|
||||
'$skip_max_list'(Xlen, -1, Xs, XTail),
|
||||
'$skip_max_list'(Ylen, -1, Ys, YTail),
|
||||
'$skip_max_list'(Xlen, _, Xs, XTail),
|
||||
'$skip_max_list'(Ylen, _, Ys, YTail),
|
||||
( XTail == [], YTail == [] % both proper lists
|
||||
-> Xlen == Ylen
|
||||
; var(XTail), YTail == [] % partial, proper
|
||||
|
||||
@@ -89,7 +89,7 @@ because the order it relies on may have been changed.
|
||||
% setof/3.
|
||||
|
||||
is_ordset(Term) :-
|
||||
'$skip_max_list'(_, -1, Term, Tail), Tail == [], %% is_list(Term),
|
||||
'$skip_max_list'(_, _, Term, Tail), Tail == [], %% is_list(Term),
|
||||
is_ordset2(Term).
|
||||
|
||||
is_ordset2([]).
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
:- use_module(library(freeze)).
|
||||
:- use_module(library(iso_ext), [setup_call_cleanup/3, partial_string/3]).
|
||||
:- use_module(library(lists), [member/2, maplist/2]).
|
||||
:- use_module(library(charsio), [read_n_chars/3]).
|
||||
:- use_module(library(charsio), [get_n_chars/3]).
|
||||
|
||||
:- meta_predicate(phrase_from_file(2, ?)).
|
||||
:- meta_predicate(phrase_from_file(2, ?, ?)).
|
||||
@@ -62,7 +62,7 @@ reader_step(Stream, Pos, Xs0) :-
|
||||
set_stream_position(Stream, Pos),
|
||||
( at_end_of_stream(Stream)
|
||||
-> Xs0 = []
|
||||
; read_n_chars(Stream, 4096, Cs),
|
||||
; get_n_chars(Stream, 4096, Cs),
|
||||
partial_string(Cs, Xs0, Xs),
|
||||
stream_to_lazy_list(Stream, Xs)
|
||||
).
|
||||
|
||||
@@ -22,11 +22,11 @@ random(R) :-
|
||||
random_integer(Lower, Upper, R) :-
|
||||
var(R),
|
||||
( (var(Lower) ; var(Upper)) ->
|
||||
instantiation_error(random_integer/3)
|
||||
instantiation_error(random_integer/3)
|
||||
; \+ integer(Lower) ->
|
||||
domain_error(integer, Lower, random_integer/3)
|
||||
type_error(integer, Lower, random_integer/3)
|
||||
; \+ integer(Upper) ->
|
||||
domain_error(integer, Upper, random_integer/3)
|
||||
type_error(integer, Upper, random_integer/3)
|
||||
; Upper > Lower,
|
||||
random(R0),
|
||||
R is floor((Upper - Lower) * R0 + Lower)
|
||||
|
||||
@@ -79,5 +79,6 @@ tmember(P_2, [X|Xs]) :-
|
||||
|
||||
:- meta_predicate(tmember_t(2, ?, ?)).
|
||||
|
||||
tmember_t(_P_2, [], false).
|
||||
tmember_t(P_2, [X|Xs], T) :-
|
||||
if_( call(P_2, X), T = true, tmember_t(P_2, Xs, T) ).
|
||||
|
||||
@@ -9,26 +9,26 @@
|
||||
syntaxes. The DCGs are presented in the order they appear in the RFC.
|
||||
While some DCGs below use `char_type/2`, the most common ones are defined
|
||||
manually in order to take advantage of Prolog's first-argument indexing.
|
||||
|
||||
|
||||
BSD 3-Clause License
|
||||
|
||||
|
||||
Copyright (c) 2021, Aram Panasenco
|
||||
All rights reserved.
|
||||
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
|
||||
* Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Written Apr 2021 by Aram Panasenco (panasenco@ucla.edu)
|
||||
Part of Scryer Prolog.
|
||||
|
||||
|
||||
`json_chars//1` can be used with [`phrase_from_file/2`](src/lib/pio.pl)
|
||||
or [`phrase/2`](src/lib/dcgs.pl) to parse and generate [JSON](https://www.json.org/json-en.html).
|
||||
|
||||
|
||||
BSD 3-Clause License
|
||||
|
||||
|
||||
Copyright (c) 2021, Aram Panasenco
|
||||
All rights reserved.
|
||||
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
|
||||
* Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
@@ -44,7 +44,7 @@
|
||||
:- use_module(library(dif)).
|
||||
:- use_module(library(lists)).
|
||||
|
||||
/* The DCGs are written to match the McKeeman form presented on the right side of https://www.json.org/json-en.html
|
||||
/* The DCGs are written to match the McKeeman form presented on the right side of https://www.json.org/json-en.html
|
||||
as closely as possible. Note that the names in the McKeeman form conflict with the pictures on the site. */
|
||||
json_chars(Internal) --> json_element(Internal).
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
:- use_module(library(error)).
|
||||
:- use_module(library(dcgs)).
|
||||
:- use_module(library(pio)).
|
||||
:- use_module(library(charsio)).
|
||||
|
||||
load_html(Source, Es, Options) :-
|
||||
load_structure_(Source, Es, Options, html).
|
||||
@@ -75,15 +76,8 @@ load_structure_(file(Fs), [E], Options, What) :-
|
||||
load_(What, Cs, E, Options).
|
||||
load_structure_(stream(Stream), [E], Options, What) :-
|
||||
must_be(list, Options),
|
||||
read_to_end(Stream, Cs),
|
||||
get_n_chars(Stream, _, Cs),
|
||||
load_(What, Cs, E, Options).
|
||||
|
||||
load_(html, Cs, E, Options) :- '$load_html'(Cs, E, Options).
|
||||
load_(xml, Cs, E, Options) :- '$load_xml'(Cs, E, Options).
|
||||
|
||||
read_to_end(Stream, Cs) :-
|
||||
'$get_n_chars'(Stream, 4096, Cs0),
|
||||
( Cs0 = [] -> Cs = []
|
||||
; partial_string(Cs0, Cs, Rest),
|
||||
read_to_end(Stream, Rest)
|
||||
).
|
||||
|
||||
@@ -41,6 +41,8 @@
|
||||
trie_get_all_values/2 % +Trie, -Value
|
||||
]).
|
||||
|
||||
:- use_module(library(format)).
|
||||
|
||||
:- use_module(library(assoc)).
|
||||
:- use_module(library(atts)).
|
||||
:- use_module(library(lists)).
|
||||
|
||||
@@ -49,11 +49,11 @@
|
||||
:- use_module(library(error)).
|
||||
:- use_module(library(dcgs)).
|
||||
:- use_module(library(lists)).
|
||||
:- use_module(library(charsio), [read_term_from_chars/2]).
|
||||
:- use_module(library(charsio), [read_from_chars/2]).
|
||||
|
||||
current_time(T) :-
|
||||
'$current_time'(T0),
|
||||
read_term_from_chars(T0, T).
|
||||
read_from_chars(T0, T).
|
||||
|
||||
format_time([], _) --> [].
|
||||
format_time(['%','%'|Fs], T) --> !, "%", format_time(Fs, T).
|
||||
|
||||
630
src/lib/ugraphs.pl
Normal file
630
src/lib/ugraphs.pl
Normal file
@@ -0,0 +1,630 @@
|
||||
/* Author: R.A.O'Keefe, Vitor Santos Costa, Jan Wielemaker
|
||||
E-mail: J.Wielemaker@vu.nl
|
||||
WWW: http://www.swi-prolog.org
|
||||
Copyright (c) 1984-2021, VU University Amsterdam
|
||||
CWI, Amsterdam
|
||||
SWI-Prolog Solutions .b.v
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
:- module(ugraphs,
|
||||
[ add_edges/3, % +Graph, +Edges, -NewGraph
|
||||
add_vertices/3, % +Graph, +Vertices, -NewGraph
|
||||
complement/2, % +Graph, -NewGraph
|
||||
compose/3, % +LeftGraph, +RightGraph, -NewGraph
|
||||
del_edges/3, % +Graph, +Edges, -NewGraph
|
||||
del_vertices/3, % +Graph, +Vertices, -NewGraph
|
||||
edges/2, % +Graph, -Edges
|
||||
neighbors/3, % +Vertex, +Graph, -Vertices
|
||||
neighbours/3, % +Vertex, +Graph, -Vertices
|
||||
reachable/3, % +Vertex, +Graph, -Vertices
|
||||
top_sort/2, % +Graph, -Sort
|
||||
top_sort/3, % +Graph, -Sort0, -Sort
|
||||
transitive_closure/2, % +Graph, -Closure
|
||||
transpose_ugraph/2, % +Graph, -NewGraph
|
||||
vertices/2, % +Graph, -Vertices
|
||||
vertices_edges_to_ugraph/3, % +Vertices, +Edges, -Graph
|
||||
ugraph_union/3, % +Graph1, +Graph2, -Graph
|
||||
connect_ugraph/3 % +Graph1, -Start, -Graph
|
||||
]).
|
||||
|
||||
/** <module> Graph manipulation library
|
||||
|
||||
The S-representation of a graph is a list of (vertex-neighbours) pairs,
|
||||
where the pairs are in standard order (as produced by keysort) and the
|
||||
neighbours of each vertex are also in standard order (as produced by
|
||||
sort). This form is convenient for many calculations.
|
||||
|
||||
A new UGraph from raw data can be created using
|
||||
vertices_edges_to_ugraph/3.
|
||||
|
||||
Adapted to support some of the functionality of the SICStus ugraphs
|
||||
library by Vitor Santos Costa.
|
||||
|
||||
Ported from YAP 5.0.1 to SWI-Prolog by Jan Wielemaker.
|
||||
|
||||
@author R.A.O'Keefe
|
||||
@author Vitor Santos Costa
|
||||
@author Jan Wielemaker
|
||||
@license BSD-2 or Artistic 2.0
|
||||
*/
|
||||
|
||||
:- use_module(library(lists)).
|
||||
:- use_module(library(pairs)).
|
||||
:- use_module(library(ordsets)).
|
||||
|
||||
%! vertices(+Graph, -Vertices)
|
||||
%
|
||||
% Unify Vertices with all vertices appearing in Graph. Example:
|
||||
%
|
||||
% ?- vertices([1-[3,5],2-[4],3-[],4-[5],5-[]], L).
|
||||
% L = [1, 2, 3, 4, 5]
|
||||
|
||||
vertices([], []) :- !.
|
||||
vertices([Vertex-_|Graph], [Vertex|Vertices]) :-
|
||||
vertices(Graph, Vertices).
|
||||
|
||||
|
||||
%! vertices_edges_to_ugraph(+Vertices, +Edges, -UGraph) is det.
|
||||
%
|
||||
% Create a UGraph from Vertices and edges. Given a graph with a
|
||||
% set of Vertices and a set of Edges, Graph must unify with the
|
||||
% corresponding S-representation. Note that the vertices without
|
||||
% edges will appear in Vertices but not in Edges. Moreover, it is
|
||||
% sufficient for a vertice to appear in Edges.
|
||||
%
|
||||
% ==
|
||||
% ?- vertices_edges_to_ugraph([],[1-3,2-4,4-5,1-5], L).
|
||||
% L = [1-[3,5], 2-[4], 3-[], 4-[5], 5-[]]
|
||||
% ==
|
||||
%
|
||||
% In this case all vertices are defined implicitly. The next
|
||||
% example shows three unconnected vertices:
|
||||
%
|
||||
% ==
|
||||
% ?- vertices_edges_to_ugraph([6,7,8],[1-3,2-4,4-5,1-5], L).
|
||||
% L = [1-[3,5], 2-[4], 3-[], 4-[5], 5-[], 6-[], 7-[], 8-[]]
|
||||
% ==
|
||||
|
||||
vertices_edges_to_ugraph(Vertices, Edges, Graph) :-
|
||||
sort(Edges, EdgeSet),
|
||||
p_to_s_vertices(EdgeSet, IVertexBag),
|
||||
append(Vertices, IVertexBag, VertexBag),
|
||||
sort(VertexBag, VertexSet),
|
||||
p_to_s_group(VertexSet, EdgeSet, Graph).
|
||||
|
||||
|
||||
%! add_vertices(+Graph, +Vertices, -NewGraph)
|
||||
%
|
||||
% Unify NewGraph with a new graph obtained by adding the list of
|
||||
% Vertices to Graph. Example:
|
||||
%
|
||||
% ```
|
||||
% ?- add_vertices([1-[3,5],2-[]], [0,1,2,9], NG).
|
||||
% NG = [0-[], 1-[3,5], 2-[], 9-[]]
|
||||
% ```
|
||||
|
||||
% replace with real msort/2 when available
|
||||
msort_(List, Sorted) :-
|
||||
pairs_keys(Pairs, List),
|
||||
keysort(Pairs, SortedPairs),
|
||||
pairs_keys(SortedPairs, Sorted).
|
||||
|
||||
add_vertices(Graph, Vertices, NewGraph) :-
|
||||
% msort/2 not available in Scryer Prolog yet: msort(Vertices, V1),
|
||||
msort_(Vertices, V1),
|
||||
add_vertices_to_s_graph(V1, Graph, NewGraph).
|
||||
|
||||
add_vertices_to_s_graph(L, [], NL) :-
|
||||
!,
|
||||
add_empty_vertices(L, NL).
|
||||
add_vertices_to_s_graph([], L, L) :- !.
|
||||
add_vertices_to_s_graph([V1|VL], [V-Edges|G], NGL) :-
|
||||
compare(Res, V1, V),
|
||||
add_vertices_to_s_graph(Res, V1, VL, V, Edges, G, NGL).
|
||||
|
||||
add_vertices_to_s_graph(=, _, VL, V, Edges, G, [V-Edges|NGL]) :-
|
||||
add_vertices_to_s_graph(VL, G, NGL).
|
||||
add_vertices_to_s_graph(<, V1, VL, V, Edges, G, [V1-[]|NGL]) :-
|
||||
add_vertices_to_s_graph(VL, [V-Edges|G], NGL).
|
||||
add_vertices_to_s_graph(>, V1, VL, V, Edges, G, [V-Edges|NGL]) :-
|
||||
add_vertices_to_s_graph([V1|VL], G, NGL).
|
||||
|
||||
add_empty_vertices([], []).
|
||||
add_empty_vertices([V|G], [V-[]|NG]) :-
|
||||
add_empty_vertices(G, NG).
|
||||
|
||||
%! del_vertices(+Graph, +Vertices, -NewGraph) is det.
|
||||
%
|
||||
% Unify NewGraph with a new graph obtained by deleting the list of
|
||||
% Vertices and all the edges that start from or go to a vertex in
|
||||
% Vertices to the Graph. Example:
|
||||
%
|
||||
% ==
|
||||
% ?- del_vertices([1-[3,5],2-[4],3-[],4-[5],5-[],6-[],7-[2,6],8-[]],
|
||||
% [2,1],
|
||||
% NL).
|
||||
% NL = [3-[],4-[5],5-[],6-[],7-[6],8-[]]
|
||||
% ==
|
||||
%
|
||||
% @compat Upto 5.6.48 the argument order was (+Vertices, +Graph,
|
||||
% -NewGraph). Both YAP and SWI-Prolog have changed the argument
|
||||
% order for compatibility with recent SICStus as well as
|
||||
% consistency with del_edges/3.
|
||||
|
||||
del_vertices(Graph, Vertices, NewGraph) :-
|
||||
sort(Vertices, V1), % JW: was msort
|
||||
( V1 = []
|
||||
-> Graph = NewGraph
|
||||
; del_vertices(Graph, V1, V1, NewGraph)
|
||||
).
|
||||
|
||||
del_vertices(G, [], V1, NG) :-
|
||||
!,
|
||||
del_remaining_edges_for_vertices(G, V1, NG).
|
||||
del_vertices([], _, _, []).
|
||||
del_vertices([V-Edges|G], [V0|Vs], V1, NG) :-
|
||||
compare(Res, V, V0),
|
||||
split_on_del_vertices(Res, V,Edges, [V0|Vs], NVs, V1, NG, NGr),
|
||||
del_vertices(G, NVs, V1, NGr).
|
||||
|
||||
del_remaining_edges_for_vertices([], _, []).
|
||||
del_remaining_edges_for_vertices([V0-Edges|G], V1, [V0-NEdges|NG]) :-
|
||||
ord_subtract(Edges, V1, NEdges),
|
||||
del_remaining_edges_for_vertices(G, V1, NG).
|
||||
|
||||
split_on_del_vertices(<, V, Edges, Vs, Vs, V1, [V-NEdges|NG], NG) :-
|
||||
ord_subtract(Edges, V1, NEdges).
|
||||
split_on_del_vertices(>, V, Edges, [_|Vs], Vs, V1, [V-NEdges|NG], NG) :-
|
||||
ord_subtract(Edges, V1, NEdges).
|
||||
split_on_del_vertices(=, _, _, [_|Vs], Vs, _, NG, NG).
|
||||
|
||||
%! add_edges(+Graph, +Edges, -NewGraph)
|
||||
%
|
||||
% Unify NewGraph with a new graph obtained by adding the list of Edges
|
||||
% to Graph. Example:
|
||||
%
|
||||
% ```
|
||||
% ?- add_edges([1-[3,5],2-[4],3-[],4-[5],
|
||||
% 5-[],6-[],7-[],8-[]],
|
||||
% [1-6,2-3,3-2,5-7,3-2,4-5],
|
||||
% NL).
|
||||
% NL = [1-[3,5,6], 2-[3,4], 3-[2], 4-[5],
|
||||
% 5-[7], 6-[], 7-[], 8-[]]
|
||||
% ```
|
||||
|
||||
add_edges(Graph, Edges, NewGraph) :-
|
||||
p_to_s_graph(Edges, G1),
|
||||
ugraph_union(Graph, G1, NewGraph).
|
||||
|
||||
%! ugraph_union(+Graph1, +Graph2, -NewGraph)
|
||||
%
|
||||
% NewGraph is the union of Graph1 and Graph2. Example:
|
||||
%
|
||||
% ```
|
||||
% ?- ugraph_union([1-[2],2-[3]],[2-[4],3-[1,2,4]],L).
|
||||
% L = [1-[2], 2-[3,4], 3-[1,2,4]]
|
||||
% ```
|
||||
|
||||
ugraph_union(Set1, [], Set1) :- !.
|
||||
ugraph_union([], Set2, Set2) :- !.
|
||||
ugraph_union([Head1-E1|Tail1], [Head2-E2|Tail2], Union) :-
|
||||
compare(Order, Head1, Head2),
|
||||
ugraph_union(Order, Head1-E1, Tail1, Head2-E2, Tail2, Union).
|
||||
|
||||
ugraph_union(=, Head-E1, Tail1, _-E2, Tail2, [Head-Es|Union]) :-
|
||||
ord_union(E1, E2, Es),
|
||||
ugraph_union(Tail1, Tail2, Union).
|
||||
ugraph_union(<, Head1, Tail1, Head2, Tail2, [Head1|Union]) :-
|
||||
ugraph_union(Tail1, [Head2|Tail2], Union).
|
||||
ugraph_union(>, Head1, Tail1, Head2, Tail2, [Head2|Union]) :-
|
||||
ugraph_union([Head1|Tail1], Tail2, Union).
|
||||
|
||||
%! del_edges(+Graph, +Edges, -NewGraph)
|
||||
%
|
||||
% Unify NewGraph with a new graph obtained by removing the list of
|
||||
% Edges from Graph. Notice that no vertices are deleted. Example:
|
||||
%
|
||||
% ```
|
||||
% ?- del_edges([1-[3,5],2-[4],3-[],4-[5],5-[],6-[],7-[],8-[]],
|
||||
% [1-6,2-3,3-2,5-7,3-2,4-5,1-3],
|
||||
% NL).
|
||||
% NL = [1-[5],2-[4],3-[],4-[],5-[],6-[],7-[],8-[]]
|
||||
% ```
|
||||
|
||||
del_edges(Graph, Edges, NewGraph) :-
|
||||
p_to_s_graph(Edges, G1),
|
||||
graph_subtract(Graph, G1, NewGraph).
|
||||
|
||||
%! graph_subtract(+Set1, +Set2, ?Difference)
|
||||
%
|
||||
% Is based on ord_subtract
|
||||
|
||||
graph_subtract(Set1, [], Set1) :- !.
|
||||
graph_subtract([], _, []).
|
||||
graph_subtract([Head1-E1|Tail1], [Head2-E2|Tail2], Difference) :-
|
||||
compare(Order, Head1, Head2),
|
||||
graph_subtract(Order, Head1-E1, Tail1, Head2-E2, Tail2, Difference).
|
||||
|
||||
graph_subtract(=, H-E1, Tail1, _-E2, Tail2, [H-E|Difference]) :-
|
||||
ord_subtract(E1,E2,E),
|
||||
graph_subtract(Tail1, Tail2, Difference).
|
||||
graph_subtract(<, Head1, Tail1, Head2, Tail2, [Head1|Difference]) :-
|
||||
graph_subtract(Tail1, [Head2|Tail2], Difference).
|
||||
graph_subtract(>, Head1, Tail1, _, Tail2, Difference) :-
|
||||
graph_subtract([Head1|Tail1], Tail2, Difference).
|
||||
|
||||
%! edges(+Graph, -Edges)
|
||||
%
|
||||
% Unify Edges with all edges appearing in Graph. Example:
|
||||
%
|
||||
% ?- edges([1-[3,5],2-[4],3-[],4-[5],5-[]], L).
|
||||
% L = [1-3, 1-5, 2-4, 4-5]
|
||||
|
||||
edges(Graph, Edges) :-
|
||||
s_to_p_graph(Graph, Edges).
|
||||
|
||||
p_to_s_graph(P_Graph, S_Graph) :-
|
||||
sort(P_Graph, EdgeSet),
|
||||
p_to_s_vertices(EdgeSet, VertexBag),
|
||||
sort(VertexBag, VertexSet),
|
||||
p_to_s_group(VertexSet, EdgeSet, S_Graph).
|
||||
|
||||
|
||||
p_to_s_vertices([], []).
|
||||
p_to_s_vertices([A-Z|Edges], [A,Z|Vertices]) :-
|
||||
p_to_s_vertices(Edges, Vertices).
|
||||
|
||||
|
||||
p_to_s_group([], _, []).
|
||||
p_to_s_group([Vertex|Vertices], EdgeSet, [Vertex-Neibs|G]) :-
|
||||
p_to_s_group(EdgeSet, Vertex, Neibs, RestEdges),
|
||||
p_to_s_group(Vertices, RestEdges, G).
|
||||
|
||||
|
||||
p_to_s_group([V1-X|Edges], V2, [X|Neibs], RestEdges) :- V1 == V2,
|
||||
!,
|
||||
p_to_s_group(Edges, V2, Neibs, RestEdges).
|
||||
p_to_s_group(Edges, _, [], Edges).
|
||||
|
||||
|
||||
|
||||
s_to_p_graph([], []) :- !.
|
||||
s_to_p_graph([Vertex-Neibs|G], P_Graph) :-
|
||||
s_to_p_graph(Neibs, Vertex, P_Graph, Rest_P_Graph),
|
||||
s_to_p_graph(G, Rest_P_Graph).
|
||||
|
||||
|
||||
s_to_p_graph([], _, P_Graph, P_Graph) :- !.
|
||||
s_to_p_graph([Neib|Neibs], Vertex, [Vertex-Neib|P], Rest_P) :-
|
||||
s_to_p_graph(Neibs, Vertex, P, Rest_P).
|
||||
|
||||
%! transitive_closure(+Graph, -Closure)
|
||||
%
|
||||
% Generate the graph Closure as the transitive closure of Graph.
|
||||
% Example:
|
||||
%
|
||||
% ```
|
||||
% ?- transitive_closure([1-[2,3],2-[4,5],4-[6]],L).
|
||||
% L = [1-[2,3,4,5,6], 2-[4,5,6], 4-[6]]
|
||||
% ```
|
||||
|
||||
transitive_closure(Graph, Closure) :-
|
||||
warshall(Graph, Graph, Closure).
|
||||
|
||||
warshall([], Closure, Closure) :- !.
|
||||
warshall([V-_|G], E, Closure) :-
|
||||
memberchk(V-Y, E), % Y := E(v)
|
||||
warshall(E, V, Y, NewE),
|
||||
warshall(G, NewE, Closure).
|
||||
|
||||
|
||||
warshall([X-Neibs|G], V, Y, [X-NewNeibs|NewG]) :-
|
||||
memberchk(V, Neibs),
|
||||
!,
|
||||
ord_union(Neibs, Y, NewNeibs),
|
||||
warshall(G, V, Y, NewG).
|
||||
warshall([X-Neibs|G], V, Y, [X-Neibs|NewG]) :-
|
||||
!,
|
||||
warshall(G, V, Y, NewG).
|
||||
warshall([], _, _, []).
|
||||
|
||||
%! transpose_ugraph(Graph, NewGraph) is det.
|
||||
%
|
||||
% Unify NewGraph with a new graph obtained from Graph by replacing
|
||||
% all edges of the form V1-V2 by edges of the form V2-V1. The cost
|
||||
% is O(|V|*log(|V|)). Notice that an undirected graph is its own
|
||||
% transpose. Example:
|
||||
%
|
||||
% ==
|
||||
% ?- transpose([1-[3,5],2-[4],3-[],4-[5],
|
||||
% 5-[],6-[],7-[],8-[]], NL).
|
||||
% NL = [1-[],2-[],3-[1],4-[2],5-[1,4],6-[],7-[],8-[]]
|
||||
% ==
|
||||
%
|
||||
% @compat This predicate used to be known as transpose/2.
|
||||
% Following SICStus 4, we reserve transpose/2 for matrix
|
||||
% transposition and renamed ugraph transposition to
|
||||
% transpose_ugraph/2.
|
||||
|
||||
transpose_ugraph(Graph, NewGraph) :-
|
||||
edges(Graph, Edges),
|
||||
vertices(Graph, Vertices),
|
||||
flip_edges(Edges, TransposedEdges),
|
||||
vertices_edges_to_ugraph(Vertices, TransposedEdges, NewGraph).
|
||||
|
||||
flip_edges([], []).
|
||||
flip_edges([Key-Val|Pairs], [Val-Key|Flipped]) :-
|
||||
flip_edges(Pairs, Flipped).
|
||||
|
||||
%! compose(+LeftGraph, +RightGraph, -NewGraph)
|
||||
%
|
||||
% Compose NewGraph by connecting the _drains_ of LeftGraph to the
|
||||
% _sources_ of RightGraph. Example:
|
||||
%
|
||||
% ?- compose([1-[2],2-[3]],[2-[4],3-[1,2,4]],L).
|
||||
% L = [1-[4], 2-[1,2,4], 3-[]]
|
||||
|
||||
compose(G1, G2, Composition) :-
|
||||
vertices(G1, V1),
|
||||
vertices(G2, V2),
|
||||
ord_union(V1, V2, V),
|
||||
compose(V, G1, G2, Composition).
|
||||
|
||||
compose([], _, _, []) :- !.
|
||||
compose([Vertex|Vertices], [Vertex-Neibs|G1], G2,
|
||||
[Vertex-Comp|Composition]) :-
|
||||
!,
|
||||
compose1(Neibs, G2, [], Comp),
|
||||
compose(Vertices, G1, G2, Composition).
|
||||
compose([Vertex|Vertices], G1, G2, [Vertex-[]|Composition]) :-
|
||||
compose(Vertices, G1, G2, Composition).
|
||||
|
||||
|
||||
compose1([V1|Vs1], [V2-N2|G2], SoFar, Comp) :-
|
||||
compare(Rel, V1, V2),
|
||||
!,
|
||||
compose1(Rel, V1, Vs1, V2, N2, G2, SoFar, Comp).
|
||||
compose1(_, _, Comp, Comp).
|
||||
|
||||
|
||||
compose1(<, _, Vs1, V2, N2, G2, SoFar, Comp) :-
|
||||
!,
|
||||
compose1(Vs1, [V2-N2|G2], SoFar, Comp).
|
||||
compose1(>, V1, Vs1, _, _, G2, SoFar, Comp) :-
|
||||
!,
|
||||
compose1([V1|Vs1], G2, SoFar, Comp).
|
||||
compose1(=, V1, Vs1, V1, N2, G2, SoFar, Comp) :-
|
||||
ord_union(N2, SoFar, Next),
|
||||
compose1(Vs1, G2, Next, Comp).
|
||||
|
||||
%! top_sort(+Graph, -Sorted) is semidet.
|
||||
%! top_sort(+Graph, -Sorted, ?Tail) is semidet.
|
||||
%
|
||||
% Sorted is a topological sorted list of nodes in Graph. A
|
||||
% toplogical sort is possible if the graph is connected and
|
||||
% acyclic. In the example we show how topological sorting works
|
||||
% for a linear graph:
|
||||
%
|
||||
% ==
|
||||
% ?- top_sort([1-[2], 2-[3], 3-[]], L).
|
||||
% L = [1, 2, 3]
|
||||
% ==
|
||||
%
|
||||
% The predicate top_sort/3 is a difference list version of
|
||||
% top_sort/2.
|
||||
|
||||
top_sort(Graph, Sorted) :-
|
||||
vertices_and_zeros(Graph, Vertices, Counts0),
|
||||
count_edges(Graph, Vertices, Counts0, Counts1),
|
||||
select_zeros(Counts1, Vertices, Zeros),
|
||||
top_sort(Zeros, Sorted, Graph, Vertices, Counts1).
|
||||
|
||||
top_sort(Graph, Sorted0, Sorted) :-
|
||||
vertices_and_zeros(Graph, Vertices, Counts0),
|
||||
count_edges(Graph, Vertices, Counts0, Counts1),
|
||||
select_zeros(Counts1, Vertices, Zeros),
|
||||
top_sort(Zeros, Sorted, Sorted0, Graph, Vertices, Counts1).
|
||||
|
||||
|
||||
vertices_and_zeros([], [], []) :- !.
|
||||
vertices_and_zeros([Vertex-_|Graph], [Vertex|Vertices], [0|Zeros]) :-
|
||||
vertices_and_zeros(Graph, Vertices, Zeros).
|
||||
|
||||
|
||||
count_edges([], _, Counts, Counts) :- !.
|
||||
count_edges([_-Neibs|Graph], Vertices, Counts0, Counts2) :-
|
||||
incr_list(Neibs, Vertices, Counts0, Counts1),
|
||||
count_edges(Graph, Vertices, Counts1, Counts2).
|
||||
|
||||
|
||||
incr_list([], _, Counts, Counts) :- !.
|
||||
incr_list([V1|Neibs], [V2|Vertices], [M|Counts0], [N|Counts1]) :-
|
||||
V1 == V2,
|
||||
!,
|
||||
N is M+1,
|
||||
incr_list(Neibs, Vertices, Counts0, Counts1).
|
||||
incr_list(Neibs, [_|Vertices], [N|Counts0], [N|Counts1]) :-
|
||||
incr_list(Neibs, Vertices, Counts0, Counts1).
|
||||
|
||||
|
||||
select_zeros([], [], []) :- !.
|
||||
select_zeros([0|Counts], [Vertex|Vertices], [Vertex|Zeros]) :-
|
||||
!,
|
||||
select_zeros(Counts, Vertices, Zeros).
|
||||
select_zeros([_|Counts], [_|Vertices], Zeros) :-
|
||||
select_zeros(Counts, Vertices, Zeros).
|
||||
|
||||
|
||||
|
||||
top_sort([], [], Graph, _, Counts) :-
|
||||
!,
|
||||
vertices_and_zeros(Graph, _, Counts).
|
||||
top_sort([Zero|Zeros], [Zero|Sorted], Graph, Vertices, Counts1) :-
|
||||
graph_memberchk(Zero-Neibs, Graph),
|
||||
decr_list(Neibs, Vertices, Counts1, Counts2, Zeros, NewZeros),
|
||||
top_sort(NewZeros, Sorted, Graph, Vertices, Counts2).
|
||||
|
||||
top_sort([], Sorted0, Sorted0, Graph, _, Counts) :-
|
||||
!,
|
||||
vertices_and_zeros(Graph, _, Counts).
|
||||
top_sort([Zero|Zeros], [Zero|Sorted], Sorted0, Graph, Vertices, Counts1) :-
|
||||
graph_memberchk(Zero-Neibs, Graph),
|
||||
decr_list(Neibs, Vertices, Counts1, Counts2, Zeros, NewZeros),
|
||||
top_sort(NewZeros, Sorted, Sorted0, Graph, Vertices, Counts2).
|
||||
|
||||
graph_memberchk(Element1-Edges, [Element2-Edges2|_]) :-
|
||||
Element1 == Element2,
|
||||
!,
|
||||
Edges = Edges2.
|
||||
graph_memberchk(Element, [_|Rest]) :-
|
||||
graph_memberchk(Element, Rest).
|
||||
|
||||
|
||||
decr_list([], _, Counts, Counts, Zeros, Zeros) :- !.
|
||||
decr_list([V1|Neibs], [V2|Vertices], [1|Counts1], [0|Counts2], Zi, Zo) :-
|
||||
V1 == V2,
|
||||
!,
|
||||
decr_list(Neibs, Vertices, Counts1, Counts2, [V2|Zi], Zo).
|
||||
decr_list([V1|Neibs], [V2|Vertices], [N|Counts1], [M|Counts2], Zi, Zo) :-
|
||||
V1 == V2,
|
||||
!,
|
||||
M is N-1,
|
||||
decr_list(Neibs, Vertices, Counts1, Counts2, Zi, Zo).
|
||||
decr_list(Neibs, [_|Vertices], [N|Counts1], [N|Counts2], Zi, Zo) :-
|
||||
decr_list(Neibs, Vertices, Counts1, Counts2, Zi, Zo).
|
||||
|
||||
|
||||
%! neighbors(+Vertex, +Graph, -Neigbours) is det.
|
||||
%! neighbours(+Vertex, +Graph, -Neigbours) is det.
|
||||
%
|
||||
% Neigbours is a sorted list of the neighbours of Vertex in Graph.
|
||||
% Example:
|
||||
%
|
||||
% ```
|
||||
% ?- neighbours(4,[1-[3,5],2-[4],3-[],
|
||||
% 4-[1,2,7,5],5-[],6-[],7-[],8-[]], NL).
|
||||
% NL = [1,2,7,5]
|
||||
% ```
|
||||
|
||||
neighbors(Vertex, Graph, Neig) :-
|
||||
neighbours(Vertex, Graph, Neig).
|
||||
|
||||
neighbours(V,[V0-Neig|_],Neig) :-
|
||||
V == V0,
|
||||
!.
|
||||
neighbours(V,[_|G],Neig) :-
|
||||
neighbours(V,G,Neig).
|
||||
|
||||
|
||||
%! connect_ugraph(+UGraphIn, -Start, -UGraphOut) is det.
|
||||
%
|
||||
% Adds Start as an additional vertex that is connected to all vertices
|
||||
% in UGraphIn. This can be used to create an topological sort for a
|
||||
% not connected graph. Start is before any vertex in UGraphIn in the
|
||||
% standard order of terms. No vertex in UGraphIn can be a variable.
|
||||
%
|
||||
% Can be used to order a not-connected graph as follows:
|
||||
%
|
||||
% ```
|
||||
% top_sort_unconnected(Graph, Vertices) :-
|
||||
% ( top_sort(Graph, Vertices)
|
||||
% -> true
|
||||
% ; connect_ugraph(Graph, Start, Connected),
|
||||
% top_sort(Connected, Ordered0),
|
||||
% Ordered0 = [Start|Vertices]
|
||||
% ).
|
||||
% ```
|
||||
|
||||
connect_ugraph([], 0, []) :- !.
|
||||
connect_ugraph(Graph, Start, [Start-Vertices|Graph]) :-
|
||||
vertices(Graph, Vertices),
|
||||
Vertices = [First|_],
|
||||
before(First, Start).
|
||||
|
||||
%! before(+Term, -Before) is det.
|
||||
%
|
||||
% Unify Before to a term that comes before Term in the standard
|
||||
% order of terms.
|
||||
%
|
||||
% @error instantiation_error if Term is unbound.
|
||||
|
||||
before(X, _) :-
|
||||
var(X),
|
||||
!,
|
||||
instantiation_error(X).
|
||||
before(Number, Start) :-
|
||||
number(Number),
|
||||
!,
|
||||
Start is Number - 1.
|
||||
before(_, 0).
|
||||
|
||||
|
||||
%! complement(+UGraphIn, -UGraphOut)
|
||||
%
|
||||
% UGraphOut is a ugraph with an edge between all vertices that are
|
||||
% _not_ connected in UGraphIn and all edges from UGraphIn removed.
|
||||
% Example:
|
||||
%
|
||||
% ```
|
||||
% ?- complement([1-[3,5],2-[4],3-[],
|
||||
% 4-[1,2,7,5],5-[],6-[],7-[],8-[]], NL).
|
||||
% NL = [1-[2,4,6,7,8],2-[1,3,5,6,7,8],3-[1,2,4,5,6,7,8],
|
||||
% 4-[3,5,6,8],5-[1,2,3,4,6,7,8],6-[1,2,3,4,5,7,8],
|
||||
% 7-[1,2,3,4,5,6,8],8-[1,2,3,4,5,6,7]]
|
||||
% ```
|
||||
%
|
||||
% @tbd Simple two-step algorithm. You could be smarter, I suppose.
|
||||
|
||||
complement(G, NG) :-
|
||||
vertices(G,Vs),
|
||||
complement(G,Vs,NG).
|
||||
|
||||
complement([], _, []).
|
||||
complement([V-Ns|G], Vs, [V-INs|NG]) :-
|
||||
ord_add_element(Ns,V,Ns1),
|
||||
ord_subtract(Vs,Ns1,INs),
|
||||
complement(G, Vs, NG).
|
||||
|
||||
%! reachable(+Vertex, +UGraph, -Vertices)
|
||||
%
|
||||
% True when Vertices is an ordered set of vertices reachable in
|
||||
% UGraph, including Vertex. Example:
|
||||
%
|
||||
% ?- reachable(1,[1-[3,5],2-[4],3-[],4-[5],5-[]],V).
|
||||
% V = [1, 3, 5]
|
||||
|
||||
reachable(N, G, Rs) :-
|
||||
reachable([N], G, [N], Rs).
|
||||
|
||||
reachable([], _, Rs, Rs).
|
||||
reachable([N|Ns], G, Rs0, RsF) :-
|
||||
neighbours(N, G, Nei),
|
||||
ord_union(Rs0, Nei, Rs1, D),
|
||||
append(Ns, D, Nsi),
|
||||
reachable(Nsi, G, Rs1, RsF).
|
||||
@@ -4,9 +4,9 @@
|
||||
This library provides reasoning about UUID (only version 4 right now).
|
||||
There are three predicates:
|
||||
* uuidv4/1, to generate a new UUIDv4
|
||||
* uuidv4_string/1, to generate a new UUIDv4 in string hex representation
|
||||
* uuidv4_string/1, to generate a new UUIDv4 in string hex representation
|
||||
* uuid_string/2, to converte between UUID list of bytes and UUID hex representation
|
||||
|
||||
|
||||
Examples:
|
||||
?- uuidv4(X).
|
||||
X = [42,147,248,242,117,196,79,2,129,159|...].
|
||||
@@ -30,7 +30,7 @@
|
||||
:- use_module(library(dcgs)).
|
||||
:- use_module(library(lists)).
|
||||
|
||||
/*
|
||||
/*
|
||||
An UUID is made of 16 bytes, composed of 5 sections:
|
||||
time_low - 4
|
||||
time_mid - 2
|
||||
|
||||
Reference in New Issue
Block a user