%
% True if Key-Value is an association in Assoc.
%
-% Throws error: type_error(assoc, Assoc) if Assoc is not an association list.
+% Throws error: type\_error(assoc, Assoc) if Assoc is not an association list.
get_assoc(Key, Assoc, Val) :-
must_be(assoc, Assoc),
% Create an association from a list Pairs of Key-Value pairs. List
% must not contain duplicate keys.
%
-% Throws error: domain_error(unique_key_pairs, List) if List contains duplicate keys
+% Throws error: domain\_error(unique\_key\_pairs, List) if List contains duplicate keys
list_to_assoc(List, Assoc) :-
( List = [] -> Assoc = t
% pairs. The pairs must occur in strictly ascending order of
% their keys.
%
-% Throws error: domain_error(key_ordered_pairs, List) if pairs are not ordered.
+% Throws error: domain\_error(key\_ordered\_pairs, List) if pairs are not ordered.
ord_list_to_assoc(Sorted, Assoc) :-
( Sorted = [] -> Assoc = t
Access =.. [Module,_].
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+/**
Each CLP(B) variable belongs to exactly one BDD. Each CLP(B)
variable gets an attribute (in module "clpb") of the form:
- index_root(Index,Root)
+ ```
+ index_root(Index,Root)
+ ```
where Index is the variable's unique integer index, and Root is the
root of the BDD that the variable belongs to.
- Each CLP(B) variable also gets an attribute in module clpb_hash: an
+ Each CLP(B) variable also gets an attribute in module `clpb_hash`: an
association table node(LID,HID) -> Node, to keep the BDD reduced.
The association table of each variable must be rebuilt on occasion
to remove nodes that are no longer reachable. We rebuild the
association tables of involved variables after BDDs are merged to
build a new root. This only serves to reclaim memory: Keeping a
node in a local table even when it no longer occurs in any BDD does
- not affect the solver's correctness. However, apply_shortcut/4
+ not affect the solver's correctness. However, `apply_shortcut/4`
relies on the invariant that every node that occurs in the relevant
BDDs is also registered in the table of its branching variable.
- A root is a logical variable with a single attribute ("clpb_bdd")
+ A root is a logical variable with a single attribute ("clpb\_bdd")
of the form:
- Sat-BDD
+ ```
+ Sat-BDD
+ ```
where Sat is the SAT formula (in original form) that corresponds to
BDD. Sat is necessary to rebuild the BDD after variable aliasing,
- and to project all remaining constraints to a list of sat/1 goals.
+ and to project all remaining constraints to a list of `sat/1` goals.
Finally, a BDD is either:
- *) The integers 0 or 1, denoting false and true, respectively, or
- *) A node of the form
+ * The integers 0 or 1, denoting false and true, respectively, or
+ * A node of the form
+
+ ```
+ node(ID, Var, Low, High, Aux)
+ ```
- node(ID, Var, Low, High, Aux)
- Where ID is the node's unique integer ID, Var is the
- node's branching variable, and Low and High are the
- node's low (Var = 0) and high (Var = 1) children. Aux
- is a free variable, one for each node, that can be used
- to attach attributes and store intermediate results.
+ Where ID is the node's unique integer ID, Var is the
+ node's branching variable, and Low and High are the
+ node's low (Var = 0) and high (Var = 1) children. Aux
+ is a free variable, one for each node, that can be used
+ to attach attributes and store intermediate results.
Variable aliasing is treated as a conjunction of corresponding SAT
formulae.
You should think of CLP(B) as a potentially vast collection of BDDs
that can range from small to gigantic in size, and which can merge.
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+*/
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Type checking.
%
% Examples:
%
-% ==
+% ```
% ?- sat(A =< B), Vs = [A,B], sat_count(+[1|Vs], Count).
% Vs = [A, B],
% Count = 3,
% Vs = [...],
% CountOr = 1329227995784915872903807060280344575,
% CountAnd = 1.
-% ==
+% ```
% linear objective function over Boolean variables Vs with integer
% coefficients Weights. This predicate assigns 0 and 1 to the
% variables in Vs such that all stated constraints are satisfied, and
-% Maximum is the maximum of sum(Weight_i*V_i) over all admissible
+% Maximum is the maximum of `sum(Weight_i*V_i)` over all admissible
% assignments. On backtracking, all admissible assignments that
% attain the optimum are generated.
%
%
% Example:
%
-% ==
+% ```
% ?- sat(A#B), weighted_maximum([1,2,1], [A,B,C], Maximum).
% A = 0, B = 1, C = 1, Maximum = 3.
-% ==
+% ```
weighted_maximum(Ws, Vars, Max) :-
must_be(list(integer), Ws),
/** Predicates for reasoning about files and directories.
In this library, directories and files are represented as
-*lists of characters*. This is an ideal representation:
+_lists of characters_. This is an ideal representation:
* Lists of characters can be conveniently reasoned about with DCGs
- and built-in Prolog predicates from library(lists). This alone
+ and built-in Prolog predicates from `library(lists)`. This alone
is already a very compelling argument to use them.
-* Other Scryer libraries such as library(http/http_open) also already
+* Other Scryer libraries such as `library(http/http_open)` also already
use lists of characters to represent paths.
* File names are mostly ephemeral, so it is good for efficiency
that they can quickly allocated transiently on the heap, leaving the
%% make_directory(+Directory).
%
% Succeeds if it creates a new directory named Directory in the current system.
-% If you want to create a nested directory, use make\_directory\_path/1.
+% If you want to create a nested directory, use `make_directory_path/1`.
make_directory(Directory) :-
must_be(chars, Directory),
'$make_directory'(Directory).
%% make_directory_path(+Directory).
%
-% Similar to make\_directory/1 but recursively creates directories if they're missing.
+% Similar to `make_directory/1` but recursively creates directories if they're missing.
% Equivalent to mkdir -p in Unix.
make_directory_path(Directory) :-
must_be(chars, Directory),
%
% Dir0 is the current working directory, and the working directory
% is changed to Dir.
-
-% Use `working\_directory(Ds, Ds)` to determine the current working directory,
+%
+% Use `working_directory/2` to determine the current working directory,
% and leave it as is.
working_directory(Dir0, Dir) :-
%
% For a file File that must exist, it returns a time stamp T with the modification time
%
-% T is a time stamp compatible with library(time).
+% T is a time stamp compatible with `library(time)`.
file_modification_time(File, T) :-
file_time_(File, modification, T).
%
% For a file File that must exist, it returns a time stamp T with the access time
%
-% T is a time stamp compatible with library(time).
+% T is a time stamp compatible with `library(time)`.
file_access_time(File, T) :-
file_time_(File, access, T).
%
% For a file File that must exist, it returns a time stamp T with the creation time
%
-% T is a time stamp compatible with library(time).
+% T is a time stamp compatible with `library(time)`.
file_creation_time(File, T) :-
file_time_(File, creation, T).
%
% Examples:
%
-% ?- path_segments("/hello/there", Segments).
-% Segments = [[],"hello","there"].
-% ?- path_segments(Path, ["hello","there"]).
-% Path = "hello/there".
-%
+% ```
+% ?- path_segments("/hello/there", Segments).
+% Segments = [[],"hello","there"].
+% ?- path_segments(Path, ["hello","there"]).
+% Path = "hello/there".
+% ```
+%
% To obtain the platform-specific directory separator, you can use:
%
-% ?- path_segments(Separator, ["",""]).
-% Separator = "/".
+% ```
+% ?- path_segments(Separator, ["",""]).
+% Separator = "/".
+% ```
path_segments(Path, Segments) :-
'$directory_separator'(Sep),
/** Make HTTP requests.
-This library contains the predicate http\_open/3 which allows you to perform HTTP(S) calls.
+This library contains the predicate `http_open/3` which allows you to perform HTTP(S) calls.
Useful for making API calls, or parsing websites. It uses Hyper underneath.
*/
%
% Example:
%
-% ?- http_open("https://www.example.com", S, []), get_n_chars(S, N, HTML).
-% S = '$stream'(0x7fb548001be8), N = 1256, HTML = "<!doctype html>\n<ht ...".
+% ```
+% ?- http_open("https://www.example.com", S, []), get_n_chars(S, N, HTML).
+% S = '$stream'(0x7fb548001be8), N = 1256, HTML = "<!doctype html>\n<ht ...".
+% ```
http_open(Address, Response, Options) :-
parse_http_options(Options, OptionValues),
( member(method(Method), OptionValues) -> true; Method = get),
% For all bindings possible by Generate, Test must be true.
%
% In this example, it checks that all numbers are even:
-%
-% ?- Ns = [2,4,6], forall(member(N, Ns), 0 is N mod 2).
-% Ns = [2,4,6].
+%
+% ```
+% ?- Ns = [2,4,6], forall(member(N, Ns), 0 is N mod 2).
+% Ns = [2,4,6].
+% ```
forall(Generate, Test) :-
\+ (Generate, \+ Test).
%% bb_put(+Key, +Value).
%
% Sets a global variable named Key (must be an atom) with value Value.
-% The global variable isn't backtrackable. Check bb\_b\_put/2 for the
+% The global variable isn't backtrackable. Check `bb_b_put/2` for the
% backtrackable version.
%
-% ?- bb_put(city, "Valladolid").
-% true.
-% ?- bb_get(city, X).
-% X = "Valladolid".
-% In this example one can understand the difference between bb\_put/2 and
-% bb\_b\_put/2:
+% ```
+% ?- bb_put(city, "Valladolid").
+% true.
+% ?- bb_get(city, X).
+% X = "Valladolid".
+% ```
+%
+% In this example one can understand the difference between `bb_put/2` and
+% `bb_b_put/2`:
%
-% ?- bb_put(city, "Valladolid"), (bb_put(city, "Salamanca"), false);(bb_get(city, X)).
-% X = "Salamanca".
-% ?- bb_put(city, "Valladolid"), (bb_b_put(city, "Salamanca"), false);(bb_get(city, X)).
-% X = "Valladolid".
+% ```
+% ?- bb_put(city, "Valladolid"), (bb_put(city, "Salamanca"), false);(bb_get(city, X)).
+% X = "Salamanca".
+% ?- bb_put(city, "Valladolid"), (bb_b_put(city, "Salamanca"), false);(bb_get(city, X)).
+% X = "Valladolid".
+% ```
bb_put(Key, Value) :-
( atom(Key) ->
'$store_global_var'(Key, Value)
%% bb_b_put(+Key, +Value).
%
% Sets a global variable named Key (must be an atom) with value Value.
-% The global variable is backtrackable. Check bb\_put/2 for the
+% The global variable is backtrackable. Check `bb_put/2` for the
% non-backtrackable version.
%
-% ?- bb_b_put(city, "Valladolid").
-% true.
-% ?- bb_get(city, X).
-% X = "Valladolid".
-% In this example one can understand the difference between bb\_put/2 and
-% bb\_b\_put/2:
+% ```
+% ?- bb_b_put(city, "Valladolid").
+% true.
+% ?- bb_get(city, X).
+% X = "Valladolid".
+% ```
+%
+% In this example one can understand the difference between `bb_put/2` and
+% `bb_b_put/2`:
%
-% ?- bb_put(city, "Valladolid"), (bb_put(city, "Salamanca"), false);(bb_get(city, X)).
-% X = "Salamanca".
-% ?- bb_put(city, "Valladolid"), (bb_b_put(city, "Salamanca"), false);(bb_get(city, X)).
-% X = "Valladolid".
+% ```
+% ?- bb_put(city, "Valladolid"), (bb_put(city, "Salamanca"), false);(bb_get(city, X)).
+% X = "Salamanca".
+% ?- bb_put(city, "Valladolid"), (bb_b_put(city, "Salamanca"), false);(bb_get(city, X)).
+% X = "Valladolid".
+% ```
bb_b_put(Key, Value) :-
( atom(Key) ->
'$store_backtrackable_global_var'(Key, Value)
%
% In this example, we use the predicate to always close an open file:
%
-% ?- setup_call_cleanup(open(File, read, Stream), do_something_with_stream(Stream), close(Stream)).
+% ```
+% ?- setup_call_cleanup(open(File, read, Stream), do_something_with_stream(Stream), close(Stream)).
+% ```
setup_call_cleanup(S, G, C) :-
'$get_b_value'(B),
'$call_with_inference_counting'(call(S)),
%% copy_term_nat(Source, Dest)
%
-% Similar to copy\_term/2 but without attribute variables
+% Similar to `copy_term/2` but without attribute variables
copy_term_nat(Source, Dest) :-
'$copy_term_without_attr_vars'(Source, Dest).
%% asserta(Module, Rule_Fact).
%
-% Similar to asserta/1 but allows specifying a Module
+% Similar to `asserta/1` but allows specifying a Module
asserta(Module, (Head :- Body)) :-
!,
'$asserta'(Module, Head, Body).
%% assertz(Module, Rule_Fact).
%
-% Similar to assertz/1 but allows specifying a Module
+% Similar to `assertz/1` but allows specifying a Module
assertz(Module, (Head :- Body)) :-
!,
'$assertz'(Module, Head, Body).
% Relates a list to its length (number of items). It can be used to count the elements of a current list or
% to create a list full of free variables with N length.
%
-% ?- length([a,b,c], 3).
-% true.
-% ?- length([a,b,c], N).
-% N = 3.
-% ?- length(Xs, 3).
-% Xs = [_A, _B, _C].
+% ```
+% ?- length([a,b,c], 3).
+% true.
+% ?- length([a,b,c], N).
+% N = 3.
+% ?- length(Xs, 3).
+% Xs = [_A, _B, _C].
+% ```
length(Xs0, N) :-
'$skip_max_list'(M, N, Xs0,Xs),
%
% Succeeds when X unifies with an item of the list Xs, which can be at any position.
%
-% ?- member(X, "hello world").
-% X = h
-% ; ... .
-%
+% ```
+% ?- member(X, "hello world").
+% X = h
+% ; ... .
+% ```
member(X, [X|_]).
member(X, [_|Xs]) :- member(X, Xs).
%
% Succeeds when the list Xs1 is the list Xs0 without the item X
%
-% ?- select(c, "abcd", X).
-% X = "abd".
-%
+% ```
+% ?- select(c, "abcd", X).
+% X = "abd".
+% ```
select(X, [X|Xs], Xs).
select(X, [Y|Xs], [Y|Ys]) :- select(X, Xs, Ys).
%
% Concatenates a list of lists
%
-% ?- append([[1, 2], [3]], Xs).
-% Xs = [1, 2, 3].
-%
+% ```
+% ?- append([[1, 2], [3]], Xs).
+% Xs = [1, 2, 3].
+% ```
append([], []).
append([L0|Ls0], Ls) :-
append(L0, Rest, Ls),
%
% List Xs is the concatenation of Xs0 and Xs1
%
-% ?- append([1,2,3], [4,5,6], Xs).
-% Xs = [1, 2, 3, 4, 5, 6].
-%
+% ```
+% ?- append([1,2,3], [4,5,6], Xs).
+% Xs = [1, 2, 3, 4, 5, 6].
+% ```
append([], R, R).
append([X|L], R, [X|S]) :- append(L, R, S).
%% memberchk(?X, +Xs).
%
-% This predicate is similar to member/2, but it only provides a single answer
+% This predicate is similar to `member/2`, but it only provides a single answer
memberchk(X, Xs) :- member(X, Xs), !.
%% reverse(?Xs, ?Ys).
%
% This is a metapredicate that applies predicate to each element of the list Xs0
%
-% ?- maplist(write, [1,2,3]).
-% 123 true.
-%
+% ```
+% ?- maplist(write, [1,2,3]).
+% 123 true.
+% ```
maplist(_, []).
maplist(Cont1, [E1|E1s]) :-
call(Cont1, E1),
%
% This is a metapredicate that applies predicate to each element of the lists Xs0 and Xs1.
%
-% ?- maplist(length, ["hello", "prolog", "marseille"], Xs1).
-% Xs1 = [5,6,9].
-%
+% ```
+% ?- maplist(length, ["hello", "prolog", "marseille"], Xs1).
+% Xs1 = [5,6,9].
+% ```
maplist(_, [], []).
maplist(Cont2, [E1|E1s], [E2|E2s]) :-
call(Cont2, E1, E2),
%
% Takes a lists of numbers and unifies Sum with the result of summing all the elements of the list.
%
-% ?- sum_list([2,2,2], 6).
-% true.
+% ```
+% ?- sum_list([2,2,2], 6).
+% true.
+% ```
sum_list(Ls, S) :-
foldl(lists:sum_, Ls, 0, S).
%
% For example, if we define sum_ as:
%
-% sum_(L, S0, S) :- S is S0 + L.
+% ```
+% sum_(L, S0, S) :- S is S0 + L.
+% ```
%
-% Then we can define sum\_list/2 as the following:
-%
-% sum_list(Ls, S) :- foldl(sum_, Ls, 0, S).
+% Then we can define `sum_list/2` as the following:
%
+% ```
+% sum_list(Ls, S) :- foldl(sum_, Ls, 0, S).
+% ```
foldl(Goal_3, Ls, A0, A) :-
foldl_(Ls, Goal_3, A0, A).
%% foldl(+Predicate, ?Ls0, ?Ls1, +A0, ?A).
%
-% Same as foldl/4 but with an extra list
+% Same as `foldl/4` but with an extra list
foldl(Goal_4, Xs, Ys, A0, A) :-
foldl_(Xs, Ys, Goal_4, A0, A).
%
% If Ls is a list of lists, Ts contains the transposition
%
-% ?- transpose([[1,1],[2,2]], Ts).
-% Ts = [[1,2],[1,2]].
-%
+% ```
+% ?- transpose([[1,1],[2,2]], Ts).
+% Ts = [[1,2],[1,2]].
+% ```
transpose(Ls, Ts) :-
lists_transpose(Ls, Ts).
%
% Takes a list Ls0 and returns a list Set that doesn't contain any repeated element
%
-% ?- list_to_set([2,3,4,4,1,2], Set).
-% Set = [2,3,4,1].
-%
+% ```
+% ?- list_to_set([2,3,4,4,1,2], Set).
+% Set = [2,3,4,1].
+% ```
list_to_set(Ls0, Ls) :-
maplist(lists:with_var, Ls0, LVs0),
keysort(LVs0, LVs),
%
% Succeeds if in the N position of the list Ls, we found the element E. The elements start counting from zero.
%
-% ?- nth0(2, [1,2,3,4], 3).
-% true.
+% ```
+% ?- nth0(2, [1,2,3,4], 3).
+% true.
+% ```
nth0(N, Es0, E) :-
nonvar(N),
'$skip_max_list'(Skip, N, Es0,Es1),
%
% Succeeds if in the N position of the list Ls, we found the element E. The elements start counting from one.
%
-% ?- nth1(2, [1,2,3,4], 2).
-% true.
+% ```
+% ?- nth1(2, [1,2,3,4], 2).
+% true.
+% ```
nth1(N, Es0, E) :-
N \== 0,
nth0(N, [_|Es0], E),
%
% Succeeds if in the N position of the list Ls, we found the element E and the rest of the list is Rs. The elements start counting from zero.
%
-% ?- nth0(2, [1,2,3,4], 3, [1,2,4]).
-% true.
+% ```
+% ?- nth0(2, [1,2,3,4], 3, [1,2,4]).
+% true.
+% ```
nth0(N, Es0, E, Es) :-
integer(N),
N >= 0,
%
% Succeeds if in the N position of the list Ls, we found the element E and the rest of the list is Rs. The elements start counting from one.
%
-% ?- nth1(2, [1,2,3,4], 2, [1,3,4]).
-% true.
+% ```
+% ?- nth1(2, [1,2,3,4], 2, [1,3,4]).
+% true.
+% ```
nth1(N, Es0, E, Es) :-
N \== 0,
nth0(N, [_|Es0], E, [_|Es]),
%
% True when Xs is a permutation of Ys. This can solve for Ys given
% Xs or Xs given Ys, or even enumerate Xs and Ys together. The
-% predicate permutation/2 is primarily intended to generate
+% predicate `permutation/2` is primarily intended to generate
% permutations. Note that a list of length N has N! permutations,
% and unbounded permutation generation becomes prohibitively
% expensive, even for rather short lists (10! = 3,628,800).
% The example below illustrates that Xs and Ys being proper lists
% is not a sufficient condition to use the above replacement.
%
-% ?- permutation([1,2], [X,Y]).
-% X = 1, Y = 2
-% ; X = 2, Y = 1
-% ; false.
+% ```
+% ?- permutation([1,2], [X,Y]).
+% X = 1, Y = 2
+% ; X = 2, Y = 1
+% ; false.
+% ```
%
-% Throws type\_error(list, Arg) if either argument is not a proper
+% Throws `type_error(list, Arg)` if either argument is not a proper
% or partial list.
permutation(Xs, Ys) :-
/** Ordered set manipulation
Ordered sets are lists with unique elements sorted to the standard order
-of terms (see sort/2). Exploiting ordering, many of the set operations
+of terms (see `sort/2`). Exploiting ordering, many of the set operations
can be expressed in order N rather than N^2 when dealing with unordered
sets that may contain duplicates. The library(ordsets) is available in a
number of Prolog implementations. Our predicates are designed to be
compatible with common practice in the Prolog community.
Some of these predicates match directly to corresponding list
operations. It is advised to use the versions from this library to make
-clear you are operating on ordered sets. An exception is member/2. See
-ord\_memberchk/2.
+clear you are operating on ordered sets. An exception is `member/2`. See
+`ord_memberchk/2`.
The ordsets library is based on the standard order of terms. This
implies it can handle all Prolog terms, including variables. Note
however, that the ordering is not stable if a term inside the set is
further instantiated. Also note that variable ordering changes if
variables in the set are unified with each other or a variable in the
-set is unified with a variable that is `older' than the newest variable
+set is unified with a variable that is _older_ than the newest variable
in the set. In practice, this implies that it is allowed to use
member(X, OrdSet) on an ordered set that holds variables only if X is a
fresh variable. In other cases one should cease using it as an ordset
% True if Term is an ordered set. All predicates in this library
% expect ordered sets as input arguments. Failing to fullfil this
% assumption results in undefined behaviour. Typically, ordered
-% sets are created by predicates from this library, sort/2 or
-% setof/3.
+% sets are created by predicates from this library, `sort/2` or
+% `setof/3`.
is_ordset(Term) :-
'$skip_max_list'(_, _, Term, Tail), Tail == [], %% is_list(Term),
%% ord_seteq(+Set1, +Set2) is semidet.
%
% True if Set1 and Set2 have the same elements. As both are
-% canonical sorted lists, this is the same as ==/2.
+% canonical sorted lists, this is the same as `==/2`.
ord_seteq(Set1, Set2) :-
Set1 == Set2.
%% ord_disjoint(+Set1, +Set2) is semidet.
%
% True if Set1 and Set2 have no common elements. This is the
-% negation of ord\_intersect/2.
+% negation of `ord_intersect/2`.
ord_disjoint(Set1, Set2) :-
\+ ord_intersect(Set1, Set2).
%
% Intersection holds the common elements of Set1 and Set2.
%
-% This predicate is **deprecated**. Use ord\_intersection/3
+% This predicate is *deprecated*. Use `ord_intersection/3`
ord_intersect(Set1, Set2, Intersection) :-
oset_int(Set1, Set2, Intersection).
%% ord_intersection(+Set1, +Set2, -Intersection) is det.
%
% Intersection holds the common elements of Set1 and Set2. Uses
-% ord\_disjoint/2 if Intersection is bound to `[]` on entry.
+% `ord_disjoint/2` if Intersection is bound to `[]` on entry.
ord_intersection(Set1, Set2, Intersection) :-
( Intersection == []
%
% Intersection and difference between two ordered sets.
% Intersection is the intersection between Set1 and Set2, while
-% Difference is defined by ord\_subtract(Set2, Set1, Difference).
+% Difference is defined by `ord_subtract(Set2, Set1, Difference)`.
ord_intersection([], L, [], L) :- !.
ord_intersection([_|_], [], [], []) :- !.
%% ord_add_element(+Set1, +Element, ?Set2) is det.
%
% Insert an element into the set. This is the same as
-% ord\_union(Set1, [Element], Set2).
+% `ord_union(Set1, [Element], Set2)`.
ord_add_element(Set1, Element, Set2) :-
oset_addel(Set1, Element, Set2).
%% ord_del_element(+Set, +Element, -NewSet) is det.
%
% Delete an element from an ordered set. This is the same as
-% ord\_subtract(Set, [Element], NewSet).
+% `ord_subtract(Set, [Element], NewSet)`.
ord_del_element(Set, Element, NewSet) :-
oset_delel(Set, Element, NewSet).
%% ord_selectchk(+Item, ?Set1, ?Set2) is semidet.
%
-% Selectchk/3, specialised for ordered sets. Is true when
+% `selectchk/3`, specialised for ordered sets. Is true when
% select(Item, Set1, Set2) and Set1, Set2 are both sorted lists
% without duplicates. This implementation is only expected to work
% for Item ground and either Set1 or Set2 ground. The "chk" suffix
-% is meant to remind you of memberchk/2, which also expects its
-% first argument to be ground. ord\_selectchk(X, S, T) =>
-% ord\_memberchk(X, S) & \\+ ord\_memberchk(X, T).
+% is meant to remind you of `memberchk/2`, which also expects its
+% first argument to be ground. `ord_selectchk(X, S, T) =>
+% ord_memberchk(X, S) & \+ ord_memberchk(X, T).`
%
% Author: Richard O'Keefe
%
% True if Element is a member of OrdSet, compared using ==. Note
% that _enumerating_ elements of an ordered set can be done using
-% member/2.
+% `member/2`.
%
-% Some Prolog implementations also provide ord\_member/2, with the
-% same semantics as ord\_memberchk/2. We believe that having a
-% semidet ord\_member/2 is unacceptably inconsistent with the \*\_chk
-% convention. Portable code should use ord\_memberchk/2 or
-% member/2.
+% Some Prolog implementations also provide `ord_member/2`, with the
+% same semantics as `ord_memberchk/2`. We believe that having a
+% semidet `ord_member/2` is unacceptably inconsistent with the \*\_chk
+% convention. Portable code should use `ord_memberchk/2` or
+% `member/2`.
%
% Author: Richard O'Keefe
%% ord_union(+Set1, +Set2, -Union, -New) is det.
%
-% True iff ord\_union(Set1, Set2, Union) and
-% ord\_subtract(Set2, Set1, New).
+% True iff `ord_union(Set1, Set2, Union)` and
+% `ord_subtract(Set2, Set1, New)`.
ord_union([], Set2, Set2, Set2).
ord_union([H|T], Set2, Union, New) :-
% sequence below (but the actual implementation requires only a
% single scan).
%
-% ord_union(Set1, Set2, Union),
-% ord_intersection(Set1, Set2, Intersection),
-% ord_subtract(Union, Intersection, Difference).
+% ```
+% ord_union(Set1, Set2, Union),
+% ord_intersection(Set1, Set2, Intersection),
+% ord_subtract(Union, Intersection, Difference).
+% ```
%
-% For example:
+% For example:
%
-% ?- ord_symdiff([1,2], [2,3], X).
-% X = [1,3].
+% ```
+% ?- ord_symdiff([1,2], [2,3], X).
+% X = [1,3].
+% ```
ord_symdiff([], Set2, Set2).
ord_symdiff([H1|T1], Set2, Difference) :-
%
% Generates a random integer number between Lower (inclusive) and Upper (exclusive).
%
-% Throws instantiation\_error if Lower or Upper are variables.
+% Throws `instantiation_error` if Lower or Upper are variables.
%
-% Throws type\_error if Lower or Upper aren't integers.
+% Throws `type_error` if Lower or Upper aren't integers.
random_integer(Lower, Upper, R) :-
var(R),
( (var(Lower) ; var(Upper)) ->
/**
Predicates for handling network sockets, both as a server and as a client.
-As a server, you should open a socket an call socket\_server\_accept/4 to get a stream for each connection.
+As a server, you should open a socket an call `socket_server_accept/4` to get a stream for each connection.
As a client, you should just open a socket and you will receive a stream.
In both cases, with a stream, you can use the usual predicates to read and write to the stream.
*/
%
% The following options are available:
%
-% * alias(+Alias): Set an alias to the stream
-% * eof_action(+Action): Defined what happens if the end of the stream is reached. Values: `error`, `eof_code` and `reset`.
-% * reposition(+Boolean): Specifies whether repositioning is required for the stream. `false` is the default.
-% * type(+Type): Type can be `text` or `binary`. Defines the type of the stream, if it's optimized for plain text
+% * `alias(+Alias)`: Set an alias to the stream
+% * `eof_action(+Action)`: Defined what happens if the end of the stream is reached. Values: `error`, `eof_code` and `reset`.
+% * `reposition(+Boolean)`: Specifies whether repositioning is required for the stream. `false` is the default.
+% * `type(+Type)`: Type can be `text` or `binary`. Defines the type of the stream, if it's optimized for plain text
% or just binary
%
socket_client_open(Addr, Stream, Options) :-
%% socket_server_open(+Addr, -ServerSocket).
%
% Open a server socket, returning a ServerSocket. Use that ServerSocket to accept incoming connections in
-% socket\_server\_accept/4. Addr must satisfy `Addr = Address:Port`. Depending on the operating system
+% `socket_server_accept/4`. Addr must satisfy `Addr = Address:Port`. Depending on the operating system
% configuration, some ports might be reserved for superusers.
socket_server_open(Addr, ServerSocket) :-
must_be(var, ServerSocket),
%
% The following options are available:
%
-% * alias(+Alias): Set an alias to the stream
-% * eof_action(+Action): Defined what happens if the end of the stream is reached. Values: `error`, `eof_code` and `reset`.
-% * reposition(+Boolean): Specifies whether repositioning is required for the stream. `false` is the default.
-% * type(+Type): Type can be `text` or `binary`. Defines the type of the stream, if it's optimized for plain text
+% * `alias(+Alias)`: Set an alias to the stream
+% * `eof_action(+Action)`: Defined what happens if the end of the stream is reached. Values: `error`, `eof_code` and `reset`.
+% * `reposition(+Boolean)`: Specifies whether repositioning is required for the stream. `false` is the default.
+% * `type(+Type)`: Type can be `text` or `binary`. Defines the type of the stream, if it's optimized for plain text
% or just binary
%
socket_server_accept(ServerSocket, Client, Stream, Options) :-
sort). This form is convenient for many calculations.
A new UGraph from raw data can be created using
-vertices\_edges\_to\_ugraph/3.
+`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.
-Ported from SWI-Prolog to Scryer by Adrián Arroyo Calle
+Ported from SWI-Prolog to Scryer by [Adrián Arroyo Calle](https://adrianistan.eu)
License: BSD-2 or Artistic 2.0
*/
%
% 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([1-[3,5],2-[4],3-[],4-[5],5-[]], L).
+% L = [1, 2, 3, 4, 5]
+% ```
vertices([], []) :- !.
vertices([Vertex-_|Graph], [Vertex|Vertices]) :-
% 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-[]]
-%
+% ```
+% ?- 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([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),
% 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-[]]
+% ```
+% ?- 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) :-
% 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-[]]
+% ```
+% ?- 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-[]]
+% ```
del_vertices(Graph, Vertices, NewGraph) :-
sort(Vertices, V1), % JW: was msort
% 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([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),
%
% 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([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) :- !.
% 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([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(+Set1, +Set2, ?Difference)
%
-% Is based on ord_subtract
+% Is based on `ord_subtract/3`
graph_subtract(Set1, [], Set1) :- !.
graph_subtract([], _, []).
%
% 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([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).
% 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([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).
%
% 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
+% 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-[]]
+% ```
+% ?- 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-[]]
+% ```
transpose_ugraph(Graph, NewGraph) :-
edges(Graph, Edges),
% 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([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),
% 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]
+% ```
+% ?- top_sort([1-[2], 2-[3], 3-[]], L).
+% L = [1, 2, 3]
+% ```
top_sort(Graph, Sorted) :-
vertices_and_zeros(Graph, Vertices, Counts0),
%% top_sort(+Graph, -Sorted, ?Tail) is semidet.
%
-% The predicate top\_sort/3 is a difference list version of
-% top\_sort/2.
+% The predicate `top_sort/3` is a difference list version of
+% `top_sort/2`.
top_sort(Graph, Sorted0, Sorted) :-
vertices_and_zeros(Graph, Vertices, Counts0),
% 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]
+% ```
+% ?- 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, -Neigbours) is det.
%
-% Same as neighbours/3
+% Same as `neighbours/3`.
neighbors(Vertex, Graph, Neig) :-
neighbours(Vertex, Graph, Neig).
%
% 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]
-% ).
+% ```
+% 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]) :-
% Unify Before to a term that comes before Term in the standard
% order of terms.
%
-% Throws instantiation_error if Term is unbound.
+% Throws `instantiation_error` if Term is unbound.
before(X, _) :-
var(X),
% _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]]
-%
+% ```
+% ?- 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]]
+% ```
% TODO: Simple two-step algorithm. You could be smarter, I suppose.
% 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(1,[1-[3,5],2-[4],3-[],4-[5],5-[]],V).
+% V = [1, 3, 5]
+% ```
reachable(N, G, Rs) :-
reachable([N], G, [N], Rs).
(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
- * uuid\_string/2, to converte between UUID list of bytes and UUID hex representation
+
+ * `uuidv4/1`, to generate a new UUIDv4
+ * `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|...].
- ?- uuidv4_string(X).
- X = "428499fc-76e3-4240- ...".
- ?- uuidv4(X), uuid_string(X, S).
- X = [173,12,244,152,139,118,64,139,137,4|...], S = "ad0cf498-8b76-408b- ...".
- ?- uuid_string(X, "61ae692e-eaf6-4199-8dd3-9f01db70a20b").
- X = [97,174,105,46,234,246,65,153,141,211|...].
+```
+?- uuidv4(X).
+ X = [42,147,248,242,117,196,79,2,129,159|...].
+?- uuidv4_string(X).
+ X = "428499fc-76e3-4240- ...".
+?- uuidv4(X), uuid_string(X, S).
+ X = [173,12,244,152,139,118,64,139,137,4|...], S = "ad0cf498-8b76-408b- ...".
+?- uuid_string(X, "61ae692e-eaf6-4199-8dd3-9f01db70a20b").
+ X = [97,174,105,46,234,246,65,153,141,211|...].
*/
:- module(uuid, [
%% uuidv4_string(-UuidString).
%
% Generates a new UUID v4 (random). It unifies with a string representation of the UUID.
-% It is equivalent of calling uuidv4/1 followed by uuid\_string/2.
+% It is equivalent of calling `uuidv4/1` followed by `uuid_string/2`.
uuidv4_string(String) :- uuidv4(Uuid), uuid_string(Uuid, String).
%% uuid_string(?UuidBytes, ?UuidString).