improve docs

This commit is contained in:
Vítor Santos Costa 2014-09-15 03:13:50 -05:00
parent 582efcf6eb
commit 8eec3113be
43 changed files with 3307 additions and 1435 deletions

View File

@ -17,7 +17,7 @@
/** @defgroup YAPArrays Arrays
@ingroup YAPBuiltins
@ingroup YAPExtensions
@{
The YAP system includes experimental support for arrays. The
@ -124,7 +124,8 @@ static Int p_compile_array_refs( USES_REGS1 );
static Int p_array_refs_compiled( USES_REGS1 );
static Int p_sync_mmapped_arrays( USES_REGS1 );
/*
/**
* === Implementation Notes
*
* This file works together with pl/arrays.yap and arrays.h.
*
@ -136,7 +137,7 @@ static Int p_sync_mmapped_arrays( USES_REGS1 );
* object. Any term can be an argument to a dynamic array.
*
* Dynamic arrays are named as a free variable and are
* initialised with free variables.
* initialized with free variables.
*
* o named arrays are created during execution but allocated
* in the code space. They have the lifetime of an heap
@ -145,13 +146,13 @@ static Int p_sync_mmapped_arrays( USES_REGS1 );
* Named arrays are named with atoms and are initialised with
* free variables.
*
* o static arrays are allocated in the heap. Their space is
* never recovered unless explictly said so by the
* + static arrays are allocated in the heap. Their space is
* never recovered unless explicitly said so by the
* program. Arguments to these arrays must have fixed size,
* and can only be atomic (at least for now).
*
* Static arrays can be named through an atom. They are
* initialised with [].
* initialized with [].
*
* Users create arrays by a declaration X array Arity. If X is an atom
* A, then this it is a static array and A's the array name, otherwise
@ -165,16 +166,17 @@ static Int p_sync_mmapped_arrays( USES_REGS1 );
* of array X. The mechanism used to implement this is the same
* mechanism used to implement suspension variables.
*
* Representation:
* ==== Representation:
*
* Dynamic Arrays are represented as a compound term of arity N, where
* N is the size of the array. Even so, I will not include array bound
* checking for now.
*
* ~~~~
* |--------------------------------------------------------------|
* | $ARRAY/N|....
* |______________________________________________________________
*
* ~~~~
*
* Unbound Var is used as a place to point to.
*
@ -184,27 +186,7 @@ static Int p_sync_mmapped_arrays( USES_REGS1 );
* A term of the form X[I] is represented as a Reference pointing to
* the compound term:
*
* '$array_arg'(X,I)
*
* Dereferecing will automatically find X[I].
*
* The only exception is the compiler, which uses a different
* dereferencing routine. The clause cl(a[2], Y[X], Y) will be
* compiled as:
*
* cl(A, B, Y) :- '$access_array'(a, A, 2), '$access_array'(Y, B, X).
*
* There are three operations to access arrays:
*
* X[I] = A, This is normal unification.
*
* X[I] := A, This is multiassignment, and therefore
* backtrackable.
*
* X[I] ::= A, This is non-backtrackable multiassignment, ans most
* useful for static arrays.
*
* The LHS of := and of ::= must be an array element!
* []([I],X)
*
*/
@ -534,6 +516,17 @@ AccessNamedArray(Atom a, Int indx USES_REGS)
}
/** @pred array_element(+ _Name_, + _Index_, ? _Element_)
Unify _Element_ with _Name_[ _Index_]. It works for both
static and dynamic arrays, but it is read-only for static arrays, while
it can be used to unify with an element of a dynamic array.
*/
/// @memberof array_element/3
static Int
p_access_array( USES_REGS1 )
{
@ -1049,6 +1042,15 @@ p_create_array( USES_REGS1 )
/* create an array (+Name, + Size, +Props) */
static Int
/** @pred static_array(+ _Name_, + _Size_, + _Type_)
Create a new static array with name _Name_. Note that the _Name_
must be an atom (named array). The _Size_ must evaluate to an
integer. The _Type_ must be bound to one of types mentioned
previously.
*/
/// @memberof static_array/3
p_create_static_array( USES_REGS1 )
{
Term ti = Deref(ARG2);
@ -1258,6 +1260,14 @@ p_resize_static_array( USES_REGS1 )
/* resize a static array (+Name, + Size, +Props) */
/* does not work for mmap arrays yet */
/** @pred reset_static_array(+ _Name_)
Reset static array with name _Name_ to its initial value.
*/
/// @memberof reset_static_array/1
static Int
p_clear_static_array( USES_REGS1 )
{
@ -1288,6 +1298,16 @@ p_clear_static_array( USES_REGS1 )
}
/* Close a named array (+Name) */
/** @pred close_static_array(+ _Name_)
Close an existing static array of name _Name_. The _Name_ must
be an atom (named array). Space for the array will be recovered and
further accesses to the array will return an error.
*/
/// @memberof close_static_array/1
static Int
p_close_static_array( USES_REGS1 )
{
@ -1337,7 +1357,20 @@ p_close_static_array( USES_REGS1 )
}
}
/* create an array (+Name, + Size, +Props) */
/** @pred mmapped_array(+ _Name_, + _Size_, + _Type_, + _File_)
Similar to static_array/3, but the array is memory mapped to file
_File_. This means that the array is initialized from the file, and
that any changes to the array will also be stored in the file.
This built-in is only available in operating systems that support the
system call `mmap`. Moreover, mmapped arrays do not store generic
terms (type `term`).
*/
/// @memberof mmapped_array/4
static Int
p_create_mmapped_array( USES_REGS1 )
{
@ -1634,6 +1667,24 @@ p_array_references( USES_REGS1 )
return (Yap_unify(t1, ARG2) && Yap_unify(t2, ARG3));
}
/** @pred update_array(+ _Name_, + _Index_, ? _Value_)
Attribute value _Value_ to _Name_[ _Index_]. Type
restrictions must be respected for static arrays. This operation is
available for dynamic arrays if `MULTI_ASSIGNMENT_VARIABLES` is
enabled (true by default). Backtracking undoes _update_array/3_ for
dynamic arrays, but not for static arrays.
Note that update_array/3 actually uses `setarg/3` to update
elements of dynamic arrays, and `setarg/3` spends an extra cell for
every update. For intensive operations we suggest it may be less
expensive to unify each element of the array with a mutable terms and
to use the operations on mutable terms.
*/
/// @memberof update_array/3
static Int
p_assign_static( USES_REGS1 )
{
@ -2106,6 +2157,30 @@ p_assign_dynamic( USES_REGS1 )
return TRUE;
}
/** @pred add_to_array_element(+ _Name_, + _Index_, + _Number_, ? _NewValue_)
Add _Number_ _Name_[ _Index_] and unify _NewValue_ with
the incremented value. Observe that _Name_[ _Index_] must be an
number. If _Name_ is a static array the type of the array must be
`int` or `float`. If the type of the array is `int` you
only may add integers, if it is `float` you may add integers or
floats. If _Name_ corresponds to a dynamic array the array element
must have been previously bound to a number and `Number` can be
any kind of number.
The `add_to_array_element/3` built-in actually uses
`setarg/3` to update elements of dynamic arrays. For intensive
operations we suggest it may be less expensive to unify each element
of the array with a mutable terms and to use the operations on mutable
terms.
*/
/// @memberof add_to_array_element/4
static Int
p_add_to_array_element( USES_REGS1 )
{
@ -2327,6 +2402,18 @@ p_sync_mmapped_arrays( USES_REGS1 )
return(TRUE);
}
/** @pred static_array_to_term(? _Name_, ? _Term_)
Convert a static array with name
_Name_ to a compound term of name _Name_.
This built-in will silently fail if the there is no static array with
that name.
*/
/// @memberof static_array_to_term/2
static Int
p_static_array_to_term( USES_REGS1 )
{
@ -2490,6 +2577,13 @@ p_static_array_to_term( USES_REGS1 )
return FALSE;
}
/** @pred static_array_location(+ _Name_, - _Ptr_)
Give the location or memory address for a static array with name
_Name_. The result is observed as an integer.
*/
/// @memberof static_array_location/2
static Int
p_static_array_location( USES_REGS1 )
{
@ -2526,139 +2620,20 @@ Yap_InitArrayPreds( void )
Yap_InitCPred("$array_references", 3, p_array_references, SafePredFlag);
Yap_InitCPred("$array_arg", 3, p_array_arg, SafePredFlag);
Yap_InitCPred("static_array", 3, p_create_static_array, SafePredFlag|SyncPredFlag);
/** @pred static_array(+ _Name_, + _Size_, + _Type_)
Create a new static array with name _Name_. Note that the _Name_
must be an atom (named array). The _Size_ must evaluate to an
integer. The _Type_ must be bound to one of types mentioned
previously.
*/
Yap_InitCPred("resize_static_array", 3, p_resize_static_array, SafePredFlag|SyncPredFlag);
/** @pred resize_static_array(+ _Name_, - _OldSize_, + _NewSize_)
Expand or reduce a static array, The _Size_ must evaluate to an
integer. The _Name_ must be an atom (named array). The _Type_
must be bound to one of `int`, `dbref`, `float` or
`atom`.
Note that if the array is a mmapped array the size of the mmapped file
will be actually adjusted to correspond to the size of the array.
*/
Yap_InitCPred("mmapped_array", 4, p_create_mmapped_array, SafePredFlag|SyncPredFlag);
/** @pred mmapped_array(+ _Name_, + _Size_, + _Type_, + _File_)
Similar to static_array/3, but the array is memory mapped to file
_File_. This means that the array is initialized from the file, and
that any changes to the array will also be stored in the file.
This built-in is only available in operating systems that support the
system call `mmap`. Moreover, mmapped arrays do not store generic
terms (type `term`).
*/
Yap_InitCPred("update_array", 3, p_assign_static, SafePredFlag);
/** @pred update_array(+ _Name_, + _Index_, ? _Value_)
Attribute value _Value_ to _Name_[ _Index_]. Type
restrictions must be respected for static arrays. This operation is
available for dynamic arrays if `MULTI_ASSIGNMENT_VARIABLES` is
enabled (true by default). Backtracking undoes _update_array/3_ for
dynamic arrays, but not for static arrays.
Note that update_array/3 actually uses `setarg/3` to update
elements of dynamic arrays, and `setarg/3` spends an extra cell for
every update. For intensive operations we suggest it may be less
expensive to unify each element of the array with a mutable terms and
to use the operations on mutable terms.
*/
Yap_InitCPred("dynamic_update_array", 3, p_assign_dynamic, SafePredFlag);
Yap_InitCPred("add_to_array_element", 4, p_add_to_array_element, SafePredFlag);
/** @pred add_to_array_element(+ _Name_, + _Index_, + _Number_, ? _NewValue_)
Add _Number_ _Name_[ _Index_] and unify _NewValue_ with
the incremented value. Observe that _Name_[ _Index_] must be an
number. If _Name_ is a static array the type of the array must be
`int` or `float`. If the type of the array is `int` you
only may add integers, if it is `float` you may add integers or
floats. If _Name_ corresponds to a dynamic array the array element
must have been previously bound to a number and `Number` can be
any kind of number.
The `add_to_array_element/3` built-in actually uses
`setarg/3` to update elements of dynamic arrays. For intensive
operations we suggest it may be less expensive to unify each element
of the array with a mutable terms and to use the operations on mutable
terms.
*/
Yap_InitCPred("array_element", 3, p_access_array, 0);
/** @pred array_element(+ _Name_, + _Index_, ? _Element_)
Unify _Element_ with _Name_[ _Index_]. It works for both
static and dynamic arrays, but it is read-only for static arrays, while
it can be used to unify with an element of a dynamic array.
*/
Yap_InitCPred("reset_static_array", 1, p_clear_static_array, SafePredFlag);
/** @pred reset_static_array(+ _Name_)
Reset static array with name _Name_ to its initial value.
*/
Yap_InitCPred("close_static_array", 1, p_close_static_array, SafePredFlag);
/** @pred close_static_array(+ _Name_)
Close an existing static array of name _Name_. The _Name_ must
be an atom (named array). Space for the array will be recovered and
further accesses to the array will return an error.
*/
Yap_InitCPred("$sync_mmapped_arrays", 0, p_sync_mmapped_arrays, SafePredFlag);
Yap_InitCPred("$compile_array_refs", 0, p_compile_array_refs, SafePredFlag);
Yap_InitCPred("$array_refs_compiled", 0, p_array_refs_compiled, SafePredFlag);
Yap_InitCPred("$static_array_properties", 3, p_static_array_properties, SafePredFlag);
Yap_InitCPred("static_array_to_term", 2, p_static_array_to_term, 0L);
/** @pred static_array_to_term(? _Name_, ? _Term_)
Convert a static array with name
_Name_ to a compound term of name _Name_.
This built-in will silently fail if the there is no static array with
that name.
*/
Yap_InitCPred("static_array_location", 2, p_static_array_location, 0L);
/** @pred static_array_location(+ _Name_, - _Ptr_)
Give the location for a static array with name
_Name_.
*/
}

View File

@ -24,7 +24,7 @@ static char SccsId[] = "%W% %G%";
The following predicates are used to manipulate atoms:
\toc
*/

View File

@ -20,7 +20,6 @@
/** @defgroup Comparing_Terms Comparing Terms
@ingroup YAPBuiltins
@{
The following predicates are used to compare and order terms, using the
standard ordering:
@ -45,7 +44,7 @@ Compound terms are ordered first by arity of the main functor, then by
the name of the main functor, and finally by their arguments in
left-to-right order.
@{
@ -537,7 +536,21 @@ Int Yap_compare_terms(Term d0, Term d1)
return compare(Deref(d0),Deref(d1));
}
static Int
/** @pred compare( _C_, _X_, _Y_) is iso
As a result of comparing _X_ and _Y_, _C_ may take one of
the following values:
+
`=` if _X_ and _Y_ are identical;
+
`<` if _X_ precedes _Y_ in the defined order;
+
`>` if _Y_ precedes _X_ in the defined order;
*/
Int
p_compare( USES_REGS1 )
{ /* compare(?Op,?T1,?T2) */
Int r = compare(Deref(ARG2), Deref(ARG3));
@ -552,6 +565,70 @@ p_compare( USES_REGS1 )
return Yap_unify_constant(ARG1, MkAtomTerm(p));
}
/** @pred _X_ \== _Y_ is iso
Terms _X_ and _Y_ are not strictly identical.
*/
static Int
a_noteq(Term t1, Term t2)
{
return (compare(t1, t2) != 0);
}
static Int
a_gen_lt(Term t1, Term t2)
{
return (compare(t1, t2) < 0);
}
/** @pred _X_ @=< _Y_ is iso
Term _X_ does not follow term _Y_ in the standard order.
*/
static Int
a_gen_le(Term t1, Term t2)
{
return (compare(t1, t2) <= 0);
}
/** @pred _X_ @> _Y_ is iso
Term _X_ does not follow term _Y_ in the standard order
*/
static Int
a_gen_gt(Term t1, Term t2)
{
return compare(t1, t2) > 0;
}
/** @pred _X_ @>= _Y_ is iso
Term _X_ does not precede term _Y_ in the standard order.
*/
static Int
a_gen_ge(Term t1, Term t2)
{
return compare(t1, t2) >= 0;
}
/**
@}
*/
/**
@defgroup arithmetic_cmps Arithmetic Comparison Predicates
@ingroup arithmetic
Comparison of Numeric Expressions. Both arguments must be valid ground expressions at time of call.
@{
*/
inline static Int
int_cmp(Int dif)
{
@ -685,17 +762,6 @@ a_cmp(Term t1, Term t2 USES_REGS)
}
}
/**
@defgroup arithmetic_cmps Arithmetic Comparison Predicates
@ingroup arithmetic
Comparison of Numeric Expressions. Both arguments must be valid ground expressions at time of call.
@{
*/
Int
Yap_acmp(Term t1, Term t2 USES_REGS)
{
@ -717,15 +783,12 @@ p_acomp( USES_REGS1 )
}
/**
@[
@class arith_eq_2
@brief =:=/2: Equality of arithmetic expressions
@pred +_X_ =:= _Y_ is iso
Equality of arithmetic expressions
<b>+ _X_ =:= + _Y_ [ISO]</b><p> @anchor ar_eq_2
The value of the expression _X_ is less than the value of expression _Y_.
The value of the expression _X_ is equal to the value of expression _Y_.
*/
/// @memberof =:=/2
static Int
a_eq(Term t1, Term t2)
{
@ -760,17 +823,14 @@ a_eq(Term t1, Term t2)
return out == 0;
}
/**
@}
@class arith_dif_2
@brief =\\=/2: Difference of arithmetic expressions
<b>+ _X_ =\\= + _Y_ [ISO]</b><p> @anchor ar_dif_2
/*
@pred +_X_ =\\= _Y_ is iso
Difference of arithmetic expressions
The value of the expression _X_ is different from the value of expression _Y_.
*/
/// @memberof =\\=/2
static Int
a_dif(Term t1, Term t2)
{
@ -781,11 +841,8 @@ a_dif(Term t1, Term t2)
}
/**
@class arith_gt_2
@brief \>/2: Greater than arithmetic expressions
<b>+ _X_ \> + _Y_ [ISO]</b><p> @anchor qQlg_2
@pred +_X_ \> +_Y_ is iso
Greater than arithmetic expressions
The value of the expression _X_ is less than or equal to the value
of expression _Y_.
@ -800,11 +857,8 @@ a_gt(Term t1, Term t2)
}
/**
@class arith_ge_2
@brief \>=/2: Greater than or equal to arithmetic expressions
<b>+ _X_ \>= + _Y_ [ISO]</b><p> @anchor gGqQ_2
@pred +_X_ >= +_Y_ is iso
Greater than or equal to arithmetic expressions
The value of the expression _X_ is greater than or equal to the
value of expression _Y_.
@ -819,15 +873,13 @@ a_ge(Term t1, Term t2)
}
/**
@class arith_lt_2
@brief \</2: Lesser than arithmetic expressions
<b>+ _X_ \< + _Y_ [ISO]</b><p> @anchor sS_2
@pred +_X_ \< +_Y_ is iso
Lesser than arithmetic expressions
The value of the expression _X_ is less than the value of expression
_Y_.
*/
/// @memberof </2
static Int
a_lt(Term t1, Term t2)
{ /* A < B */
@ -839,15 +891,14 @@ a_lt(Term t1, Term t2)
/**
*
@class arith_le_2
@brief =\</2: Lesser than or equal to arithmetic expressions
<b>+ _X_ =\< + _Y_ [ISO]</b><p> @anchor qQsS_2
@pred _X_ =< + _Y_
Lesser than or equal to arithmetic expressions
The value of the expression _X_ is less than or equal to the value
of expression _Y_.
*/
/// @memberof =</2
static Int
a_le(Term t1, Term t2)
{ /* A <= B */
@ -857,38 +908,9 @@ a_le(Term t1, Term t2)
return out <= 0;
}
/// @}
static Int
a_noteq(Term t1, Term t2)
{
return (compare(t1, t2) != 0);
}
static Int
a_gen_lt(Term t1, Term t2)
{
return (compare(t1, t2) < 0);
}
static Int
a_gen_le(Term t1, Term t2)
{
return (compare(t1, t2) <= 0);
}
static Int
a_gen_gt(Term t1, Term t2)
{
return compare(t1, t2) > 0;
}
static Int
a_gen_ge(Term t1, Term t2)
{
return compare(t1, t2) >= 0;
}
/**
@}
*/
void
Yap_InitCmpPreds(void)
@ -901,90 +923,11 @@ Yap_InitCmpPreds(void)
Yap_InitCmpPred(">=", 2, a_ge, SafePredFlag | BinaryPredFlag);
Yap_InitCPred("$a_compare", 3, p_acomp, TestPredFlag | SafePredFlag);
Yap_InitCmpPred("\\==", 2, a_noteq, BinaryPredFlag | SafePredFlag);
/** @pred _X_ \== _Y_ is iso
Terms _X_ and _Y_ are not strictly identical.
*/
Yap_InitCmpPred("@<", 2, a_gen_lt, BinaryPredFlag | SafePredFlag);
/** @pred _X_ @< _Y_ is iso
Term _X_ precedes term _Y_ in the standard order.
*/
Yap_InitCmpPred("@=<", 2, a_gen_le, BinaryPredFlag | SafePredFlag);
/** @pred _X_ @=< _Y_ is iso
Term _X_ does not follow term _Y_ in the standard order.
*/
Yap_InitCmpPred("@>", 2, a_gen_gt, BinaryPredFlag | SafePredFlag);
/** @pred _X_ @> _Y_ is iso
Term _X_ follows term _Y_ in the standard order.
*/
Yap_InitCmpPred("@>=", 2, a_gen_ge, BinaryPredFlag | SafePredFlag);
/** @pred _X_ @>= _Y_ is iso
Term _X_ does not precede term _Y_ in the standard order.
*/
Yap_InitCPred("compare", 3, p_compare, TestPredFlag | SafePredFlag);
/** @pred compare( _C_, _X_, _Y_) is iso
As a result of comparing _X_ and _Y_, _C_ may take one of
the following values:
+
`=` if _X_ and _Y_ are identical;
+
`<` if _X_ precedes _Y_ in the defined order;
+
`>` if _Y_ precedes _X_ in the defined order;
+ _X_ == _Y_ is iso
Succeeds if terms _X_ and _Y_ are strictly identical. The
difference between this predicate and =/2 is that, if one of the
arguments is a free variable, it only succeeds when they have already
been unified.
~~~~~{.prolog}
?- X == Y.
~~~~~
fails, but,
~~~~~{.prolog}
?- X = Y, X == Y.
~~~~~
succeeds.
~~~~~{.prolog}
?- X == 2.
~~~~~
fails, but,
~~~~~{.prolog}
?- X = 2, X == 2.
~~~~~
succeeds.
*/
}
/**

View File

@ -191,6 +191,7 @@ BEAM_is(void)
#endif
/**
@{
@pred is( X:number, + Y:ground) is det
This predicate succeeds iff the result of evaluating the expression
@ -201,8 +202,11 @@ X is 2+3*4
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
succeeds with `X = 14`.
Consult @ref arithmetic_operators for the complete list of arithmetic_operators
*/
/// @memberof is/2
static Int
p_is( USES_REGS1 )
{ /* X is Y */
@ -223,15 +227,18 @@ p_is( USES_REGS1 )
return Yap_unify_constant(ARG1,out);
}
//@}
/**
@pred isnan(? X:float) is det
Interface to the IEE754 `isnan` test.
*/
/// @memberof isnan/1
static Int
p_isnan( USES_REGS1 )
{ /* X is Y */
{ /* X isnan Y */
Term out = 0L;
while (!(out = Eval(Deref(ARG1) PASS_REGS))) {
@ -263,7 +270,7 @@ p_isnan( USES_REGS1 )
Interface to the IEE754 `isinf` test.
*/
/// @memberof isnan/1
static Int
p_isinf( USES_REGS1 )
{ /* X is Y */
@ -293,13 +300,15 @@ p_isinf( USES_REGS1 )
}
/**
@pred logsum(+ Log1:float, + Log2:float, - Out:float ) is det
@{ @pred logsum(+ Log1:float, + Log2:float, - Out:float ) is det
True if _Log1_ is the logarithm of the positive number _A1_,
_Log2_ is the logarithm of the positive number _A2_, and
_Out_ is the logarithm of the sum of the numbers _A1_ and
_A2_. Useful in probability computation.
*/
/// @memberof logsum/3
static Int
p_logsum( USES_REGS1 )
{ /* X is Y */
@ -372,6 +381,8 @@ p_logsum( USES_REGS1 )
}
}
// @}
Int
Yap_ArithError(yap_error_number type, Term where, char *format,...)
{
@ -413,6 +424,7 @@ Yap_ArithError(yap_error_number type, Term where, char *format,...)
*/
/// @memberof between/3
static Int cont_between( USES_REGS1 )
{
Term t1 = EXTRA_CBACK_ARG(3,1);
@ -447,6 +459,7 @@ static Int cont_between( USES_REGS1 )
}
}
/// @memberof between/3
static Int
init_between( USES_REGS1 )
{
@ -542,6 +555,11 @@ init_between( USES_REGS1 )
return cont_between( PASS_REGS1 );
}
/**
*
* @}
*/
void
Yap_InitEval(void)
{
@ -554,20 +572,6 @@ Yap_InitEval(void)
Yap_InitCPred("isinf", 1, p_isinf, TestPredFlag);
Yap_InitCPred("logsum", 3, p_logsum, TestPredFlag);
Yap_InitCPredBack("between", 3, 2, init_between, cont_between, 0);
/** @pred between(+ _Low_,+ _High_,? _Value_)
_Low_ and _High_ are integers, _High_ less or equal than
_Low_. If _Value_ is an integer, _Low_ less or equal than
_Value_ less or equal than _High_. When _Value_ is a
variable it is successively bound to all integers between _Low_ and
_High_. If _High_ is `inf`, between/3 is true iff
_Value_ less or equal than _Low_, a feature that is particularly
interesting for generating integers from a certain value.
*/
}
/**

View File

@ -101,6 +101,93 @@ int Yap_Portray_delays = FALSE;
#endif
#endif
/**
@defgroup Operators Summary of YAP Predefined Operators
@ingroup Syntax
@{
The Prolog syntax caters for operators of three main kinds:
+ prefix;
+ infix;
+ postfix.
Each operator has precedence in the range 1 to 1200, and this
precedence is used to disambiguate expressions where the structure of the
term denoted is not made explicit using brackets. The operator of higher
precedence is the main functor.
If there are two operators with the highest precedence, the ambiguity
is solved analyzing the types of the operators. The possible infix types are:
_xfx_, _xfy_, and _yfx_.
With an operator of type _xfx_ both sub-expressions must have lower
precedence than the operator itself, unless they are bracketed (which
assigns to them zero precedence). With an operator type _xfy_ only the
left-hand sub-expression must have lower precedence. The opposite happens
for _yfx_ type.
A prefix operator can be of type _fx_ or _fy_.
A postfix operator can be of type _xf_ or _yf_.
The meaning of the notation is analogous to the above.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
a + b * c
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
means
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
a + (b * c)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
as + and \* have the following types and precedences:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:-op(500,yfx,'+').
:-op(400,yfx,'*').
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Now defining
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:-op(700,xfy,'++').
:-op(700,xfx,'=:=').
a ++ b =:= c
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
means
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
a ++ (b =:= c)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The following is the list of the declarations of the predefined operators:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:-op(1200,fx,['?-', ':-']).
:-op(1200,xfx,[':-','-->']).
:-op(1150,fx,[block,dynamic,mode,public,multifile,meta_predicate,
sequential,table,initialization]).
:-op(1100,xfy,[';','|']).
:-op(1050,xfy,->).
:-op(1000,xfy,',').
:-op(999,xfy,'.').
:-op(900,fy,['\+', not]).
:-op(900,fx,[nospy, spy]).
:-op(700,xfx,[@>=,@=<,@<,@>,<,=,>,=:=,=\=,\==,>=,=<,==,\=,=..,is]).
:-op(500,yfx,['\/','/\','+','-']).
:-op(500,fx,['+','-']).
:-op(400,yfx,['<<','>>','//','*','/']).
:-op(300,xfx,mod).
:-op(200,xfy,['^','**']).
:-op(50,xfx,same).
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#define xfx 1
#define xfy 2
#define yfx 3
@ -330,6 +417,8 @@ InitOps(void)
SetOp(Ops[i].opPrio, Ops[i].opType, Ops[i].opName, PROLOG_MODULE);
}
/// @}
#if DEBUG
#ifdef HAVE_ISATTY
#include <unistd.h>

View File

@ -17,6 +17,97 @@
#ifdef SCCS
static char SccsId[] = "%W% %G%";
#endif
/**
@defgroup Syntax YAP Syntax
@ingroup YAPProgramming
@{
We will describe the syntax of YAP at two levels. We first will
describe the syntax for Prolog terms. In a second level we describe
the \a tokens from which Prolog \a terms are
built.
@defgroup Formal_Syntax Syntax of Terms
@ingroup Syntax
@{
Below, we describe the syntax of YAP terms from the different
classes of tokens defined above. The formalism used will be <em>BNF</em>,
extended where necessary with attributes denoting integer precedence or
operator type.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
term ----> subterm(1200) end_of_term_marker
subterm(N) ----> term(M) [M <= N]
term(N) ----> op(N, fx) subterm(N-1)
| op(N, fy) subterm(N)
| subterm(N-1) op(N, xfx) subterm(N-1)
| subterm(N-1) op(N, xfy) subterm(N)
| subterm(N) op(N, yfx) subterm(N-1)
| subterm(N-1) op(N, xf)
| subterm(N) op(N, yf)
term(0) ----> atom '(' arguments ')'
| '(' subterm(1200) ')'
| '{' subterm(1200) '}'
| list
| string
| number
| atom
| variable
arguments ----> subterm(999)
| subterm(999) ',' arguments
list ----> '[]'
| '[' list_expr ']'
list_expr ----> subterm(999)
| subterm(999) list_tail
list_tail ----> ',' list_expr
| ',..' subterm(999)
| '|' subterm(999)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Notes:
+ \a op(N,T) denotes an atom which has been previously declared with type
\a T and base precedence \a N.
+ Since ',' is itself a pre-declared operator with type \a xfy and
precedence 1000, is \a subterm starts with a '(', \a op must be
followed by a space to avoid ambiguity with the case of a functor
followed by arguments, e.g.:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ (a,b) [the same as '+'(','(a,b)) of arity one]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
versus
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+(a,b) [the same as '+'(a,b) of arity two]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
In the first rule for term(0) no blank space should exist between
\a atom and '('.
+
Each term to be read by the YAP parser must end with a single
dot, followed by a blank (in the sense mentioned in the previous
paragraph). When a name consisting of a single dot could be taken for
the end of term marker, the ambiguity should be avoided by surrounding the
dot with single quotes.
@}
*/
/*
* Description:
*

View File

@ -32,6 +32,365 @@
*
*/
/**
@defgroup Formal_Syntax Syntax of Terms
@ingroup Syntax
@{
Prolog tokens are grouped into the following categories:
+ Numbers
Numbers can be further subdivided into integer and floating-point numbers.
+ Integers
Integer numbers
are described by the following regular expression:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<integer> := {<digit>+<single-quote>|0{xXo}}<alpha_numeric_char>+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
where {...} stands for optionality, \a + optional repetition (one or
more times), \a \\\<digit\\\> denotes one of the characters 0 ... 9, \a |
denotes or, and \a \\\<single-quote\\\> denotes the character "'". The digits
before the \a \\\<single-quote\\\> character, when present, form the number
basis, that can go from 0, 1 and up to 36. Letters from `A` to
`Z` are used when the basis is larger than 10.
Note that if no basis is specified then base 10 is assumed. Note also
that the last digit of an integer token can not be immediately followed
by one of the characters 'e', 'E', or '.'.
Following the ISO standard, YAP also accepts directives of the
form `0x` to represent numbers in hexadecimal base and of the form
`0o` to represent numbers in octal base. For usefulness,
YAP also accepts directives of the form `0X` to represent
numbers in hexadecimal base.
Example:
the following tokens all denote the same integer
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
10 2'1010 3'101 8'12 16'a 36'a 0xa 0o12
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Numbers of the form `0'a` are used to represent character
constants. So, the following tokens denote the same integer:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0'd 100
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
YAP (version 6.3.4) supports integers that can fit
the word size of the machine. This is 32 bits in most current machines,
but 64 in some others, such as the Alpha running Linux or Digital
Unix. The scanner will read larger or smaller integers erroneously.
+ Floats
Floating-point numbers are described by:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<float> := <digit>+{<dot><digit>+}
<exponent-marker>{<sign>}<digit>+
|<digit>+<dot><digit>+
{<exponent-marker>{<sign>}<digit>+}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
where \a \\\<dot\\\> denotes the decimal-point character '.',
\a \\\<exponent-marker\\\> denotes one of 'e' or 'E', and \a \\\<sign\\\> denotes
one of '+' or '-'.
Examples:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
10.0 10e3 10e-3 3.1415e+3
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Floating-point numbers are represented as a double in the target
machine. This is usually a 64-bit number.
+ Strings Character Strings
Strings are described by the following rules:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
string --> '"' string_quoted_characters '"'
string_quoted_characters --> '"' '"' string_quoted_characters
string_quoted_characters --> '\'
escape_sequence string_quoted_characters
string_quoted_characters -->
string_character string_quoted_characters
escape_sequence --> 'a' | 'b' | 'r' | 'f' | 't' | 'n' | 'v'
escape_sequence --> '\' | '"' | ''' | '`'
escape_sequence --> at_most_3_octal_digit_seq_char '\'
escape_sequence --> 'x' at_most_2_hexa_digit_seq_char '\'
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
where `string_character` in any character except the double quote
and escape characters.
Examples:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"" "a string" "a double-quote:"""
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The first string is an empty string, the last string shows the use of
double-quoting. The implementation of YAP represents strings as
lists of integers. Since YAP 4.3.0 there is no static limit on string
size.
Escape sequences can be used to include the non-printable characters
`a` (alert), `b` (backspace), `r` (carriage return),
`f` (form feed), `t` (horizontal tabulation), `n` (new
line), and `v` (vertical tabulation). Escape sequences also be
include the meta-characters `\\`, `"`, `'`, and
```. Last, one can use escape sequences to include the characters
either as an octal or hexadecimal number.
The next examples demonstrates the use of escape sequences in YAP:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"\x0c\" "\01\" "\f" "\\"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The first three examples return a list including only character 12 (form
feed). The last example escapes the escape character.
Escape sequences were not available in C-Prolog and in original
versions of YAP up to 4.2.0. Escape sequences can be disable by using:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:- yap_flag(character_escapes,false).
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ Atoms Atoms
Atoms are defined by one of the following rules:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
atom --> solo-character
atom --> lower-case-letter name-character*
atom --> symbol-character+
atom --> single-quote single-quote
atom --> ''' atom_quoted_characters '''
atom_quoted_characters --> ''' ''' atom_quoted_characters
atom_quoted_characters --> '\' atom_sequence string_quoted_characters
atom_quoted_characters --> character string_quoted_characters
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
where:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<solo-character> denotes one of: ! ;
<symbol-character> denotes one of: # & * + - . / : <
= > ? @ \ ^ ~ `
<lower-case-letter> denotes one of: a...z
<name-character> denotes one of: _ a...z A...Z 0....9
<single-quote> denotes: '
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
and `string_character` denotes any character except the double quote
and escape characters. Note that escape sequences in strings and atoms
follow the same rules.
Examples:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
a a12x '$a' ! => '1 2'
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Version `4.2.0` of YAP removed the previous limit of 256
characters on an atom. Size of an atom is now only limited by the space
available in the system.
+ Variables Variables
Variables are described by:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<variable-starter><variable-character>+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
where
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<variable-starter> denotes one of: _ A...Z
<variable-character> denotes one of: _ a...z A...Z
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If a variable is referred only once in a term, it needs not to be named
and one can use the character `_` to represent the variable. These
variables are known as anonymous variables. Note that different
occurrences of `_` on the same term represent <em>different</em>
anonymous variables.
+ Punctuation Tokens
Punctuation tokens consist of one of the following characters:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
( ) , [ ] { } |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
These characters are used to group terms.
@subsection Layout Layout
Any characters with ASCII code less than or equal to 32 appearing before
a token are ignored.
All the text appearing in a line after the character \a % is taken to
be a comment and ignored (including \a %). Comments can also be
inserted by using the sequence `/\*` to start the comment and
`\*` followed by `/` to finish it. In the presence of any sequence of comments or
layout characters, the YAP parser behaves as if it had found a
single blank character. The end of a file also counts as a blank
character for this purpose.
+ Encoding Wide Character Support
YAP now implements a SWI-Prolog compatible interface to wide
characters and the Universal Character Set (UCS). The following text
was adapted from the SWI-Prolog manual.
YAP now supports wide characters, characters with character
codes above 255 that cannot be represented in a single byte.
<em>Universal Character Set</em> (UCS) is the ISO/IEC 10646 standard
that specifies a unique 31-bits unsigned integer for any character in
any language. It is a superset of 16-bit Unicode, which in turn is
a superset of ISO 8859-1 (ISO Latin-1), a superset of US-ASCII. UCS
can handle strings holding characters from multiple languages and
character classification (uppercase, lowercase, digit, etc.) and
operations such as case-conversion are unambiguously defined.
For this reason YAP, following SWI-Prolog, has two representations for
atoms. If the text fits in ISO Latin-1, it is represented as an array
of 8-bit characters. Otherwise the text is represented as an array of
wide chars, which may take 16 or 32 bits. This representational issue
is completely transparent to the Prolog user. Users of the foreign
language interface sometimes need to be aware of these issues though.
Character coding comes into view when characters of strings need to be
read from or written to file or when they have to be communicated to
other software components using the foreign language interface. In this
section we only deal with I/O through streams, which includes file I/O
as well as I/O through network sockets.
+ Stream_Encoding Wide character encodings on streams
Although characters are uniquely coded using the UCS standard
internally, streams and files are byte (8-bit) oriented and there are a
variety of ways to represent the larger UCS codes in an 8-bit octet
stream. The most popular one, especially in the context of the web, is
UTF-8. Bytes 0...127 represent simply the corresponding US-ASCII
character, while bytes 128...255 are used for multi-byte
encoding of characters placed higher in the UCS space. Especially on
MS-Windows the 16-bit Unicode standard, represented by pairs of bytes is
also popular.
Prolog I/O streams have a property called <em>encoding</em> which
specifies the used encoding that influence `get_code/2` and
`put_code/2` as well as all the other text I/O predicates.
The default encoding for files is derived from the Prolog flag
`encoding`, which is initialised from the environment. If the
environment variable `LANG` ends in "UTF-8", this encoding is
assumed. Otherwise the default is `text` and the translation is
left to the wide-character functions of the C-library (note that the
Prolog native UTF-8 mode is considerably faster than the generic
`mbrtowc()` one). The encoding can be specified explicitly in
load_files/2 for loading Prolog source with an alternative
encoding, `open/4` when opening files or using `set_stream/2` on
any open stream (not yet implemented). For Prolog source files we also
provide the `encoding/1` directive that can be used to switch
between encodings that are compatible to US-ASCII (`ascii`,
`iso_latin_1`, `utf8` and many locales).
For
additional information and Unicode resources, please visit
<http://www.unicode.org/>.
YAP currently defines and supports the following encodings:
+ octet
Default encoding for <em>binary</em> streams. This causes
the stream to be read and written fully untranslated.
+ ascii
7-bit encoding in 8-bit bytes. Equivalent to `iso_latin_1`,
but generates errors and warnings on encountering values above
127.
+ iso_latin_1
8-bit encoding supporting many western languages. This causes
the stream to be read and written fully untranslated.
+ text
C-library default locale encoding for text files. Files are read and
written using the C-library functions `mbrtowc()` and
`wcrtomb()`. This may be the same as one of the other locales,
notably it may be the same as `iso_latin_1` for western
languages and `utf8` in a UTF-8 context.
+ utf8
Multi-byte encoding of full UCS, compatible to `ascii`.
See above.
+ unicode_be
Unicode Big Endian. Reads input in pairs of bytes, most
significant byte first. Can only represent 16-bit characters.
+ unicode_le
Unicode Little Endian. Reads input in pairs of bytes, least
significant byte first. Can only represent 16-bit characters.
Note that not all encodings can represent all characters. This implies
that writing text to a stream may cause errors because the stream
cannot represent these characters. The behaviour of a stream on these
errors can be controlled using `open/4` or `set_stream/2` (not
implemented). Initially the terminal stream write the characters using
Prolog escape sequences while other streams generate an I/O exception.
+ BOM BOM: Byte Order Mark
From Stream Encoding, you may have got the impression that
text-files are complicated. This section deals with a related topic,
making live often easier for the user, but providing another worry to
the programmer. *BOM* or <em>Byte Order Marker</em> is a technique
for identifying Unicode text-files as well as the encoding they
use. Such files start with the Unicode character `0xFEFF`, a
non-breaking, zero-width space character. This is a pretty unique
sequence that is not likely to be the start of a non-Unicode file and
uniquely distinguishes the various Unicode file formats. As it is a
zero-width blank, it even doesn't produce any output. This solves all
problems, or ...
Some formats start of as US-ASCII and may contain some encoding mark to
switch to UTF-8, such as the `encoding="UTF-8"` in an XML header.
Such formats often explicitly forbid the the use of a UTF-8 BOM. In
other cases there is additional information telling the encoding making
the use of a BOM redundant or even illegal.
The BOM is handled by the `open/4` predicate. By default, text-files are
probed for the BOM when opened for reading. If a BOM is found, the
encoding is set accordingly and the property `bom(true)` is
available through stream_property/2. When opening a file for
writing, writing a BOM can be requested using the option
`bom(true)` with `open/4`.
*/
#include "Yap.h"
#include "Yatom.h"
#include "YapHeap.h"
@ -1505,3 +1864,5 @@ Yap_clean_tokenizer(TokEntry *tokstart, VarEntry *vartable, VarEntry *anonvartab
LOCAL_CommentsBuffLim = 0;
}
/// @}

View File

@ -25,9 +25,7 @@
+ See @ref arithmetic_cmps for the arithmetic comparisons supported in YAP
+ See @ref arithmetic_operators for how to call arithmetic operations in YAP
+ See @ref arithmetic_operators for what arithmetic operations are supported in YAP
@tableofcontents
@ -61,7 +59,7 @@ used. Rational numbers that are returned from is/2 are canonical,
which means the denominator _M_ is positive and that the numerator _N_
and _M_ have no common divisors. Rational numbers are introduced in
the computation using the [rational/1][@ref rational_1],
[rationalize/1][@ref rationalize_1] or the [rdiv/2][@ref rdiv_2]
[rationalize/1][@ref rationalize/1] or the [rdiv/2][@ref rdiv/2]
(rational division) function.
</li>
@ -69,7 +67,7 @@ the computation using the [rational/1][@ref rational_1],
Floating point numbers are represented using the C-type double. On
most today platforms these are 64-bit IEEE-754 floating point
numbers. YAP now includes the built-in predicates [isinf/1][@ref isinf_1] and to [isnan/1][@ref isnan_1] tests.
numbers. YAP now includes the built-in predicates [isinf/1][@ref isinf/1] and to [isnan/1][@ref isnan/1] tests.
</li>
</ul>
@ -97,8 +95,8 @@ exceptions:
@exception "evaluation_error(overflow( V ), Call)" result is arithmetic overflow
@secreflist
@refitem is_2
@refitem isnan_1
@refitem is/2
@refitem isnan/1
@endsecreflist

View File

@ -57,6 +57,9 @@
/* Define to 1 if you have the `acosh' function. */
#undef HAVE_ACOSH
/* Define to 1 if you have the `add_history' function. */
#undef HAVE_ADD_HISTORY
/* Define to 1 if you have the `alarm' function. */
#undef HAVE_ALARM
@ -171,6 +174,22 @@
/* Define to 1 if you have the <cudd/util.h> header file. */
#undef HAVE_CUDD_UTIL_H
/* Define to 1 if you have the declaration of `rl_catch_signals ', and to 0 if
you don't. */
#undef HAVE_DECL_RL_CATCH_SIGNALS_
/* Define to 1 if you have the declaration of `rl_done ', and to 0 if you
don't. */
#undef HAVE_DECL_RL_DONE_
/* Define to 1 if you have the declaration of `rl_event_hook', and to 0 if you
don't. */
#undef HAVE_DECL_RL_EVENT_HOOK
/* Define to 1 if you have the declaration of `rl_readline_state', and to 0 if
you don't. */
#undef HAVE_DECL_RL_READLINE_STATE
/* Define to 1 if you have the <direct.h> header file. */
#undef HAVE_DIRECT_H
@ -574,11 +593,8 @@
/* Define to 1 if you have the <Rinterface.h> header file. */
#undef HAVE_RINTERFACE_H
/* Defined if you can turn off readline's signal handling. */
#undef HAVE_RL_CATCH_SIGNAL
/* Define to 1 if you have the `rl_cleanup_after_signal' function. */
#undef HAVE_RL_CLEANUP_AFTER_SIGNAL
/* Define to 1 if you have the `rl_begin_undo_group' function. */
#undef HAVE_RL_BEGIN_UNDO_GROUP
/* Define to 1 if you have the `rl_clear_pending_input' function. */
#undef HAVE_RL_CLEAR_PENDING_INPUT
@ -589,8 +605,8 @@
/* Define to 1 if you have the `rl_completion_matches' function. */
#undef HAVE_RL_COMPLETION_MATCHES
/* Define to 1 if you have the `rl_event_hook' function. */
#undef HAVE_RL_EVENT_HOOK
/* Define to 1 if you have the `rl_discard_argument' function. */
#undef HAVE_RL_DISCARD_ARGUMENT
/* Define to 1 if you have the `rl_filename_completion_function' function. */
#undef HAVE_RL_FILENAME_COMPLETION_FUNCTION
@ -604,12 +620,12 @@
/* Define to 1 if you have the `rl_insert_close' function. */
#undef HAVE_RL_INSERT_CLOSE
/* Define to 1 if you have the `rl_reset_after_signal' function. */
#undef HAVE_RL_RESET_AFTER_SIGNAL
/* Define to 1 if you have the `rl_set_prompt' function. */
#undef HAVE_RL_SET_PROMPT
/* Define to 1 if you have the `rl_state_initialized' function. */
#undef HAVE_RL_STATE_INITIALIZED
/* Define to 1 if you have the `sbrk' function. */
#undef HAVE_SBRK

View File

@ -1,10 +1,9 @@
/**
@defgroup CHR CHR: Constraint Handling Rules
@ingroup SWILibrary
@{
This chapter is written by Tom Schrijvers, K.U. Leuven for the hProlog
system. Adjusted by Jan Wielemaker to fit the SWI-Prolog documentation
infrastructure and remove hProlog specific references.
@ -19,9 +18,7 @@ The main reference for SWI-Prolog's CHR system is:
+ T. Schrijvers, and B. Demoen, <em>The K.U.Leuven CHR System: Implementation and Application</em>, First Workshop on Constraint Handling Rules: Selected
Contributions (Fruwirth, T. and Meister, M., eds.), pp. 1--5, 2004.
@defgroup CHR_Introduction Introduction
@ingroup CHR
# Introduction
Constraint Handling Rules (CHR) is a committed-choice bottom-up language
embedded in Prolog. It is designed for writing constraint solvers and is
@ -38,16 +35,12 @@ of CHR in general and mainly focus on elements specific to this
implementation. For a more thorough review of CHR we refer the reader to
[Freuhwirth:98]. More background on CHR can be found at the CHR web site.
@defgroup CHR_Syntax_and_Semantics Syntax and Semantics
@ingroup CHR
@{
### Syntax and Semantics
We present informally the syntax and semantics of CHR.
@defgroup CHR_Syntax CHR Syntax
@ingroup CHR_Syntax_and_Semantics
@{
#### CHR Syntax
The syntax of CHR rules in hProlog is the following:
@ -98,12 +91,7 @@ Additional syntax-related terminology:
the arrow (either `<=>` or `==>`)
@}
@defgroup Semantics Semantics
@ingroup CHR_Syntax_and_Semantics
@{
#### Semantics Semantics
In this subsection the operational semantics of CHR in Prolog are presented
informally. They do not differ essentially from other CHR systems.
@ -137,13 +125,7 @@ or another variable involved in one or more constraints. In that case the
constraint is triggered, i.e. it becomes an active constraint and all
the rules are tried.
@}
@defgroup CHR_Rule_Types Rules
@ingroup CHR
@{
### Rules
There are three different kinds of rules, each with their specific semantics:
@ -168,18 +150,12 @@ constraints are not called in the body.
@defgroup CHR_Rule_Names Rule Names
@ingroup CHR_Rule_Types
#### Rule Names
Naming a rule is optional and has no semantical meaning. It only functions
as documentation for the programmer.
@}
@defgroup CHRPragmas Pragmas
@ingroup CHR
@{
### Pragmas
The semantics of the pragmas are:
@ -190,13 +166,7 @@ passive constraint in that rule.
Additional pragmas may be released in the future.
@}
@defgroup CHR_Options Options
@ingroup CHR
@{
### CHR_Options Options
It is possible to specify options that apply to all the CHR rules in the module.
Options are specified with the `option/2` declaration:
@ -297,11 +267,7 @@ for backward compatibility. The new syntax is described below.
@}
@defgroup CHR_in_YAP_Programs CHR in Prolog Programs
@ingroup CHR
@{
### CHR in Prolog Programs
The CHR constraints defined in a particulary chr file are
@ -310,9 +276,7 @@ never load different chr files with the same CHR module name.
@defgroup Constraint_declaration Constraint Declarations
@ingroup CHR_in_YAP_Programs
@{
#### Constraint Declarations
Every constraint used in CHR rules has to be declared.
@ -334,8 +298,7 @@ The new style is as follows:
@defgroup Compilation Compilation
@ingroup CHR_in_YAP_Programs
#### Compilation
The
SWI-Prolog CHR compiler exploits term_expansion/2 rules to translate
@ -367,10 +330,7 @@ leak into modules where they might cause conflicts.
@defgroup CHR_Debugging CHR Debugging
@ingroup CHR_in_YAP_Programs
@{
#### CHR Debugging
The CHR debugging facilities are currently rather limited. Only tracing
is currently available. To use the CHR debugging facilities for a CHR
@ -379,9 +339,7 @@ controlled by the CHR option debug, whose default is derived
from the SWI-Prolog flag `generate_debug_info`. Therefore debug
info is provided unless the `-nodebug` is used.
@defgroup Ports Ports
@ingroup CHR_Debugging
#### Ports
For CHR constraints the four standard ports are defined:
@ -416,9 +374,7 @@ An active constraints commits to a rule with possibly
some passive constraints. The apply port is entered
just after committing to the rule.
@defgroup Tracing Tracing
@ingroup CHR_Debugging
#### Tracing
Tracing is enabled with the chr_trace/0 predicate
and disabled with the chr_notrace/0 predicate.
@ -462,12 +418,7 @@ Insert failure in execution.
Print the above available debug options.
@defgroup CHR_Debugging_Predicates CHR Debugging Predicates
@ingroup CHR_Debugging
#### CHR Debugging Predicates
The chr module contains several predicates that allow
@ -478,15 +429,7 @@ Activate the CHR tracer. By default the CHR tracer is activated and
deactivated automatically by the Prolog predicates trace/0 and
notrace/0.
@}
@defgroup CHR_Examples Examples
@ingroup CHR
@{
### CHR_Examples Examples
Here are two example constraint solvers written in CHR.
@ -534,14 +477,7 @@ intersection([_|T],L2,L3) :-
@}
@defgroup CHR_Compatibility Compatibility with SICStus CHR
@ingroup CHR
@{
### Compatibility with SICStus CHR
There are small differences between CHR in SWI-Prolog and newer
@ -566,19 +502,7 @@ SICStus uses a two-step compiler, where chr files are
first translated into pl files. For SWI-Prolog CHR
rules may be defined in a file with any extension.
@}
@}
@defgroup CHR_Guidelines Guidelines
@ingroup CHR
@{
### Guidelines
In this section we cover several guidelines on how to use CHR to write
constraint solvers and how to do so efficiently.
@ -603,15 +527,4 @@ Provide mode and type declarations to get more efficient program execution.
Make sure to disable debug (`-nodebug`) and enable optimization
(`-O`).
@}
@}
@}
@}
@}
@}
*/

View File

@ -1,5 +1,5 @@
/** @defgroup clpr Constraint Logic Programming over Rationals and Reals
@defgroup clpr Constraint Logic Programming over Rationals and Reals
@ingroup SWILibrary
@{
@ -74,6 +74,7 @@ result in an exception.
| max(<Expression>, <Expression>) \ maximum \
~~~~~
@}
@defgroup CLPR_Unification Use of unification
@ingroup clpr
@ -100,7 +101,7 @@ X = 5.0
~~~~~
@}
@defgroup CLPR_NonhYlinear_Constraints Non-Linear Constraints
@ingroup clpr
@ -133,3 +134,5 @@ X = tan(Y)
@}
@}

View File

@ -58,7 +58,7 @@ PROJECT_LOGO = misc/icons/yap_96x96x32.png
# entered, it will be relative to the location where doxygen was started. If
# left blank the current directory will be used.
OUTPUT_DIRECTORY = /scratch/vitor/doxout
OUTPUT_DIRECTORY = /Users/vsc/Yap/doxout
# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
# directories (in 2 levels) under the output directory of each output format and
@ -788,10 +788,6 @@ WARN_LOGFILE =
INPUT = foreigns.yap \
docs/yap.md \
docs/chr.md \
docs/threads.md \
docs/syntax.md \
docs/clpqr.md \
pl \
C \
H \

View File

@ -1,179 +0,0 @@
@defgroup Threads Threads
@ingroup YAPExtensions
@{
YAP implements a SWI-Prolog compatible multithreading
library. Like in SWI-Prolog, Prolog threads have their own stacks and
only share the Prolog <em>heap</em>: predicates, records, flags and other
global non-backtrackable data. The package is based on the POSIX thread
standard (Butenhof:1997:PPT) used on most popular systems except
for MS-Windows.
@defgroup Creating_and_Destroying_Prolog_Threads Creating and Destroying Prolog Threads
@ingroup Threads
@pred thread_create(: _Goal_, - _Id_, + _Options_)
Create a new Prolog thread (and underlying C-thread) and start it
by executing _Goal_. If the thread is created successfully, the
thread-identifier of the created thread is unified to _Id_.
_Options_ is a list of options. Currently defined options are:
+ stack
Set the limit in K-Bytes to which the Prolog stacks of
this thread may grow. If omitted, the limit of the calling thread is
used. See also the commandline `-S` option.
+ trail
Set the limit in K-Bytes to which the trail stack of this thread may
grow. If omitted, the limit of the calling thread is used. See also the
commandline option `-T`.
+ alias
Associate an alias-name with the thread. This named may be used to
refer to the thread and remains valid until the thread is joined
(see thread_join/2).
+ at_exit
Define an exit hook for the thread. This hook is called when the thread
terminates, no matter its exit status.
+ detached
If `false` (default), the thread can be waited for using
thread_join/2. thread_join/2 must be called on this thread
to reclaim the all resources associated to the thread. If `true`,
the system will reclaim all associated resources automatically after the
thread finishes. Please note that thread identifiers are freed for reuse
after a detached thread finishes or a normal thread has been joined.
See also thread_join/2 and thread_detach/1.
The _Goal_ argument is <em>copied</em> to the new Prolog engine.
This implies further instantiation of this term in either thread does
not have consequences for the other thread: Prolog threads do not share
data from their stacks.
@defgroup Monitoring_Threads Monitoring Threads
@ingroup Threads
Normal multi-threaded applications should not need these the predicates
from this section because almost any usage of these predicates is
unsafe. For example checking the existence of a thread before signalling
it is of no use as it may vanish between the two calls. Catching
exceptions using catch/3 is the only safe way to deal with
thread-existence errors.
These predicates are provided for diagnosis and monitoring tasks.
@defgroup Thread_Communication Thread communication
@ingroup Threads
Prolog threads can exchange data using dynamic predicates, database
records, and other globally shared data. These provide no suitable means
to wait for data or a condition as they can only be checked in an
expensive polling loop. <em>Message queues</em> provide a means for
threads to wait for data or conditions without using the CPU.
Each thread has a message-queue attached to it that is identified
by the thread. Additional queues are created using
`message_queue_create/2`.
@pred thread_send_message(+ _Term_)
Places _Term_ in the message-queue of the thread running the goal.
Any term can be placed in a message queue, but note that the term is
copied to the receiving thread and variable-bindings are thus lost.
This call returns immediately.
@defgroup Signalling_Threads Signalling Threads
@ingroup Threadas
These predicates provide a mechanism to make another thread execute some
goal as an <em>interrupt</em>. Signalling threads is safe as these
interrupts are only checked at safe points in the virtual machine.
Nevertheless, signalling in multi-threaded environments should be
handled with care as the receiving thread may hold a <em>mutex</em>
(see with_mutex/2). Signalling probably only makes sense to start
debugging threads and to cancel no-longer-needed threads with throw/1,
where the receiving thread should be designed carefully do handle
exceptions at any point.
@defgroup Threads_and_Dynamic_Predicates Threads and Dynamic Predicates
@ingroup Threads
Besides queues threads can share and exchange data using dynamic
predicates. The multi-threaded version knows about two types of
dynamic predicates. By default, a predicate declared <em>dynamic</em>
(see dynamic/1) is shared by all threads. Each thread may
assert, retract and run the dynamic predicate. Synchronisation inside
Prolog guarantees the consistency of the predicate. Updates are
<em>logical</em>: visible clauses are not affected by assert/retract
after a query started on the predicate. In many cases primitive from
thread synchronisation should be used to ensure application invariants on
the predicate are maintained.
Besides shared predicates, dynamic predicates can be declared with the
thread_local/1 directive. Such predicates share their
attributes, but the clause-list is different in each thread.
@defgroup Thread_Synchronisation Thread Synchronisation
@ingroup Threads
All
internal Prolog operations are thread-safe. This implies two Prolog
threads can operate on the same dynamic predicate without corrupting the
consistency of the predicate. This section deals with user-level
<em>mutexes</em> (called <em>monitors</em> in ADA or
<em>critical-sections</em> by Microsoft). A mutex is a
<em>MUT</em>ual <em>EX</em>clusive device, which implies at most one thread
can <em>hold</em> a mutex.
Mutexes are used to realise related updates to the Prolog database.
With `related', we refer to the situation where a `transaction' implies
two or more changes to the Prolog database. For example, we have a
predicate `address/2`, representing the address of a person and we want
to change the address by retracting the old and asserting the new
address. Between these two operations the database is invalid: this
person has either no address or two addresses, depending on the
assert/retract order.
Here is how to realise a correct update:
~~~~~
:- initialization
mutex_create(addressbook).
change_address(Id, Address) :-
mutex_lock(addressbook),
retractall(address(Id, _)),
asserta(address(Id, Address)),
mutex_unlock(addressbook).
~~~~~
@}

View File

@ -3,20 +3,13 @@ This file documents the YAP Prolog System version 6.3.4, a high-performance Prol
+ @ref DownloadInstall
+ @ref Run describes how to invoke YAP
+ @ref Run
+ @ref YAPLoading presents the main predicates and
directives available to load files and to control the Prolog
environment.
+ @ref YAPLoading
+ @ref YAPConsulting
+ @ref YAPModules introduces the YAP module system and meta-predicates.
+ @ref YAPBuiltins
+ @ref YAPBuiltins describes predicates providing core YAP
functionality:
+ @ref YAPExtensions presents several extensions over standard
Prolog
+ @ref YAPExtensions
+ @ref YAPProgramming
@ -782,9 +775,11 @@ will be used:
+ @ref arithmetic
+ @ref YAPChars
+ @ref YAP_Terms
+ @ref InputOutput.
+ @ref YAP_InputOutput
+ @ref YAPOS
@ -816,7 +811,7 @@ being designed to work with the swig (@url(www.swig.org}) interface compiler.
@defgroup YAPExtensions Extensions to core Prolog.
+ @ref Rational_Trees
+@ref Rational_Trees
+ @ref CohYroutining
@ -901,6 +896,8 @@ being designed to work with the swig (@url(www.swig.org}) interface compiler.
@defgroup YAPProgramming Programming in YAP
@page Programming Programming in YAP
+ @ref Syntax
+ @ref Indexing
@ -909,18 +906,52 @@ being designed to work with the swig (@url(www.swig.org}) interface compiler.
@defgroup SWILibrary SWI-Prolog Libraries and Packages
+ @ref Read_Utilities Read Utilities
+ @ref shlib SWI-Prolog's shlib library
@page SWICode The SWI-Prolog Libraries and Packages
+ @ref Lambda Lambda Expressions
+ @ref aggregates
+ @ref date
+ @ref debug
+ @ref persistence
+ @ref pio
+ @ref predicate_options
+ @ref prolog_clause
+ @ref prolog_colour
+ @ref prolog_main
+ @ref prolog_source
+ @ref quasi_quotations
+ @ref swi_option
+ @ref read_util
+ @ref record
+ @ref settings
+ @ref shlib
+ @ref url
+ @ref Lambda
+ @ref archive
+ @ref chr
+ @ref CHR
+ @ref clpr
+ @ref http
+ @ref zlib
@defgroup YAPPackages The YAP packages
@ -935,7 +966,16 @@ being designed to work with the swig (@url(www.swig.org}) interface compiler.
+ @ref MYDDAS
@defgroup http The SWI The SWI http packages
+ @ref PFL
+ @ref ProbLog1
+ @ref YAPRaptor
+ @ref YAP-LBFGS
@defgroup http The SWI http packages
@ingroup SWILibrary
Tthe package HTTP is a series of libraries developed by Jan Wielmaker
and the SWI-Prolog community for accessing and serving data on the
@ -945,9 +985,6 @@ data-representation primitives, and more.
The port to YAP focussed on the client-side support. The server
package has not been as widely tested.
\toc
@page Compatibility Compatibility with Other Prolog systems
YAP has been designed to be as compatible as possible with

View File

@ -3,9 +3,8 @@
@{
This library provides a SWI-compatible set of utilities for applying a
predicate to all elements of a list. The library just forwards
definitions from the `maplist` library.
predicate to all elements of a list. In practice, the library just forwards
definitions from the @ref maplist library library.
*/

View File

@ -22,7 +22,8 @@
@ingroup Attributed_Variables
@{
Old style attribute declarations are activated through loading the library <tt>atts</tt> . The command
Old style attribute declarations are activated through loading the
library <tt>atts</tt> . The command
~~~~~
| ?- use_module(library(atts)).

View File

@ -5,16 +5,17 @@
/**
@defgroup system
@file swi.yap
@page SWIhYProlog_Emulation SWI-Prolog Emulation
@defgroup System SWI Dialect SupportXS
This library provides a number of SWI-Prolog builtins that are not by
default in YAP. This support is loaded with the
`expects_dialect(swi)` command.
~~~~~
expects_dialect(swi)
~~~~~
command.
@{
*/
@ -26,14 +27,6 @@ Unify the last modification time of _File_ with
elapsed since Jan 1, 1970.
*/
/** @pred chdir(+ _Dir_)
Compatibility predicate. New code should use working_directory/2.
*/
/** @pred concat_atom(+ _List_,- _Atom_)
@ -46,29 +39,7 @@ allowing for variables in the list.
*/
/** @pred concat_atom(? _List_,+ _Separator_,? _Atom_)
Creates an atom just like concat_atom/2, but inserts _Separator_
between each pair of atoms. For example:
~~~~~
?- concat_atom([gnu, gnat], ', ', A).
A = 'gnu, gnat'
~~~~~
(Unimplemented) This predicate can also be used to split atoms by
instantiating _Separator_ and _Atom_:
~~~~~
?- concat_atom(L, -, 'gnu-gnat').
L = [gnu, gnat]
~~~~~
*/
:- module(system, [concat_atom/2,
concat_atom/3,
read_clause/1,
@ -215,7 +186,29 @@ user:file_search_path(foreign, swi(ArchLib)) :-
atom_concat('lib/', Arch, ArchLib).
user:file_search_path(foreign, swi(lib)).
/** @pred concat_atom(? _List_,+ _Separator_,? _Atom_)
Creates an atom just like concat_atom/2, but inserts _Separator_
between each pair of atoms. For example:
~~~~~
?- concat_atom([gnu, gnat], ', ', A).
A = 'gnu, gnat'
~~~~~
(Unimplemented) This predicate can also be used to split atoms by
instantiating _Separator_ and _Atom_:
~~~~~
?- concat_atom(L, -, 'gnu-gnat').
L = [gnu, gnat]
~~~~~
*/
concat_atom([A|List], Separator, New) :- var(List), !,
atom_codes(Separator,[C]),
atom_codes(New, NewChars),
@ -254,6 +247,10 @@ cvt_bindings([[Name|Value]|L],[AName=Value|Bindings]) :-
atom_codes(AName, Name),
cvt_bindings(L,Bindings).
/** @pred chdir(+ _Dir_)
Compatibility predicate. New code should use working_directory/2.
*/
chdir(X) :- cd(X).
%% convert_time(+Stamp, -String)
@ -342,4 +339,6 @@ required_predicate(Na/Ar, M) :-
autoloader:find_predicate(G, _)
).
/**
@}
*/

View File

@ -22,8 +22,10 @@
This package provides a set of useful predicates to manipulate
sequences of characters codes, usually first read in as a line. It is
available by loading the library `library(lineutils)`.
available by loading the
~~~~
:- use_module(library(lineutils)).
~~~~
*/
@ -191,7 +193,19 @@ copy_line(StreamInp, StreamOut) :-
For every line _LineIn_ in stream _StreamInp_, execute
`call(Goal,LineIn,LineOut)`, and output _LineOut_ to
stream _StreamOut_.
stream _StreamOut_. If `call(Goal,LineIn,LineOut)` fails,
nothing will be output but execution continues with the next
line. As an example, consider a procedure to select the second and
fifth field of a CSV table :
~~~~~{.prolog}
select(Sep, In, Out) :-
fields(In, Sep, [_,F2,_,_,F5|_]),
fields(Out,Sep, [F2,F5]).
select :-
filter(",",
~~~~~
*/
filter(StreamInp, StreamOut, Command) :-
repeat,
@ -206,7 +220,7 @@ filter(StreamInp, StreamOut, Command) :-
fail
).
/** @pred process(+ _StreamInp_, + _Goal_)
/** @pred process(+ _StreamInp_, + _Goal_) is meta
For every line _LineIn_ in stream _StreamInp_, call
`call(Goal,LineIn)`.
@ -224,7 +238,7 @@ process(StreamInp, Command) :-
).
/** @pred file_filter(+ _FileIn_, + _FileOut_, + _Goal_)
/** @pred file_filter(+ _FileIn_, + _FileOut_, + _Goal_) is meta
For every line _LineIn_ in file _FileIn_, execute
`call(Goal,LineIn,LineOut)`, and output _LineOut_ to file

View File

@ -1399,7 +1399,7 @@ atom_pred(N) -->
!,
decl(1,N).
atom_pred(0) -->
blank, !.
blanks, !.
int(I0, I) -->
[A],
@ -1419,9 +1419,9 @@ decl(I0, I) -->
[_],
decl( I0, I).
blank --> " ", !, blank.
blank --> "\t", !, blank.
blank --> [].
blanks --> " ", !, blanks.
blanks --> "\t", !, blanks.
blanks --> [].
atom([A|As]) -->
[A],
@ -1440,8 +1440,7 @@ atom2([A|As]) -->
atom2([]) --> [].
add_comments :-
open( commands, write, S ),
findall(File, do_comment( File, Line, C, Type, Dup), Fs0 ),
findall(File, do_comment( File, Line, C, Type, Dup), Fs0 ),
(
sort(Fs0, Fs),
member( File, Fs ),

View File

@ -1,3 +1,5 @@
/* Part of SWI-Prolog
Author: Jan Wielemaker
@ -25,6 +27,13 @@
#include <ctype.h>
#include "pl-ctype.h"
//! @defgroup YAPChars Character Classification and Manipulation
// @ingroup YAPBuiltins
//
// This module defines routines to manipulate individual characters.
//
// @{
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
This module defines:
@ -436,9 +445,23 @@ error:
/** @pred char_type(? _Char_, ? _Type_)
Like code_type/2, tests or generates alternative _Types_ or
_Chars_. The character-types are inspired by the standard `C`
`<ctype.h>` primitives.
*/
/// @memberof code_type/2
static
PRED_IMPL("char_type", 2, char_type, PL_FA_NONDETERMINISTIC)
/** @pred char_type(? _Char_, ? _Type_)
{ return do_char_type(A1, A2, PL__ctx, PL_CHAR);
}
/** @pred code_type(? _Char_, ? _Type_)
Tests or generates alternative _Types_ or _Chars_. The
@ -536,10 +559,7 @@ atom_chars/2 and atom_codes/2.
*/
{ return do_char_type(A1, A2, PL__ctx, PL_CHAR);
}
/// @memberof code_type/2
static
PRED_IMPL("code_type", 2, code_type, PL_FA_NONDETERMINISTIC)
{ return do_char_type(A1, A2, PL__ctx, PL_CODE);
@ -698,12 +718,31 @@ modify_case_atom(term_t in, term_t out, int down)
}
/** @pred downcase_atom(+ _Word_, - _LowerCaseWord_)
If the first argument is bound to an atom _Word_, the
second argument shoud unify with an atom such that all alphabetic cdes
are lower case, _LowerCaseWord_. Non-alphabetic characers are
preserved.
*/
/// @memberof downcase_atom/2
static
PRED_IMPL("downcase_atom", 2, downcase_atom, 0)
{ return modify_case_atom(A1, A2, TRUE);
}
/** @pred upcase_atom(+ _Word_, - _UpCaseWord_)
If the first argument is bound to an atom _Word_, the
second argument shoud unify with an atom such that all alphabetic cdes
are up case, _UpCaseWord_. Non-alphabetic characers are
preserved.
*/
/// @memberof upcase_atom/2
static
PRED_IMPL("upcase_atom", 2, upcase_atom, 0)
{ return modify_case_atom(A1, A2, FALSE);
@ -748,6 +787,24 @@ write_normalize_space(IOSTREAM *out, term_t in)
}
/** @pred normalize_space(- _Out_, + _In_)
Remove white space at the beginning an end of the word _In_, and replace
sequences of white space in the middle of _In_ by a single white
space.
~~~
?- normalize_space(atom(X), ' the white fox jumped ').
X = 'the white fox jumped'.
?- normalize_space(string(X), ' over the lazy dog ').
X = "over the lazy dog".
~~~
Notice that the first argument is bound to a stream descriptor in the
style of format/3.
*/
/// @memberof normalize_space/2
static
PRED_IMPL("normalize_space", 2, normalize_space, 0)
{ redir_context ctx;
@ -764,6 +821,9 @@ PRED_IMPL("normalize_space", 2, normalize_space, 0)
}
/// @addtogroup SetLocale
// @{
//
/*******************************
* LOCALE *
@ -819,7 +879,13 @@ static lccat lccats[] =
{ 0, NULL }
};
/// @}
/** @pred setlocale( + _In_, - _Old_, -_New_)
*/
/// @memberof setlocale/3
static
PRED_IMPL("setlocale", 3, setlocale, 0)
{ PRED_LD
@ -871,7 +937,7 @@ PRED_IMPL("setlocale", 3, setlocale, 0)
}
#endif
/// @}
/*******************************
* PUBLISH PREDICATES *
@ -994,3 +1060,5 @@ initCharTypes(void)
{ initEncoding();
}
/// @}

View File

@ -22,13 +22,9 @@
*/
/** @defgroup Streams_and_Files Handling Streams and Files
@ingroup YAPBuiltins
/** @addtogroup YAP_inputOutput
@{
*/
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -124,11 +120,16 @@ standardStreamIndexFromStream(IOSTREAM *s)
return -1;
}
//! @}
/*******************************
* BOOKKEEPING *
*******************************/
/**
* @defgroup YAP_StreamM Stream Manipulation
* @ingroup YAP_InputOutput
* @{
*/
static void aliasStream(IOSTREAM *s, atom_t alias);
static void unaliasStream(IOSTREAM *s, atom_t name);
@ -898,8 +899,14 @@ getBinaryInputStream__LD(term_t t, IOSTREAM **stream ARG_LD)
}
/** stream_pairs(+Pair, -Read, -Write)
stream_pairs(-Pair, +Read, +Write)
/** stream_pairs(-Pair, +Read, +Write)
* stream_pairs(+Pair, -Read, -Write)
*
* This SWI Built-in can be used in two ways: if the second argument is an input stream
* and the third sn output stresm, Prolog createes a new _Pair_. A stream pair can be
* used in any operation, with the Prolog chosing the appropriate stream to the operation.
*
* If _Pair_ is bound, the predicate can be used to access the two streams in the pair.
*/
static
@ -1434,7 +1441,40 @@ discardOutputRedirect(redir_context *ctx)
}
}
/** @pred with_output_to(+ _Ouput_,: _Goal_)
This SWI-Prolog predicate runs _Goal_ as once/1, while characters written to the current
output are sent to _Output_.
This predicate supports creating
difference-lists from character data efficiently. The example below
defines the DCG rule `term/3` to insert a term in the output:
~~~~~
term(Term, In, Tail) :-
with_output_to(codes(In, Tail), write(Term)).
?- phrase(term(hello), X).
X = [104, 101, 108, 108, 111]
~~~~~
+ A Stream handle or alias
Temporary switch current output to the given stream. Redirection using with_output_to/2 guarantees the original output is restored, also if Goal fails or raises an exception. See also call_cleanup/2.
+ atom(- _Atom_)
Create an atom from the emitted characters. Please note that there is a cost in creating atoms.
+ string(- _String_)
Create a string-object.
+ codes(- _Codes_)
Create a list of character codes from the emitted characters, similar to atom_codes/2.
+ codes(- _Codes_, - _Tail_)
Create a list of character codes as a difference-list.
+ chars(- _Chars_)
Create a list of one-character-atoms codes from the emitted characters, similar to atom_chars/2.
+ chars(- _Chars_, - _Tail_)
Create a list of one-character-atoms as a difference-list.
*/
static
PRED_IMPL("with_output_to", 2, with_output_to, PL_FA_TRANSPARENT)
{ redir_context outctx;
@ -1638,7 +1678,6 @@ openProtocol(term_t f, int appnd)
return FALSE;
}
static int
noprotocol(void)
{ GET_LD
@ -1664,12 +1703,20 @@ noprotocol(void)
return TRUE;
}
/** @pred noprotocol
Stop protocolling user interaction.
*/
static
PRED_IMPL("noprotocol", 0, noprotocol, 0)
{ return noprotocol();
}
//! @}
// @{
//
/*******************************
* STREAM ATTRIBUTES *
@ -1986,7 +2033,12 @@ static const set_stream_info ss_info[] =
SS_INFO((atom_t)0, 0)
};
/** @pred set_stream(+ _S_, + _Prop_) is iso
Set a property _Prop_ for a stream _S_.
*/
static
PRED_IMPL("set_stream", 2, set_stream, 0)
{ PRED_LD
@ -2054,6 +2106,11 @@ extern int ftruncate(int fileno, int64_t length);
#define HAVE_FTRUNCATE
#endif
/** @pred set_end_of_stream(+ _S_ ) is iso
Set stream position to be the end of stream.
*/
static
PRED_IMPL("set_end_of_stream", 1, set_end_of_stream, 0)
{ IOSTREAM *s;
@ -2129,6 +2186,14 @@ toldString(void)
#ifndef HAVE_SELECT
/** @pred wait_for_input(+ _Streams_, -_Available_, - _Timeout_) is iso
*
* Implement the select operation over a set of stream _Streams, with
* _Available_ unified with all ready streams. The operation can last at most
* _Timeout_ seconds.
*
*
*/
static
PRED_IMPL("wait_for_input", 3, wait_for_input, 0)
{ return notImplemented("wait_for_input", 3);
@ -2369,7 +2434,12 @@ skip_cr(IOSTREAM *s)
return FALSE;
}
/** @pred read_pending_input( _Stream_ , _Codes_, _End_ )
*
* Reads all characters or bytes currently available from _Stream_ to the difference
* list _Codes_ - _End_. This SWI predicate allows cleaning up input from unbuffered
* streams.
*/
static
PRED_IMPL("read_pending_input", 3, read_pending_input, 0)
{ PRED_LD
@ -2595,6 +2665,12 @@ PRED_IMPL("read_pending_input", 3, read_pending_input, 0)
return FALSE;
}
// @}
//! @defgroup YAPCharsIO Character Input/Output
// @ingroup YAP_InputOutput
// @{
//
static foreign_t
put_byte(term_t stream, term_t byte ARG_LD)
@ -2615,8 +2691,6 @@ put_byte(term_t stream, term_t byte ARG_LD)
/** @pred put_byte(+ _S_,+ _N_) is iso
As `put_byte(N)`, but to binary stream _S_.
*/
static
PRED_IMPL("put_byte", 2, put_byte2, 0)
@ -2631,8 +2705,6 @@ PRED_IMPL("put_byte", 2, put_byte2, 0)
Outputs to the current output stream the character whose code is
_N_. The current output stream must be a binary stream.
*/
static
PRED_IMPL("put_byte", 1, put_byte1, 0)
@ -2663,6 +2735,12 @@ put_code(term_t stream, term_t chr ARG_LD)
As `put_code(N)`, but to text stream _S_.
*/
/** @pred put_char(+ _S_,+ _A_) is iso
As `put_char(A)`, but to text stream _S_.
*/
static
PRED_IMPL("put_code", 2, put_code2, 0)
@ -2672,6 +2750,15 @@ PRED_IMPL("put_code", 2, put_code2, 0)
}
/** @pred put_char(+ _N_) is iso
Outputs to the current output stream the character who is used to build
the representation of atom `A`. The current output stream must be a
text stream.
*/
/** @pred put_code(+ _N_) is iso
@ -2830,7 +2917,13 @@ PRED_IMPL("skip", 2, skip2, 0)
return skip(A1, A2 PASS_LD);
}
/** @pred get_single_char( +_Stream_ )
*
* SWI-Prolog predicate that reads the first charcter from `user_input`.
* This operation is unbuffered,
* and it does not have to wait for n newline. Spaces and tabulation characters are
* ignored.
*/
static
PRED_IMPL("get_single_char", 1, get_single_char, 0)
{ GET_LD
@ -2909,7 +3002,12 @@ PRED_IMPL("get_byte", 1, get_byte1, 0)
return get_byte2(0, A1 PASS_LD);
}
/** @pred get0(+ _S_,- _C_)
The same as `get0(C)`, but from stream _S_.
*/
static foreign_t
get_code2(term_t in, term_t chr ARG_LD)
{ IOSTREAM *s;
@ -3014,6 +3112,11 @@ PRED_IMPL("get_char", 1, get_char1, 0)
}
/** @pred ttyflush
Flush the current output stream.
*/
static
PRED_IMPL("ttyflush", 0, ttyflush, 0)
{ PRED_LD
@ -3029,18 +3132,34 @@ PRED_IMPL("ttyflush", 0, ttyflush, 0)
}
/** @pred protocol( _File_ )
*
* Start protocolling user interaction to _File_, closing any previous protocolling
* file and truncating it.
*
*/
static
PRED_IMPL("protocol", 1, protocol, 0)
{ return openProtocol(A1, FALSE);
}
/** @pred protocola( _File_ )
*
* Start protocolling user interaction to _File_, closing any previous protocolling
* file and then appending it.
*
*/
static
PRED_IMPL("protocola", 1, protocola, 0)
{ return openProtocol(A1, TRUE);
}
/** @pred protocolling( -_File_ )
*
* Report whether we are protocolling and to which _File_.
*
*/
static
PRED_IMPL("protocolling", 1, protocolling, 0)
{ PRED_LD
@ -3061,10 +3180,7 @@ PRED_IMPL("protocolling", 1, protocolling, 0)
/** @pred prompt(- _A_,+ _B_)
Changes YAP input prompt from _A_ to _B_.
*/
static
PRED_IMPL("prompt", 2, prompt, 0)
@ -3086,7 +3202,10 @@ PRED_IMPL("prompt", 2, prompt, 0)
return FALSE;
}
/** @pred prompt1(+ _Prompt_)
Set the YAP input prompt for the next line.
*/
void
prompt1(atom_t prompt)
{ GET_LD
@ -3514,8 +3633,6 @@ Opens the file with name _F_ in mode _M_ (`read`, `write` or
`append`), returning _S_ unified with the stream name, and following
these options:
+ `type(+ _T_)` is iso
Specify whether the stream is a `text` stream (default), or a
@ -3618,6 +3735,11 @@ PRED_IMPL("open", 3, open3, PL_FA_ISO)
return FALSE;
}
/** @defgroup DEC10_IO DEC-10/C-Prolog Compatible File Handling
*
* @ingroup YAP_InputOutput
* @{
*/
/*******************************
* EDINBURGH I/O *
*******************************/
@ -3730,9 +3852,6 @@ PRED_IMPL("see", 1, see, 0)
Closes the current input stream (see 6.7.).
*/
static
PRED_IMPL("seen", 0, seen, 0)
@ -3872,6 +3991,16 @@ PRED_IMPL("told", 0, told, 0)
return symbol_no_stream(ATOM_current_output);
}
/**
* @}
*/
//! @defgroup YAPStream Opening and Closing Streams
// @ingroup YAP_InputOutput
// @{
//
/*******************************
* NULL-STREAM *
*******************************/
@ -4426,8 +4555,6 @@ typedef struct
} prop_enum;
static
PRED_IMPL("stream_property", 2, stream_property,
/** @pred stream_property(? _Stream_,? _Prop_) is iso
@ -4508,6 +4635,8 @@ Unify _LineNumber_ with the line number for the current stream.
*/
static
PRED_IMPL("stream_property", 2, stream_property,
PL_FA_ISO|PL_FA_NONDETERMINISTIC)
{ PRED_LD
IOSTREAM *s;
@ -4714,15 +4843,13 @@ Unify _LineNumber_ with the line number for the current stream.
}
static
PRED_IMPL("is_stream", 1, is_stream, 0)
/** @pred is_stream( _S_)
Succeeds if _S_ is a currently open stream.
*/
static
PRED_IMPL("is_stream", 1, is_stream, 0)
{ GET_LD
IOSTREAM *s;
atom_t a;
@ -4734,11 +4861,17 @@ Succeeds if _S_ is a currently open stream.
return FALSE;
}
/*******************************
* FLUSH *
*******************************/
/**
* @}
*/
/**
* @addtogroup YAPStreamM
* @{
*/
static int
@ -4753,8 +4886,6 @@ flush_output(term_t out ARG_LD)
return FALSE;
}
static
PRED_IMPL("flush_output", 0, flush_output, PL_FA_ISO)
/** @pred flush_output is iso
@ -4762,24 +4893,35 @@ Send out all data in the output buffer of the current output stream.
*/
static
PRED_IMPL("flush_output", 0, flush_output, PL_FA_ISO)
{ PRED_LD
return flush_output(0 PASS_LD);
}
static
PRED_IMPL("flush_output", 1, flush_output1, PL_FA_ISO)
/** @pred flush_output(+ _S_) is iso
Send all data in the output buffer for stream _S_.
*/
static
PRED_IMPL("flush_output", 1, flush_output1, PL_FA_ISO)
{ PRED_LD
return flush_output(A1 PASS_LD);
}
/**
* @}
*/
/**
* @addtogroup YAPStream
* @{
*/
static int
getStreamWithPosition(term_t stream, IOSTREAM **sp)
@ -4826,8 +4968,6 @@ getRepositionableStream(term_t stream, IOSTREAM **sp)
}
static
PRED_IMPL("set_stream_position", 2, set_stream_position, PL_FA_ISO)
/** @pred set_stream_position(+ _S_, + _POS_) is iso
@ -4836,6 +4976,8 @@ stream position for _S_ to be _POS_.
*/
static
PRED_IMPL("set_stream_position", 2, set_stream_position, PL_FA_ISO)
{ PRED_LD
IOSTREAM *s = NULL; /* make compiler happy */
int64_t charno, byteno;
@ -4932,8 +5074,6 @@ PRED_IMPL("seek", 4, seek, 0)
}
static
PRED_IMPL("set_input", 1, set_input, PL_FA_ISO)
/** @pred set_input(+ _S_) is iso
@ -4942,6 +5082,8 @@ and get/1 will start using stream _S_.
*/
static
PRED_IMPL("set_input", 1, set_input, PL_FA_ISO)
{ PRED_LD
IOSTREAM *s;
@ -4955,9 +5097,7 @@ and get/1 will start using stream _S_.
}
static
PRED_IMPL("set_output", 1, set_output, PL_FA_ISO)
/** @pred set_output(+ _S_) is iso
/** @pred set_output(+ _S_) is iso
Set stream _S_ as the current output stream. Predicates like
@ -4965,6 +5105,8 @@ write/1 and put/1 will start using stream _S_.
*/
static
PRED_IMPL("set_output", 1, set_output, PL_FA_ISO)
{ PRED_LD
IOSTREAM *s;
@ -4978,8 +5120,6 @@ write/1 and put/1 will start using stream _S_.
}
static
PRED_IMPL("current_input", 1, current_input, PL_FA_ISO)
/** @pred current_input(- _S_) is iso
@ -4987,13 +5127,13 @@ Unify _S_ with the current input stream.
*/
static
PRED_IMPL("current_input", 1, current_input, PL_FA_ISO)
{ PRED_LD
return PL_unify_stream(A1, Scurin);
}
static
PRED_IMPL("current_output", 1, current_output, PL_FA_ISO)
/** @pred current_output(- _S_) is iso
@ -5001,11 +5141,21 @@ Unify _S_ with the current output stream.
*/
static
PRED_IMPL("current_output", 1, current_output, PL_FA_ISO)
{ PRED_LD
return PL_unify_stream(A1, Scurout);
}
/** @pred character_count(+ _Stream_,- _ByteCount_)
Unify _CharacterCount_ with the number of bytes written to or
read from _Stream_.
*/
static
PRED_IMPL("byte_count", 2, byte_count, 0)
{ PRED_LD
@ -5022,16 +5172,16 @@ PRED_IMPL("byte_count", 2, byte_count, 0)
}
static
PRED_IMPL("character_count", 2, character_count, 0)
/** @pred character_count(+ _Stream_,- _CharacterCount_)
Unify _CharacterCount_ with the number of characters written to or
read to _Stream_.
read from _Stream_.
*/
static
PRED_IMPL("character_count", 2, character_count, 0)
{ PRED_LD
IOSTREAM *s;
@ -5046,8 +5196,6 @@ read to _Stream_.
}
static
PRED_IMPL("line_count", 2, line_count, 0)
/** @pred line_count(+ _Stream_,- _LineNumber_)
@ -5055,6 +5203,8 @@ Unify _LineNumber_ with the line number for the _Stream_.
*/
static
PRED_IMPL("line_count", 2, line_count, 0)
{ GET_LD
IOSTREAM *s;
@ -5069,8 +5219,6 @@ Unify _LineNumber_ with the line number for the _Stream_.
}
static
PRED_IMPL("line_position", 2, line_position, 0)
/** @pred line_position(+ _Stream_,- _LinePosition_)
@ -5079,6 +5227,8 @@ Unify _LinePosition_ with the position on current text stream
*/
static
PRED_IMPL("line_position", 2, line_position, 0)
{ GET_LD
IOSTREAM *s;
@ -5129,8 +5279,6 @@ at_end_of_stream(term_t stream ARG_LD)
return FALSE; /* exception */
}
static
PRED_IMPL("at_end_of_stream", 1, at_end_of_stream, PL_FA_ISO)
/** @pred at_end_of_stream(+ _S_) is iso
Succeed if the stream _S_ has stream position end-of-stream or
@ -5138,12 +5286,12 @@ past-end-of-stream. Note that _S_ must be a readable stream.
*/
static
PRED_IMPL("at_end_of_stream", 1, at_end_of_stream, PL_FA_ISO)
{ PRED_LD
return at_end_of_stream(A1 PASS_LD);
}
static
PRED_IMPL("at_end_of_stream", 0, at_end_of_stream0, PL_FA_ISO)
/** @pred at_end_of_stream is iso
@ -5152,6 +5300,8 @@ past-end-of-stream.
*/
static
PRED_IMPL("at_end_of_stream", 0, at_end_of_stream0, PL_FA_ISO)
{ PRED_LD
return at_end_of_stream(0 PASS_LD);
}
@ -5187,9 +5337,17 @@ peek(term_t stream, term_t chr, int how ARG_LD)
return PL_unify_char(chr, c, how);
}
/**
* @}
*/
/**
* @addtogroup YAPCharsIO
* @{
*/
static
PRED_IMPL("peek_byte", 2, peek_byte2, 0)
/** @pred peek_byte(+ _S_,- _C_) is iso
If _C_ is unbound, or is a character code, and _S_ is a binary
@ -5198,13 +5356,13 @@ with _C_, while leaving the current stream position unaltered.
*/
static
PRED_IMPL("peek_byte", 2, peek_byte2, 0)
{ PRED_LD
return peek(A1, A2, PL_BYTE PASS_LD);
}
static
PRED_IMPL("peek_byte", 1, peek_byte1, 0)
/** @pred peek_byte(- _C_) is iso
@ -5214,13 +5372,13 @@ code with _C_, while leaving the current stream position unaltered.
*/
static
PRED_IMPL("peek_byte", 1, peek_byte1, 0)
{ PRED_LD
return peek(0, A1, PL_BYTE PASS_LD);
}
static
PRED_IMPL("peek_code", 2, peek_code2, 0)
/** @pred peek_code(+ _S_,- _C_) is iso
If _C_ is unbound, or is an atom representation of a character, and
@ -5230,30 +5388,29 @@ the current stream position unaltered.
*/
static
PRED_IMPL("peek_code", 2, peek_code2, 0)
{ PRED_LD
return peek(A1, A2, PL_CODE PASS_LD);
}
static
PRED_IMPL("peek_code", 1, peek_code1, 0)
/** @pred peek_code(- _C_) is iso
/** @pred peek_code(+ _S_,- _C_) is iso
If _C_ is unbound, or is the code for a character, and
the current stream is a text stream, read the next character from the
current stream and unify its code with _C_, while
leaving the current stream position unaltered.
If _C_ is unbound, or is an atom representation of a character, and
the stream _S_ is a text stream, read the next character from that
stream and unify its representation as an atom with _C_, while leaving
the current stream position unaltered.
*/
static
PRED_IMPL("peek_code", 1, peek_code1, 0)
{ PRED_LD
return peek(0, A1, PL_CODE PASS_LD);
}
static
PRED_IMPL("peek_char", 2, peek_char2, 0)
/** @pred peek_char(+ _S_,- _C_) is iso
If _C_ is unbound, or is an atom representation of a character, and
@ -5263,13 +5420,12 @@ the current stream position unaltered.
*/
static
PRED_IMPL("peek_char", 2, peek_char2, 0)
{ PRED_LD
return peek(A1, A2, PL_CHAR PASS_LD);
}
static
PRED_IMPL("peek_char", 1, peek_char1, 0)
/** @pred peek_char(- _C_) is iso
@ -5280,6 +5436,8 @@ leaving the current stream position unaltered.
*/
static
PRED_IMPL("peek_char", 1, peek_char1, 0)
{ PRED_LD
return peek(0, A1, PL_CHAR PASS_LD);
}
@ -5500,18 +5658,30 @@ copy_stream_data(term_t in, term_t out, term_t len ARG_LD)
return streamStatus(i);
}
/** @pred copy_stream_data( +_Source_, +_Output_, +_Len_)
*
* Copy at most _Len_ characters from stream _Source_ to stream _Output_.
*/
static
PRED_IMPL("copy_stream_data", 3, copy_stream_data3, 0)
{ PRED_LD
return copy_stream_data(A1, A2, A3 PASS_LD);
}
/** @pred copy_stream_data( +_Source_, +_Output_)
*
* Copy all the data left in _Source_ to stream _Output_.
*/
static
PRED_IMPL("copy_stream_data", 2, copy_stream_data2, 0)
{ PRED_LD
return copy_stream_data(A1, A2, 0 PASS_LD);
}
/**
* @}
*/
/*******************************
* PUBLISH PREDICATES *
@ -5544,22 +5714,7 @@ BeginPredDefs(file)
PRED_DEF("put_code", 2, put_code2, PL_FA_ISO)
PRED_DEF("put_code", 1, put_code1, PL_FA_ISO)
PRED_DEF("put_char", 2, put_code2, PL_FA_ISO)
/** @pred put_char(+ _S_,+ _A_) is iso
As `put_char(A)`, but to text stream _S_.
*/
PRED_DEF("put_char", 1, put_code1, PL_FA_ISO)
/** @pred put_char(+ _N_) is iso
Outputs to the current output stream the character who is used to build
the representation of atom `A`. The current output stream must be a
text stream.
*/
PRED_DEF("flush_output", 0, flush_output, PL_FA_ISO)
PRED_DEF("flush_output", 1, flush_output1, PL_FA_ISO)
PRED_DEF("at_end_of_stream", 1, at_end_of_stream, PL_FA_ISO)
@ -5583,23 +5738,7 @@ text stream.
PRED_DEF("get", 1, get1, 0)
PRED_DEF("get", 2, get2, 0)
PRED_DEF("get0", 2, get_code2, 0)
/** @pred get0(+ _S_,- _C_)
The same as `get0(C)`, but from stream _S_.
*/
PRED_DEF("get0", 1, get_code1, 0)
/** @pred get0(- _C_)
The next character from the current input stream is consumed, and then
unified with _C_. There are no restrictions on the possible
values of the ASCII code for the character, but the character will be
internally converted by YAP.
*/
PRED_DEF("ttyflush", 0, ttyflush, 0)
PRED_DEF("prompt", 2, prompt, 0)
PRED_DEF("tab", 2, tab2, 0)
@ -5722,148 +5861,19 @@ pl_sleep(term_t time)
static const PL_extension foreigns[] = {
FRG("nl", 0, pl_nl, ISO),
/** @pred nl is iso
Outputs a new line to the current output stream.
*/
FRG("write_canonical", 1, pl_write_canonical, ISO),
/** @pred write_canonical(+ _T_) is iso
Displays term _T_ on the current output stream. Atoms are quoted
when necessary, and operators are ignored, that is, the term is written
in standard parenthesized prefix notation.
*/
FRG("write_term", 2, pl_write_term, ISO),
/** @pred write_term(+ _T_, + _Opts_) is iso
Displays term _T_ on the current output stream, according to the
following options:
+ quoted(+ _Bool_) is iso
If `true`, quote atoms if this would be necessary for the atom to
be recognized as an atom by YAP's parser. The default value is
`false`.
+ ignore_ops(+ _Bool_) is iso
If `true`, ignore operator declarations when writing the term. The
default value is `false`.
+ numbervars(+ _Bool_) is iso
If `true`, output terms of the form
`$VAR(N)`, where _N_ is an integer, as a sequence of capital
letters. The default value is `false`.
+ portrayed(+ _Bool_)
If `true`, use <tt>portray/1</tt> to portray bound terms. The default
value is `false`.
+ portray(+ _Bool_)
If `true`, use <tt>portray/1</tt> to portray bound terms. The default
value is `false`.
+ max_depth(+ _Depth_)
If `Depth` is a positive integer, use <tt>Depth</tt> as
the maximum depth to portray a term. The default is `0`, that is,
unlimited depth.
+ priority(+ _Piority_)
If `Priority` is a positive integer smaller than `1200`,
give the context priority. The default is `1200`.
+ cycles(+ _Bool_)
Do not loop in rational trees (default).
*/
FRG("write_term", 3, pl_write_term3, ISO),
/** @pred write_term(+ _S_, + _T_, + _Opts_) is iso
Displays term _T_ on the current output stream, according to the same
options used by `write_term/3`.
*/
FRG("write", 1, pl_write, ISO),
/** @pred write( _T_) is iso
The term _T_ is written to the current output stream according to
the operator declarations in force.
*/
FRG("writeq", 1, pl_writeq, ISO),
/** @pred writeq( _T_) is iso
Writes the term _T_, quoting names to make the result acceptable to
the predicate `read` whenever necessary.
*/
FRG("print", 1, pl_print, 0),
/** @pred print( _T_)
Prints the term _T_ to the current output stream using write/1
unless T is bound and a call to the user-defined predicate
`portray/1` succeeds. To do pretty printing of terms the user should
define suitable clauses for `portray/1` and use print/1.
*/
FRG("nl", 1, pl_nl1, ISO),
/** @pred nl(+ _S_) is iso
Outputs a new line to stream _S_.
*/
FRG("format", 2, pl_format, META),
FRG("write", 2, pl_write2, ISO),
/** @pred write(+ _S_, _T_) is iso
Writes term _T_ to stream _S_ instead of to the current output
stream.
*/
FRG("writeq", 2, pl_writeq2, ISO),
/** @pred writeq(+ _S_, _T_) is iso
As writeq/1, but the output is sent to the stream _S_.
*/
FRG("print", 2, pl_print2, 0),
/** @pred print(+ _S_, _T_)
Prints term _T_ to the stream _S_ instead of to the current output
stream.
*/
FRG("write_canonical", 2, pl_write_canonical2, ISO),
/** @pred write_canonical(+ _S_,+ _T_) is iso
Displays term _T_ on the stream _S_. Atoms are quoted when
necessary, and operators are ignored.
*/
FRG("format", 3, pl_format3, META),
FRG("sleep", 1, pl_sleep, 0),
FRG("get_time", 1, pl_get_time, 0),

View File

@ -21,6 +21,12 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @defgroup YAP_Format Formatted Output
* @ingroup YAP_InputOutput
* @{
*/
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Formatted output (Prolog predicates format/[1,2,3]). One day, the C
source should also use format() to produce error messages, etc.
@ -326,6 +332,12 @@ format_impl(IOSTREAM *out, term_t format, term_t Args, Module m)
}
/** @pred format(+ _S_,+ _T_,+ _L_)
Print formatted output to stream _S_.
*/
word
pl_format3(term_t out, term_t format, term_t args)
{ GET_LD
@ -347,7 +359,210 @@ pl_format3(term_t out, term_t format, term_t args)
return rc;
}
/** @pred format(+ _T_,+ _L_)
Print formatted output to the current output stream. The arguments in
list _L_ are output according to the string or atom _T_.
A control sequence is introduced by a `w`. The following control
sequences are available in YAP:
+ `~~`
Print a single tilde.
+ `~a`
The next argument must be an atom, that will be printed as if by `write`.
+ `~Nc`
The next argument must be an integer, that will be printed as a
character code. The number _N_ is the number of times to print the
character (default 1).
+ `~Ne`
+ `~NE`
+ `~Nf`
+ `~Ng`
+ `~NG`
The next argument must be a floating point number. The float _F_, the number
_N_ and the control code `c` will be passed to `printf` as:
~~~~~{.prolog}
printf("%s.Nc", F)
~~~~~
As an example:
~~~~~{.prolog}
?- format("~8e, ~8E, ~8f, ~8g, ~8G~w",
[3.14,3.14,3.14,3.14,3.14,3.14]).
3.140000e+00, 3.140000E+00, 3.140000, 3.14, 3.143.14
~~~~~
+ `~Nd`
The next argument must be an integer, and _N_ is the number of digits
after the decimal point. If _N_ is `0` no decimal points will be
printed. The default is _N = 0_.
~~~~~{.prolog}
?- format("~2d, ~d",[15000, 15000]).
150.00, 15000
~~~~~
+ `~ND`
Identical to `~Nd`, except that commas are used to separate groups
of three digits.
~~~~~{.prolog}
?- format("~2D, ~D",[150000, 150000]).
1,500.00, 150,000
~~~~~
+ `~i`
Ignore the next argument in the list of arguments:
~~~~~{.prolog}
?- format('The ~i met the boregrove',[mimsy]).
The met the boregrove
~~~~~
+ `~k`
Print the next argument with `write_canonical`:
~~~~~{.prolog}
?- format("Good night ~k",a+[1,2]).
Good night +(a,[1,2])
~~~~~
+ `~Nn`
Print _N_ newlines (where _N_ defaults to 1).
+ `~NN`
Print _N_ newlines if at the beginning of the line (where _N_
defaults to 1).
+ `~Nr`
The next argument must be an integer, and _N_ is interpreted as a
radix, such that `2 <= N <= 36` (the default is 8).
~~~~~{.prolog}
?- format("~2r, 0x~16r, ~r",
[150000, 150000, 150000]).
100100100111110000, 0x249f0, 444760
~~~~~
Note that the letters `a-z` denote digits larger than 9.
+ `~NR`
Similar to `~NR`. The next argument must be an integer, and _N_ is
interpreted as a radix, such that `2 <= N <= 36` (the default is 8).
~~~~~{.prolog}
?- format("~2r, 0x~16r, ~r",
[150000, 150000, 150000]).
100100100111110000, 0x249F0, 444760
~~~~~
The only difference is that letters `A-Z` denote digits larger than 9.
+ `~p`
Print the next argument with print/1:
~~~~~{.prolog}
?- format("Good night ~p",a+[1,2]).
Good night a+[1,2]
~~~~~
+ `~q`
Print the next argument with writeq/1:
~~~~~{.prolog}
?- format("Good night ~q",'Hello'+[1,2]).
Good night 'Hello'+[1,2]
~~~~~
+ `~Ns`
The next argument must be a list of character codes. The system then
outputs their representation as a string, where _N_ is the maximum
number of characters for the string ( _N_ defaults to the length of the
string).
~~~~~{.prolog}
?- format("The ~s are ~4s",["woods","lovely"]).
The woods are love
~~~~~
+ `~w`
Print the next argument with write/1:
~~~~~
?- format("Good night ~w",'Hello'+[1,2]).
Good night Hello+[1,2]
~~~~~
The number of arguments, `N`, may be given as an integer, or it
may be given as an extra argument. The next example shows a small
procedure to write a variable number of `a` characters:
~~~~~
write_many_as(N) :-
format("~*c",[N,0'a]).
~~~~~
The format/2 built-in also allows for formatted output. One can
specify column boundaries and fill the intermediate space by a padding
character:
+ `~N|`
Set a column boundary at position _N_, where _N_ defaults to the
current position.
+ `~N+`
Set a column boundary at _N_ characters past the current position, where
_N_ defaults to `8`.
+ `~Nt`
Set padding for a column, where _N_ is the fill code (default is
`SPC`).
The next example shows how to align columns and padding. We first show
left-alignment:
~~~~~
?- format("~n*Hello~16+*~n",[]).
*Hello *
~~~~~
Note that we reserve 16 characters for the column.
The following example shows how to do right-alignment:
~~~~~
?- format("*~tHello~16+*~n",[]).
* Hello*
~~~~~
The `~t` escape sequence forces filling before `Hello`.
We next show how to do centering:
~~~~~
?- format("*~tHello~t~16+*~n",[]).
* Hello *
~~~~~
The two `~t` escape sequence force filling both before and after
`Hello`. Space is then evenly divided between the right and the
left sides.
*/
word
pl_format(term_t fmt, term_t args)
{ return pl_format3(0, fmt, args);
@ -1489,3 +1704,5 @@ formatFloat(PL_locale *locale, int how, int arg, Number f, Buffer out)
return baseBuffer(out, char);
}
//! @}

View File

@ -20,6 +20,15 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/** @defgroup SetLocale Localization Support
* @ingroup YAP_InputOutput
* @{
*
* This code includes support for localization, that is, the ability to support
* different languages and representation formats.
*
* The code was written by Jan Wielemaker for SWI-Prolog.
*/
#include "pl-incl.h"
#include "pl-locale.h"
@ -475,7 +484,7 @@ get_atom_arg(term_t t, atom_t *a)
/** locale_property(?Locale, ?Property) is nondet.
*/
/// @memberof locale_property/2
static
PRED_IMPL("locale_property", 2, locale_property, PL_FA_NONDETERMINISTIC)
{ PRED_LD
@ -681,7 +690,7 @@ set_grouping(term_t t, char **valp)
/** locale_create(-Locale, +Default, +Options) is det.
*/
/// @memberof locale_create/3
static
PRED_IMPL("locale_create", 3, locale_create, 0)
{ PRED_LD
@ -760,6 +769,9 @@ PRED_IMPL("locale_create", 3, locale_create, 0)
}
/** locale_destroy(+Locale) is det.
*/
/// @memberof locale_destroy/1
static
PRED_IMPL("locale_destroy", 1, locale_destroy, 0)
{ PL_locale *l;
@ -787,7 +799,7 @@ PRED_IMPL("locale_destroy", 1, locale_destroy, 0)
/** set_locale(+Locale) is det.
*/
/// @memberof set_locale/1
static
PRED_IMPL("set_locale", 1, set_locale, 0)
{ PRED_LD
@ -820,7 +832,7 @@ PRED_IMPL("set_locale", 1, set_locale, 0)
/** current_locale(-Locale) is det.
*/
/// @memberof current_locale/1
static
PRED_IMPL("current_locale", 1, current_locale, 0)
{ PRED_LD
@ -927,3 +939,5 @@ BeginPredDefs(locale)
EndPredDefs
#endif /*O_LOCALE*/
/// @}

View File

@ -23,6 +23,16 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/** @defgroup YAPWrite Outputting a term to a Stream
* @ingroup YAP_InputOutput
*
* @brief Predicates that output a term to a stream. The predicates
* call upon write_term/3 to do the actual work. They differ on the
* parameters being used
* whether they write to user_output or to an user-specified stream.
*
* @{
*/
#include <math.h>
#include "pl-incl.h"
#include "pl-dtoa.h"
@ -67,6 +77,11 @@ typedef struct
term_t prec_opt; /* term in write options with prec */
} write_options;
/** @pred nl(+ _S_) is iso
Outputs a new line to stream _S_.
*/
/// @memberof nl/1
word
pl_nl1(term_t stream)
{ GET_LD
@ -80,6 +95,12 @@ pl_nl1(term_t stream)
fail;
}
/** @pred nl is iso
Outputs a new line to the current output stream.
*/
/// @memberof nl/0
word
pl_nl(void)
{ return pl_nl1(0);
@ -517,13 +538,69 @@ out:
return (!s || streamStatus(s)) && rc;
}
/** @pred write_term(+ _S_, + _T_, + _Opts_) is iso
Displays term _T_ on the current output stream, according to the same
options used by `write_term/3`.
*/
/// @memberof write_term/3
word
pl_write_term(term_t term, term_t options)
{ return pl_write_term3(0, term, options);
}
/** @pred write_term(+ _T_, + _Opts_) is iso
Displays term _T_ on the current output stream, according to the
following options:
+ quoted(+ _Bool_) is iso
If `true`, quote atoms if this would be necessary for the atom to
be recognized as an atom by YAP's parser. The default value is
`false`.
+ ignore_ops(+ _Bool_) is iso
If `true`, ignore operator declarations when writing the term. The
default value is `false`.
+ numbervars(+ _Bool_) is iso
If `true`, output terms of the form
`$VAR(N)`, where _N_ is an integer, as a sequence of capital
letters. The default value is `false`.
+ portrayed(+ _Bool_)
If `true`, use <tt>portray/1</tt> to portray bound terms. The default
value is `false`.
+ portray(+ _Bool_)
If `true`, use <tt>portray/1</tt> to portray bound terms. The default
value is `false`.
+ max_depth(+ _Depth_)
If `Depth` is a positive integer, use <tt>Depth</tt> as
the maximum depth to portray a term. The default is `0`, that is,
unlimited depth.
+ priority(+ _Piority_)
If `Priority` is a positive integer smaller than `1200`,
give the context priority. The default is `1200`.
+ cycles(+ _Bool_)
Do not loop in rational trees (default).
*/
/// @memberof write_term/2
int
PL_write_term(IOSTREAM *s, term_t term, int precedence, int flags)
{ write_options options;
@ -572,22 +649,53 @@ do_write2(term_t stream, term_t term, int flags)
}
/** @pred write(+ _S_, _T_) is iso
Writes term _T_ to stream _S_ instead of to the current output
stream.
*/
/// @memberof write/2
word
pl_write2(term_t stream, term_t term)
{ return do_write2(stream, term, PL_WRT_NUMBERVARS);
}
/** @pred writeq(+ _S_, _T_) is iso
As writeq/1, but the output is sent to the stream _S_.
*/
/// @memberof writeq/2
word
pl_writeq2(term_t stream, term_t term)
{ return do_write2(stream, term, PL_WRT_QUOTED|PL_WRT_NUMBERVARS);
}
/** @pred print(+ _S_, _T_)
Prints term _T_ to the stream _S_ instead of to the current output
stream.
*/
/// @memberof print/2
word
pl_print2(term_t stream, term_t term)
{ return do_write2(stream, term,
PL_WRT_PORTRAY|PL_WRT_NUMBERVARS);
}
/** @pred write_canonical(+ _S_,+ _T_) is iso
Displays term _T_ on the stream _S_. Atoms are quoted when
necessary, and operators are ignored.
*/
/// @memberof write_canonical/2
word
pl_write_canonical2(term_t stream, term_t term)
{ GET_LD
@ -611,26 +719,69 @@ pl_write_canonical2(term_t stream, term_t term)
return rc;
}
/** @pred write( _T_) is iso
The term _T_ is written to the current output stream according to
the operator declarations in force.
*/
/// @memberof write/1
word
pl_write(term_t term)
{ return pl_write2(0, term);
}
word
/** @pred writeq( _T_) is iso
Writes the term _T_, quoting names to make the result acceptable to
the predicate `read` whenever necessary.
*/
/// @memberof writeq/1
pl_writeq(term_t term)
{ return pl_writeq2(0, term);
}
/** @pred print( _T_)
Prints the term _T_ to the current output stream using write/1
unless T is bound and a call to the user-defined predicate
`portray/1` succeeds. To do pretty printing of terms the user should
define suitable clauses for `portray/1` and use print/1.
*/
/// @memberof print/1
word
pl_print(term_t term)
{ return pl_print2(0, term);
}
/** @pred write_canonical(+ _T_) is iso
Displays term _T_ on the current output stream. Atoms are quoted
when necessary, and operators are ignored, that is, the term is written
in standard parenthesized prefix notation.
*/
/// @memberof write_canonical/1
word
pl_write_canonical(term_t term)
{ return pl_write_canonical2(0, term);
}
/** @pred writeln( _T_)
Prints the term _T_ to the current output stream using write/1,
followed by a newline.
*/
/// @memberof writeln/1
word
pl_writeln(term_t term)
{ return do_write2(0, term, PL_WRT_NUMBERVARS|PL_WRT_NEWLINE);
@ -641,7 +792,9 @@ pl_writeln(term_t term)
/*******************************
* PUBLISH PREDICATES *
*******************************/
/// @}
BeginPredDefs(write)
EndPredDefs

View File

@ -21,6 +21,332 @@
add_ground_factor/5 %add a new bayesian variable (for now)
]).
/** @defgroup PFL The PrologFactor Language
@ingroup YAPPackagaes
section{Introduction}
The Prolog Factor Language (PFL) is a language that extends Prolog for providing a syntax to describe first-order probabilistic graphical models. These models can be either directed (bayesian networks) or undirected (markov networks). This language replaces the old one known as CLP(BN).
The package also includes implementations for a set of well-known inference algorithms for solving probabilistic queries on these models. Both ground and lifted inference methods are support.
### Installation
PFL is included with the YAP Prolog system. The commands to perform a default installation of YAP in your home directory in a Unix-based environment are shown next.
1 `$ cd $HOME`
2 `$ git clone git://yap.git.sourceforge.net/gitroot/yap/yap-6.3`
3 `$ cd yap-6.3/`
4 `$ ./configure --enable-clpbn-bp --prefix=$HOME`
5 `$ make depend \& make install`
In case you want to install YAP somewhere else or with different settings, please consult the YAP documentation. From now on, we will assume that the directory `$HOME/bin` (where the binary is) is in your `$PATH` environment variable.
Once in a while, we will refer to the PFL examples directory. In a default installation, this directory will be located at `$HOME/share/doc/Yap/packages/examples/CLPBN`.
### Language
A first-order probabilistic graphical model is described using parametric factors, commonly known as parfactors. The PFL syntax for a parfactor is
_Type F; Phi ; C._
Where,
+ _Type_ refers the type of network over which the parfactor is defined. It can be `bayes` for directed networks, or `markov` for undirected ones.
+ _F_ is a comma-separated sequence of Prolog terms that will define sets of random variables under the constraint _C_. If _Type_ is `bayes`, the first term defines the node while the remaining terms define its parents.
+ _Phi_ is either a Prolog list of potential values or a Prolog goal that unifies with one. Notice that if _Type_ is `bayes`, this will correspond to the conditional probability table. Domain combinations are implicitly assumed in ascending order, with the first term being the 'most significant' (e.g. _\mathtt{x_0y_0}_, _\mathtt{x_0y_1}_, _\mathtt{x_0y_2}_, _\mathtt{x_1y_0}_, _\mathtt{x_1y_1}_, _\mathtt{x_1y_2}_).
+ _C_ is a (possibly empty) list of Prolog goals that will instantiate the logical variables that appear in _F_, that is, the successful substitutions for the goals in _C_ will be the valid values for the logical variables. This allows the constraint to be defined as any relation (set of tuples) over the logical variables.
~~~~
:- use_module(library(pfl)).
bayes cloudy ; cloudy_table ; [].
bayes sprinkler, cloudy ; sprinkler_table ; [].
bayes rain, cloudy ; rain_table ; [].
bayes wet_grass, sprinkler, rain ; wet_grass_table ; [].
cloudy_table(
[ 0.5,
0.5 ]).
sprinkler_table(
[ 0.1, 0.5,
0.9, 0.5 ]).
rain_table(
[ 0.8, 0.2,
0.2, 0.8 ]).
wet_grass_table(
[ 0.99, 0.9, 0.9, 0.0,
0.01, 0.1, 0.1, 1.0 ]).
~~~~
In the example, we started by loading the PFL library, then we have defined one factor for each node, and finally we have specified the probabilities for each conditional probability table.
Notice that this network is fully grounded, as all constraints are empty. Next we present the PFL representation for a well-known markov logic network - the social network model. For convenience, the two main weighted formulas of this model are shown below.
~~~~
1.5 : Smokes(x) => Cancer(x)
1.1 : Smokes(x) ^ Friends(x,y) => Smokes(y)
~~~~
Next, we show the PFL representation for this model.
~~~~
:- use_module(library(pfl)).
person(anna).
person(bob).
markov smokes(X), cancer(X) ;
[4.482, 4.482, 1.0, 4.482] ;
[person(X)].
markov friends(X,Y), smokes(X), smokes(Y) ;
[3.004, 3.004, 3.004, 3.004, 3.004, 1.0, 1.0, 3.004] ;
[person(X), person(Y)].
%markov smokes(X) ; [1.0, 4.055]; [person(X)].
%markov cancer(X) ; [1.0, 9.974]; [person(X)].
%markov friends(X,Y) ; [1.0, 99.484] ; [person(X), person(Y)].
~~~~
Notice that we have defined the world to be consisted of only two persons, `anna` and `bob`. We can easily add as many persons as we want by inserting in the program a fact like `person @ 10.`~. This would automatically create ten persons named `p1`, `p2`, \dots, `p10`.
Unlike other fist-order probabilistic languages, in PFL the logical variables that appear in the terms are not directly typed, and they will be only constrained by the goals that appears in the constraint of the parfactor. This allows the logical variables to be constrained to any relation (set of tuples), and not only pairwise (in)equalities. For instance, the next example defines a network with three ground factors, each defined respectively over the random variables `p(a,b)`, `p(b,d)` and `p(d,e)`.
~~~~
constraint(a,b).
constraint(b,d).
constraint(d,e).
markov p(A,B); some_table; [constraint(A,B)].
~~~~
We can easily add static evidence to PFL programs by inserting a fact with the same functor and arguments as the random variable, plus one extra argument with the observed state or value. For instance, suppose that we know that `anna` and `bob` are friends. We can add this knowledge to the program with the following fact: `friends(anna,bob,t).`~.
One last note for the domain of the random variables. By default, all terms instantiate boolean (`t`/`f`) random variables. It is possible to choose a different domain for a term by appending a list of its possible values or states. Next we present a self-explanatory example of how this can be done.
~~~~
bayes professor_ability::[high, medium, low] ; [0.5, 0.4, 0.1].
~~~~
More probabilistic models defined using PFL can be found in the examples directory.
### Querying
In this section we demonstrate how to use PFL to solve probabilistic queries. We will use the sprinkler network as example.
Assuming that the current directory is the one where the examples are located, first we load the model with the following command.
`$ yap -l sprinkler.pfl`
Let's suppose that we want to estimate the marginal probability for the $WetGrass$ random variable. To do so, we call the following goal.
`?- wet\_grass(X).`
The output of this goal will show the marginal probability for each $WetGrass$ possible state or value, that is, `t` and `f`. Notice that in PFL a random variable is identified by a term with the same functor and arguments plus one extra argument.
Now let's suppose that we want to estimate the probability for the same random variable, but this time we have evidence that it had rained in the day before. We can estimate this probability without resorting to static evidence with:
`?- wet\_grass(X), rain(t).`
PFL also supports calculating joint probability distributions. For instance, we can obtain the joint probability for $Sprinkler$ and $Rain$ with:
`?- sprinkler(X), rain(Y).`
%------------------------------------------------------------------------------
%------------------------------------------------------------------------------
%------------------------------------------------------------------------------
%------------------------------------------------------------------------------
### Options
PFL supports both ground and lifted inference methods. The inference algorithm can be chosen by calling `set\_solver/1`. The following are supported:
+ `ve`, variable elimination (written in Prolog)
+ `hve`, variable elimination (written in C++)
+ `jt`, junction tree
+ `bdd`, binary decision diagrams
+ `bp`, belief propagation
+ `cbp`, counting belief propagation
+ `gibbs`, gibbs sampling
+ `lve`, generalized counting first-order variable elimination (GC-FOVE)
+ `lkc`, lifted first-order knowledge compilation
+ `lbp`, lifted first-order belief propagation
For instance, if we want to use belief propagation to solve some probabilistic query, we need to call first:
`?- set\_solver(bp).`
It is possible to tweak some parameters of PFL through `set\_pfl\_flag/2` predicate. The first argument is a option name that identifies the parameter that we want to tweak. The second argument is some possible value for this option. Next we explain the available options in detail.
\optionsection{verbosity}
This option controls the level of debugging information that will be shown.
+ Values: a positive integer (default is 0 - no debugging). The higher the number, the more information that will be shown.
+ Affects: `hve`, `bp`, `cbp`, `lve`, `lkc` and `lbp`.
For instance, we can view some basic debugging information by calling the following goal.
`?- set\_pfl\_flag(verbosity, 1).`
\optionsection{use\_logarithms}
This option controls whether the calculations performed during inference should be done in a logarithm domain or not.
+ Values: `true` (default) or `false`.
+ Affects: `hve`, `bp`, `cbp`, `lve`, `lkc` and `lbp`.
\optionsection{hve\_elim\_heuristic}
This option allows to choose which elimination heuristic will be used by the `hve`.
+ Values: `sequential`, `min\_neighbors`, `min\_weight`, `min\_fill` and\\ `weighted\_min\_fill` (default).
+ Affects: `hve`.
An explanation for each of these heuristics can be found in Daphne Koller's book \textit{Probabilistic Graphical Models}.
\optionsection{bp\_max\_iter}
This option establishes a maximum number of iterations. One iteration consists in sending all possible messages.
+ Values: a positive integer (default is `1000`).
+ Affects: `bp`, `cbp` and `lbp`.
\optionsection{bp\_accuracy}
This option allows to control when the message passing should cease. Be the residual of one message the difference (according some metric) between the one sent in the current iteration and the one sent in the previous. If the highest residual is lesser than the given value, the message passing is stopped and the probabilities are calculated using the last messages that were sent.
+ Values: a float-point number (default is `0.0001`).
+ Affects: `bp`, `cbp` and `lbp`.
+ bp\_msg\_schedule
This option allows to control the message sending order.
+ Values:
+ `seq\_fixed` (default), at each iteration, all messages are sent with the same order.
+ `seq\_random`, at each iteration, all messages are sent with a random order.
+ `parallel`, at each iteration, all messages are calculated using only the values of the previous iteration.
+ `max\_residual`, the next message to be sent is the one with maximum residual (as explained in the paper \textit{Residual Belief Propagation: Informed Scheduling for Asynchronous Message Passing}).
+ Affects: `bp`, `cbp` and `lbp`.
+ export\_libdai
This option allows exporting the current model to the libDAI, http://cs.ru.nl/~jorism/libDAI/doc/fileformats.html, file format.
+ Values: `true` or `false` (default).
+ Affects: `hve`, `bp`, and `cbp`.
+ export\_uai
This option allows exporting the current model to the \href{http://graphmod.ics.uci.edu/uai08/FileFormat}{UAI08} file format.
+ Values: `true` or `false` (default).
+ Affects: `hve`, `bp`, and `cbp`.
+ export\_graphviz
This option allows exporting the factor graph's structure into a format that can be parsed by \href{http://www.graphviz.org/}{Graphviz}.
+ Values: `true` or `false` (default).
+ Affects: `hve`, `bp`, and `cbp`.
+ print\_fg
This option allows to print a textual representation of the factor graph.
+ Values: `true` or `false` (default).
+ Affects: `hve`, `bp`, and `cbp`.
### Learning
PFL is capable to learn the parameters for bayesian networks, through an implementation of the expectation-maximization algorithm.
Next we show an example of parameter learning for the sprinkler network.
~~~~
:- [sprinkler.pfl].
:- use_module(library(clpbn/learning/em)).
data(t, t, t, t).
data(_, t, _, t).
data(t, t, f, f).
data(t, t, f, t).
data(t, _, _, t).
data(t, f, t, t).
data(t, t, f, t).
data(t, _, f, f).
data(t, t, f, f).
data(f, f, t, t).
main :-
findall(X, scan_data(X), L),
em(L, 0.01, 10, CPTs, LogLik),
writeln(LogLik:CPTs).
scan_data([cloudy(C), sprinkler(S), rain(R), wet_grass(W)]) :-
data(C, S, R, W).
~~~~
Parameter learning is done by calling the `em/5` predicate. Its arguments are the following.
\begin{center}
`em(+Data, +MaxError, +MaxIters, -CPTs, -LogLik)`
\end{center}
Where,
+ `Data` is a list of samples for the distribution that we want to estimate. Each sample is a list of either observed random variables or unobserved random variables (denoted when its state or value is not instantiated).
+ `MaxError` is the maximum error allowed before stopping the EM loop.
+ `MaxIters` is the maximum number of iterations for the EM loop.
+ `CPTs` is a list with the estimated conditional probability tables.
+ `LogLik` is the log-likelihood.
It is possible to choose the solver that will be used for the inference part during parameter learning with the `set\_em\_solver/1` predicate (defaults to `hve`). At the moment, only the following solvers support parameter learning: `ve`, `hve`, `bdd`, `bp` and `cbp`.
Inside the `learning` directory from the examples directory, one can find more examples of parameter learning.
### External Interface
This package also includes an external command for perform inference over probabilistic graphical models described in formats other than PFL. Currently two are support, the \href{http://cs.ru.nl/~jorism/libDAI/doc/fileformats.html}{libDAI file format}, and the \href{http://graphmod.ics.uci.edu/uai08/FileFormat}{UAI08 file format}.
This command's name is `hcli` and its usage is as follows.
~~~
$ ./hcli [solver=hve|bp|cbp] [<OPTION>=<VALUE>]...
<FILE> [<VAR>|<VAR>=<EVIDENCE>]...
~~~
Let's assume that the current directory is the one where the examples are located. We can perform inference in any supported model by passing the file name where the model is defined as argument. Next, we show how to load a model with `hcli`.
`$ ./hcli burglary-alarm.uai`
With the above command, the program will load the model and print the marginal probabilities for all defined random variables. We can view only the marginal probability for some variable with a identifier $X$, if we pass $X$ as an extra argument following the file name. For instance, the following command will output only the marginal probability for the variable with identifier $0$.
`$ ./hcli burglary-alarm.uai 0`
If we give more than one variable identifier as argument, the program will output the joint probability for all the passed variables.
Evidence can be given as a pair containing a variable identifier and its observed state (index), separated by a '=`. For instance, we can introduce knowledge that some variable with identifier $0$ has evidence on its second state as follows.
`$ ./hcli burglary-alarm.uai 0=1`
By default, all probability tasks are resolved using the `hve` solver. It is possible to choose another solver using the `solver` option as follows.
`$ ./hcli solver=bp burglary-alarm.uai`
Notice that only the `hve`, `bp` and `cbp` solvers can be used with `hcli`.
The options that are available with the `set\_pfl\_flag/2` predicate can be used in `hcli` too. The syntax is a pair `<Option>=<Value>` before the model's file name.
*/
:- reexport(library(clpbn),
[clpbn_flag/2 as pfl_flag,
set_clpbn_flag/2 as set_pfl_flag,

View File

@ -223,6 +223,469 @@
%
% angelika.kimmig@cs.kuleuven.be
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
/**
@defgroup ProbLog1 The Leuven ProbLog1 System
@ingroup YAPPackages
@brief This document is intended as a user guide for the users of ProbLog. ProbLog is a probabilistic Prolog, a probabilistic logic programming language, which is integrated in YAP-Prolog.
## Installing ProbLog
### Requirements
For installing and running ProbLog, the following are required:
+ a reasonable up-to-date computer, running Linux or Mac OS
+ YAP Prolog 5.1.3 (for Mac OS the more recent version 5.1.4 is needed) or YAP-6
### Download
To install ProbLog1, it is first necessary to download SimpleCUDD or CUDD. YAP Prolog also needs to be downloaded if it is not already installed on the machine
For downloading SimpleCUDD, go to:
+ http://www.cs.kuleuven.be/$sim$theo/tools/SimpleCUDD.tar.gz
You can also use the CUDD interface package in YAP. You will need to
1. If a Fedora user, CUDD is just available.
2. If a Mac user, there is a ports package.
3 Otherwise, you can obtain the version at . This version compiles under WIN32.
Last, when you configure YAP you need to add the options --with-cidd --enable-bddlib. Binary distributed versions already have the interface.
## Running ProbLog
To use ProbLog, the ProbLog module has to be loaded at the top of your Prolog programs. If you use SimpleCUDD, this is done with the following statement:
~~~~
:- use_module(library(problog)).
~~~~
otherwise, if you prefer using YAP BDDs, use:
~~~~
:- use_module(library(problog_lbdd)).
~~~~
Similarly, to compile the ProbLog learning module, use:
~~~~
:- use_module(library(problog_learning)).
~~~~
or
~~~~
:- use_module(library(problog_learning_lbdd)).
~~~~
## Encoding Probabilistic Facts
A probabilistic fact is encoded in ProbLog by preceding a predicate with a probability value. For example:
~~~~
0.5::heads(_).
~~~~
encodes the fact that there's 50% chance of getting heads when tossing an unbiassed coin.
### Encoding Parameter Learning Facts
Instead of probabilities every fact has a t( ) prefix. The t stands for tunable and indicate that ProbLog should learn the probability. The number between the parentheses indicates the ground truth probability. It is ignored by the learning algorithm and if you do not know the ground truth, you can write t(_). The ground truth is used after learning to estimate the distance of the learned model parameters to the ground truth model parameters. For example:
~~~~
t(0.5)::heads(_).
~~~~
### ProbLog Predicates
This chapter describes the predicates defined by ProbLog for evaluating the probability of queries.
In the description of the arguments of functors the following notation will be used:
+ a preceding plus sign will denote an argument as an "input argument" - it cannot be a free variable at the time of the call
+ a preceding minus sign will denote an "output argument"
+ an argument with no preceding symbol can be used in both ways
@{
*/
/**
* @pred problog_max(+G, -Prob, -FactsUsed)
*
This predicate returns the most likely explanation of proving the goal G and the facts used in achieving this explanation.
*/
/**
* @pred problog_exact(+G, -Prob, -Status)
*
This predicate returns the exact total probability of achieving the goal G and the status of the query.
*/
/**
* @pred problog_kbest(+G, +K, -Prob, -Status)
*
This predicate returns the sum of the probabilities of the best K proofs of achieving the goal G and the status of the query.
*/
/**
* @pred problog_montecarlo(+G, +Interval_width, -Prob)
*
This predicate approximates the probability of achieving the goal G by using a Monte Carlo approach, with 95% confidence in the given interval width.
*/
/**
* @pred problog_delta(+G , +Interval_width, -Bound_low, -Bound_up, -Status)
*
This predicate returns the lower and upper bound of the probability of achieving the goal G by using an iterative
deepening approach with the given interval width.
*/
/**
* @pred problog_threshold(+G , +Prob, -Bound_low, -Bound_up, -Status)
*
This predicate returns the lower and upper bound of the probability of achieving the goal G obtained by cutting the sld tree at the given probability for each branch.
*/
/**
* @pred problog_low(+G, +Prob, -Bound_low, -Status)
*
This predicate returns the lower bound of the probability of achieving the goal G obtained by cutting the sld tree at the given probability for each branch.
*/
### ProbLog Parameter Learning Predicates
/**
* @pred example(+N, +Q, +Prob)
*
This predicate specifies an example. Every example has as input a unique identifier (N), a query (Q) and a probability (Prob) associated with it.
Instead of queries, you can also give proofs as training example. They are encoded as the conjunction of the probabilistic facts used in the proof.
*/
/**
* @pred test_example(+N, +Q, +Prob)
*
This predicate specifies a test example. Every test example has as input a unique identifier (N), a query (Q) and a probability (Prob) associated with it.
Test examples are ignored during learning but are used afterwards to check the performance of the model. The ID namespace is shared between the test examples and the training examples and you may only reuse an ID if the queries are identical.
*/
/**
* @pred do_learning(+N).
*
Starts the learning algorithm with N iterations.
paragraph{}
/**
* @pred do_learning(+N, +Epsilon).
*
The output is created in the output subfolder of the current folder where YAP was started. There you will find the file log.dat which contains MSE on training and test set for every iteration, the timings, and some metrics on the gradient in CSV format. The files factprobs_N.pl contain the fact probabilities after the Nth iteration and the files predictions_N.pl contain the estimated probabilities for each training and test example - per default these file are generated every 5th iteration only.
Starts the learning algorithm. The learning will stop after N iterations or if the difference of the Mean Squared Error (MSE) between two iterations gets smaller than Epsilon - depending on what happens first.
*/
### Miscelaneous
Both the learning and the inference module have various parameters, or flags, that can be adjusted by the user.
The following predicates are defined by ProbLog to access and set these flags.
*/
/**
* @pred problog_flags
*
This predicate lists all the flags name, value, domain and description.
*/
/**
* @pred problog_flag(+Name, -Value)
*
This predicate gives the value of the flag with the specified name. The supported flags are:
+ use_db_trie
Flag telling whether to use the builtin trie to trie transformation.
The possible values for this flag are true or false.
+ db_trie_opt_lvl
Sets the optimization level for the trie to trie transformation
The possible values for this flag are any integer
+ compare_opt_lvl
Flag telling whether to use comparison mode for the optimization level.
The possible values for this flag are true or false.
+ db_min_prefix
Sets the minimum size of the prefix for dbtrie to optimize.
The possible values for this flag are any integer
+ use_naive_trie
Flag telling whether to use the naive algorithm to generate bdd scripts.
The possible values for this flag are true or false.
+ use_old_trie
Flag telling whether to use the old not nested trie to trie transformation.
The possible values for this flag are true or false.
+ use_dec_trie
Flag telling whether to use the decomposition method.
The possible values for this flag are true or false.
+ subset_check
Flag telling whether to perform subset check in nested tries.
The possible values for this flag are true or false.
+ deref_terms
Flag telling whether to dereference BDD terms after their last use.
The possible values for this flag are true or false.
+ trie_preprocess
Flag telling whether to perform a preprocess step to nested tries.
The possible values for this flag are true or false.
+ refine_anclst
Flag telling whether to refine the ancestor list with their children.
The possible values for this flag are true or false.
+ anclst_represent
Flag that sets the representation of the ancestor list.
The possible values for this flag are list or integer
+ max\cccccccccccc_depth
Sets the maximum proof depth.
The possible values for this flag are any integer.
+ retain_tables
Flag telling whether to retain tables after the query.
The possible values for this flag are true or false.
+ mc_batchsize
Flag related to Monte Carlo Sampling that sets the number of samples before update.
The possible values for this flag are any integer greater than zero.
+ min_mc_samples
Flag related to Monte Carlo Sampling that sets the minimum number of samples before convergence.
The possible values for this flag are any integer greater than or equal to zero.
+ max_mc_samples
Flag related to Monte Carlo Sampling that sets the maximum number of samples waiting to converge.
The possible values for this flag are any integer greater than or equal to zero.
+ randomizer
Flag related to Monte Carlo Sampling telling whether the random numbers are repeatable or not.
The possible values for this flag are repeatable or nonrepeatable.
+ search_method
Flag related to DNF Monte Carlo Sampling that sets the search method for picking the proof.
The possible values for this flag are linear or binary.
+ represent_world
Flag related to Monte Carlo Sampling that sets the structure that represents sampled world.
The possible values for this flag are list, record, array or hash_table
+ first_threshold
Flag related to inference that sets the starting threshold of iterative deepening.
The possible values for this flag are a number in the interval (0,1).
+ last_threshold
Flag related to inference that sets the stopping threshold of iterative deepening.
The possible values for this flag are a number in the interval (0,1).
+ id_stepsize
Flag related to inference that sets the threshold shrinking factor of iterative deepening.
The possible values for this flag are a number in the interval [0,1].
+ prunecheck
Flag related to inference telling whether to stop derivations including all facts of known proofs.
The possible values for this flag are on or off.
+ maxsteps
Flag related to inference that sets the max. number of prob. steps per derivation.
The possible values for this flag are any integer greater than zero.
+ mc_logfile
Flag related to MCMC that sets the logfile for montecarlo.
The possible values for this flag are any valid filename.
+ bdd_time
Flag related to BDD that sets the BDD computation timeout in seconds.
The possible values for this flag are any integer greater than zero.
+ bdd_par_file
Flag related to BDD that sets the file for BDD variable parameters.
The possible values for this flag are any valid filename.
+ bdd_result
Flag related to BDD that sets the file to store result calculated from BDD.
The possible values for this flag are any valid filename.
+ bdd_file
Flag related to BDD that sets the file for the BDD script.
The possible values for this flag are any valid filename.
+ save_bdd
Flag related to BDD telling whether to save BDD files for (last) lower bound.
The possible values for this flag are true or false.
+ dynamic_reorder
Flag related to BDD telling whether to use dynamic re-ordering for BDD.
The possible values for this flag are true or false.
+ bdd_static_order
Flag related to BDD telling whether to use static order.
The possible values for this flag are true or false.
+ static_order_file
Flag related to BDD that sets the file for BDD static order.
The possible values for this flag are any valid filename.
+ verbose
Flag telling whether to output intermediate information.
The possible values for this flag are true or false.
+ show_proofs
Flag telling whether to output proofs.
The possible values for this flag are true or false.
+ triedump
Flag telling whether to generate the file: trie_file containing the trie structure.
The possible values for this flag are true or false.
+ dir
Flag telling the location of the output files directory.
The possible values for this flag are any valid directory name.
/** @pred set_problog_flag(+Name, +Value)
the predicate sets the value of the given flag. The supported flags are the ones listed in above
*/
/** @pred learning_flags
the predicate sets the value of the given flag. The supported flags are the ones listed in above
*/
/** @pred learning_flag(+Name, -Value)}
This predicate gives the value of the learning flag with the specified name. The supported flags are:
+ output_directory
Flag setting the directory where to store results.
The possible values for this flag are any valid path name.
+ query_directory
Flag setting the directory where to store BDD files.
The possible values for this flag are any valid path name.
+ verbosity_level
Flag telling how much output shall be given.
The possible values for this flag are an integer between 0 and 5 (0=nothing, 5=all).
+ reuse_initialized_bdds
Flag telling whether to reuse BDDs from previous runs.
The possible values for this flag are true or false.
+ rebuild_bdds
Flag telling whether to rebuild BDDs every nth iteration.
The possible values for this flag are any integer greater or equal to zero (0=never).
+ check_duplicate_bdds
Flag telling whether to store intermediate results in hash table.
The possible values for this flag are true or false.
+ init_method
Flag setting the ProbLog predicate to search proofs.
The possible values for this flag are of the form: (+Query,-P,+BDDFile,+ProbFile,+Call). For example: A,B,C,D,problog_kbest_save(A,100,B,E,C,D)
+ probability_initializer
Flag setting the ProbLog predicate to initialize probabilities.
The possible values for this flag are of the form: (+FactID,-P,+Call). For example: A,B,random_probability(A,B)
+ log_frequency
Flag telling whether to log results every nth iteration.
The possible values for this flag are any integer greater than zero.
+ alpha
Flag setting the weight of negative examples.
The possible values for this flag are number or "auto" (auto=n_p/n_n).
+ slope
Flag setting the slope of the sigmoid function.
The possible values for this flag are any real number greater than zero.
+ learning_rate
Flag setting the default Learning rate (if line_search=false)
The possible values for this flag are any number greater than zero or "examples``
+ line_search
Flag telling whether to use line search to estimate the learning rate.
The possible values for this flag are true or false.
+ line_search_tau
Flag setting the Tau value for line search.
The possible values for this flag are a number in the interval (0,1).
+ line_search_tolerance
Flag setting the tolerance value for line search.
The possible values for this flag are any number greater than zero.
+ line_search_interval
Flag setting the interval for line search.
*/
%% @}
:- module(problog, [problog_koptimal/3,
problog_koptimal/4,
problog_delta/5,
@ -3688,3 +4151,5 @@ user:term_expansion(Term,ExpandedTerm) :-
prolog_load_context(module,Mod),
problog:term_expansion_intern(Term,Mod,ExpandedTerm).
%% @}

View File

@ -226,4 +226,4 @@ semiring_multiplication((A1,A2),(B1,B2),(C1,C2)) :-
(0.2,0.2*1)::dir_edge(5,4).
%%% end case 4 %%%
*/
*/

@ -1 +1 @@
Subproject commit 3a80c7eb1120f5571933631d0e778df1602a6936
Subproject commit 6e84f300b550185e439c16079b4a6ec5925b1dc3

@ -1 +1 @@
Subproject commit 8a83f16c7b798e7eb9e75214f25015d787b91c66
Subproject commit 9caa663c7694094bafee1c055052ef8c771b5193

@ -1 +1 @@
Subproject commit 4aa1c28369a3003506aafafc9911d85683d58b2c
Subproject commit f086a96d77aa015e10484e161d7d23e51cb95635

@ -1 +1 @@
Subproject commit c34733e2127705ec20a0661245eb2d20b1494dc2
Subproject commit 373c30a0e81c72a1fa3cb28b971f075aae28b443

View File

@ -106,20 +106,23 @@
@defgroup MYDDAS The MYDDAS Data-base interface.
@ingroup YAPPackages
@{
The MYDDAS database project was developed within a FCT project aiming at
the development of a highly efficient deductive database system, based
on the coupling of the MySQL relational database system with the Yap
on the coupling of the MySQL relational database system with the YAP
Prolog system. MYDDAS was later expanded to support the ODBC interface.
@section Requirements_and_Installation_Guide Requirements and Installation Guide
*/
/** @defgroup Requirements_and_Installation_Guide Requirements and Installation Guide
ee
Next, we describe how to usen of the YAP with the MYDDAS System. The
use of this system is entirely depend of the MySQL development libraries
or the ODBC development libraries. At least one of the this development
libraries must be installed on the computer system, otherwise MYDDAS
will not compile. The MySQL development libraries from MySQL 3.23 an
above are know to work. We recommend the usage of MySQL versusODBC,
above are know to work. We recommend the usage of MySQL versus ODBC,
but it is possible to have both options installed
At the same time, without any problem. The MYDDAS system automatically
@ -128,20 +131,28 @@ problems in Linux. The usage of this system on Windows has not been
tested yet. MYDDAS must be enabled at configure time. This can be done
with the following options:
<ul>
+ --enable-myddas
This option will detect which development libraries are installed on the computer system, MySQL, ODBC or both, and will compile the Yap system with the support for which libraries it detects;
+ --enable-myddas-stats
<li>--enable-myddas
This option will detect which development libraries are installed on the computer system, MySQL, ODBC or both, and will compile the Yap system with the support for which libraries it detects;
+ --enable-myddas-stats
This option is only available in MySQL. It includes code to get
This option is only available in MySQL. It includes code to get
statistics from the MYDDAS system;
+ --enable-top-level
This option is only available in MySQL. It enables the option to interact with the MySQL server in
+ --enable-top-level
This option is only available in MySQL. It enables the option to interact with the MySQL server in
two different ways. As if we were on the MySQL Client Shell, and as if
we were using Datalog.
@}
*/
@section MYDDAS_Architecture MYDDAS Architecture
/** @defgroup MYDDAS_Architecture MYDDAS Architecture
@ingroup MYDDAS
@{
The system includes four main blocks that are put together through the
MYDDAS interface: the Yap Prolog compiler, the MySQL database system, an
@ -166,114 +177,8 @@ completely transparent. An example of this transparent support is the
Prolog cut operator, which has exactly the same behaviour from
predicates defined in the Prolog program source code, or from predicates
defined in database as relations.
@section Loading_MYDDAS Loading MYDDAS
Begin by starting YAP and loading the library
`use_module(library(myddas))`. This library already includes the
Prolog to SQL Compiler described in [2] and [1]. In MYDDAS this compiler
has been extended to support further constructs which allow a more
efficient SQL translation.
@section Connecting_to_and_disconnecting_from_a_Database_Server Connecting to and disconnecting from a Database Server
@pred db open(+,+,+,+,+).
@pred db open(+,+,+,+).
@pred db close(+).
Assuming the MySQL server is running and we have an account, we can
login to MySQL by invoking db_open/5 as one of the following:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
?- db_open(mysql,Connection,Host/Database,User,Password).
?- db_open(mysql,Connection,Host/Database/Port,User,Password).
?- db_open(mysql,Connection,Host/Database/UnixSocket,User,Password).
?- db_open(mysql,Connection,Host/Database/Port/UnixSocket,User,Password).
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If the login is successful, there will be a response of `yes`. For
instance:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
?- db_open(mysql,con1,localhost/guest_db,guest,'').
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
uses the MySQL native interface, selected by the first argument, to open
a connection identified by the `con1` atom, to an instance of a
MySQL server running on host `localhost`, using database guest `db`
and user `guest` with empty `password`. To disconnect from the `con1`
connection we use:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
?- db_close(con1).
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Alternatively, we can use `db_open/4` and `db_close/0,` without an argument
to identify the connection. In this case the default connection is used,
with atom `myddas`. Thus using
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
?- db_open(mysql,localhost/guest_db,guest,'').
?- db_close.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
or
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
?- db_open(mysql,myddas,localhost/guest_db,guest,'').
?- db_close(myddas).
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
is exactly the same.
MYDDAS also supports ODBC. To connect to a database using an ODBC driver
you must have configured on your system a ODBC DSN. If so, the `db_open/4`
and db_open/5 have the following mode:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
?- db_open(odbc,Connection,ODBC_DSN,User,Password).
?- db_open(odbc,ODBC_DSN,User,Password).
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
For instance, if you do `db_open(odbc,odbc_dsn,guest,'')`. it will connect
to a database, through ODBC, using the definitions on the `odbc_dsn` DSN
configured on the system. The user will be the user `guest` with no
password.
@section Accessing_a_Relation Accessing a Relation
@pred db_import(+Conn,+RelationName,+PredName).
@pred db_import(+RelationName,+PredName).
Assuming you have access permission for the relation you wish to import,
you can use db_import/3 or `db_import/2` as:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
?- db_import(Conn,RelationName,PredName).
?- db_import(RelationName,PredName).
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
where _RelationName_, is the name of
relation we wish to access, _PredName_ is the name of the predicate we
wish to use to access the relation from YAP. _Conn_, is the connection
identifier, which again can be dropped so that the default myddas connection
is used. For instance, if we want to access the relation phonebook,
using the predicate `phonebook/3` we write:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
?- db_import(con1,phonebook,phonebook).
yes
?- phonebook(Letter,Name,Number).
Letter = 'D',
Name = 'John Doe',
Number = 123456789 ?
yes
@ -297,7 +202,14 @@ FROM 'phonebook' A
WHERE A.Name = 'John Doe';
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@section View_Level_Interface View Level Interface
@}
*/
/** @defgroup View_Level_Interface View Level Interface
@ingroup MYDDAS
@{
@pred db view(+,+,+).
@ -390,7 +302,14 @@ FROM Edge A WHERE A.attr1 = 10;
To know how to use db `view/3`, please refer to Draxler's Prolog to
SQL Compiler Manual.
@section Accessing_Tables_in_Data_Sources_Using_SQL Accessing Tables in Data Sources Using SQL
@}
*/
/** @defgroup Accessing_Tables_in_Data_Sources_Using_SQL Accessing Tables in Data Sources Using SQL
@ingroup MYDDAS
@{
@pred db_sql(+,+,?).
@ -493,7 +412,13 @@ yes
yes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@section Types_of_Attributes Types of Attributes
@}
*/
/** @defgroup Types_of_Attributes Types of AttributesL
@ingroup MYDDAS
@{
@pred db_get_attributes_types(+,+,?).
@ -524,7 +449,14 @@ yes
where <tt>Hello World</tt> is the name of the relation and <tt>myddas</tt> is the
connection identifier.
@section Number_of_Fields Number of Fields
@}
*/
/** @defgroup Number_of_Fields Number of Fields
@ingroup MYDDAS
@{
@pred db_number_of_fields(+,?).
@ -553,7 +485,14 @@ yes
where `Hello World` is the name of the
relation and `myddas` is the connection identifier.
@section Describing_a_Relation Describing a Relation
@}
*/
/** @defgroup Describing_a_Relation Describing a Relation
@ingroup MYDDAS
@{
@pred db_datalog_describe(+,+).
@ -598,7 +537,14 @@ Term = tableInfo('Letter',char(1),'YES','',null(2),'') ? ;
no
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@section Enumerating_Relations Enumeration Relations
@}
*/
/** @defgroup Enumerating_Relations Enumeration Relations Describing_a_Relation Describing a Relation
@ingroup MYDDAS
@{
@pred db_datalog_show_tables(+).
@pred db_datalog_show_tables
@ -638,7 +584,14 @@ Table = table('Hello World') ? ;
no
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@section The_MYDDAS_MySQL_Top_Level The MYDDAS MySQL Top Level
@}
*/
/** @defgroup The_MYDDAS_MySQL_Top_Level The MYDDAS MySQL Top Level
@ingroup MYDDAS
@{
@pred db_top_level(+,+,+,+,+).
@ -691,8 +644,15 @@ Bye
yes
?-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@}
*/
/** @defgroup Other_MYDDAS_Properties Other MYDDAS Properties
@ingroup MYDDAS
@{
@section Other_MYDDAS_Properties Other MYDDAS Properties
@pred db_verbose(+).
@pred db_top_level(+,+,+,+).

@ -1 +1 @@
Subproject commit 8497465ab06f0991add8c5928ff11904ae204d51
Subproject commit c70811ad67640151b4f2edc523136469fedf6a8c

View File

@ -31,6 +31,7 @@
:- dynamic( sqlite_db:sqlite_asserted/4 ).
/** <module> proSQLite: a Prolog interface to the SQLite database system.
\ingroup SWILibrary
This library follows the design and borrows code from the ODBC library of SWI-Prolog
http://www.swi-prolog.org/pldoc/packasqlite_connectge/odbc.html .

@ -1 +1 @@
Subproject commit e5bbf54db21189a5c56e0201433cffbf7e959147
Subproject commit 92887835dfc6b4a07bac4d56966470fd159d3afc

View File

@ -37,11 +37,130 @@
% :- yap_flag(unknown,error).
% :- style_check(single_var).
/**
@defgroup YAP-LBFGS
@ingroup YAPPackages
@short What is YAP-LBFGS? YAP-LBFGS is an interface to call libLBFGS, http://www.chokkan.org/software/liblbfgs/, from within
YAP. libLBFGS is a C library for Limited-memory
Broyden-Fletcher-Goldfarb-Shanno (L-BFGS) solving the under-constrained
minimization problem:
+ minimize `F(X), X=(x1,x2,..., xN)`
### Contact</h2>
YAP-LBFGS has been developed by Bernd Gutmann. In case you publish something using YAP-LBFGS, please give credit to me and to libLBFGS. And if you find YAP-LBFGS useful, or if you find a bug, or if you
port it to another system, ... please send me an email.
### License
+ YAP-LBFGS is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
+ YAP-LBFGS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
### Usage</h2>
The module lbfgs provides the following predicates after you loaded
it by
~~~~
:-use_module(library(lbfgs)).
~~~~
+ use optimizer_set_paramater(Name,Value) to change parameters
+ use optimizer_get_parameter(Name,Value) to see current parameters
+ use optimizer_parameters to print this overview
### Demo
The following Prolog program, ex1.pl, searches for minimas of the
function `f(x0)=sin(x0)`. In order to do so, it provides the
call back predicate <span class="code">evaluate` which
calculates `f(x0)` and the gradient `d/dx0 f=cos(x0)`.
~~~~~
:- use_module(lbfgs).
% This is the call back function which evaluates F and the gradient of F
evaluate(FX,_N,_Step) :-
optimizer_get_x(0,X0),
FX is sin(X0),
G0 is cos(X0),
optimizer_set_g(0,G0).
% This is the call back function which is invoked to report the progress
% if the last argument is set to anything else than 0, the optimizer will
% stop right now
progress(FX,X_Norm,G_Norm,Step,_N,Iteration,Ls,0) :-
optimizer_get_x(0,X0),
format('~d. Iteration : x0=~4f f(X)=~4f |X|=~4f
|X\'|=~4f Step=~4f Ls=~4f~n',
[Iteration,X0,FX,X_Norm,G_Norm,Step,Ls]).
demo :-
format('Optimizing the function f(x0) = sin(x0)~n',[]),
optimizer_initialize(1,evaluate,progress),
StartX is random*10,
format('We start the search at the random position x0=~5f~2n',[StartX]),
optimizer_set_x(0,StartX),
optimizer_run(BestF,Status),
optimizer_get_x(0,BestX0),
optimizer_finalize,
format('~2nOptimization done~nWe found a minimum at
f(~f)=~f~2nLBFGS Status=~w~n',[BestX0,BestF,Status]).
~~~~~
The output of this program is something like:
~~~~~
?- demo.
Optimizing the function f(x0) = sin(x0)
We start the search at the random position x0=7.24639
1. Iteration : x0=5.0167 f(X)=-0.9541 |X|=5.0167 |X'|=0.2996 Step=3.9057 Ls=3.0000
2. Iteration : x0=4.7708 f(X)=-0.9983 |X|=4.7708 |X'|=0.0584 Step=0.0998 Ls=2.0000
3. Iteration : x0=4.7113 f(X)=-1.0000 |X|=4.7113 |X'|=0.0011 Step=1.0000 Ls=1.0000
4. Iteration : x0=4.7124 f(X)=-1.0000 |X|=4.7124 |X'|=0.0000 Step=1.0000 Ls=1.0000
Optimization done
We found a minimum at f(4.712390)=-1.000000
LBFGS Status=0
yes
?-
~~~~~
@{
*/
:- dynamic initialized/0.
:- load_foreign_files(['yap_lbfgs'],[],'init_lbfgs_predicates').
/** @pred optimizer_initialize(+N,+Evaluate,+Progress)
The same as before, except that the user module is the default
value.
Example
~~~~
optimizer_initialize(1,evaluate,progress)
~~~~~
*/
optimizer_initialize(N,Call_Evaluate,Call_Progress) :-
optimizer_initialize(N,user,Call_Evaluate,Call_Progress).
optimizer_initialize(N,Module,Call_Evaluate,Call_Progress) :-
@ -67,6 +186,9 @@ optimizer_initialize(N,Module,Call_Evaluate,Call_Progress) :-
assert( (user:'$lbfgs_callback_progress'(P1,P2,P3,P4,P5,P6,P7,P8) :- Module:ProgressGoal, !) ),
assert(initialized).
/** @pred optimizer_finalize/0
Clean up the memory.
*/
optimizer_finalize :-
initialized,
optimizer_free_memory,
@ -74,6 +196,34 @@ optimizer_finalize :-
retractall(user:'$lbfgs_callback_progress'(_,_,_,_,_,_,_,_)),
retractall(initialized).
/** @pred optimizer_parameters/0
Prints a table with the current parameters. See the <a href="http://www.chokkan.org/software/liblbfgs/structlbfgs__parameter__t.html#_details">documentation
of libLBFGS</a> for the meaning of each parameter.
~~~~
?- optimizer_parameters.
==========================================================================================
Type Name Value Description
==========================================================================================
int m 6 The number of corrections to approximate the inverse hessian matrix.
float epsilon 1e-05 Epsilon for convergence test.
int past 0 Distance for delta-based convergence test.
float delta 1e-05 Delta for convergence test.
int max_iterations 0 The maximum number of iterations
int linesearch 0 The line search algorithm.
int max_linesearch 40 The maximum number of trials for the line search.
float min_step 1e-20 The minimum step of the line search routine.
float max_step 1e+20 The maximum step of the line search.
float ftol 0.0001 A parameter to control the accuracy of the line search routine.
float gtol 0.9 A parameter to control the accuracy of the line search routine.
float xtol 1e-16 The machine precision for floating-point values.
float orthantwise_c 0.0 Coefficient for the L1 norm of variables
int orthantwise_start 0 Start index for computing the L1 norm of the variables.
int orthantwise_end -1 End index for computing the L1 norm of the variables.
==========================================================================================
~~~~
*/
optimizer_parameters :-
optimizer_get_parameter(m,M),
optimizer_get_parameter(epsilon,Epsilon),

View File

@ -141,7 +141,10 @@ static int progress(
return 1;
}
/** @pred optimizer_set_x(+I,+X)
Set the current value for `x[I]`. Only possible when the optimizer is
initialized but not running.
*/
static int set_x_value(void) {
YAP_Term t1=YAP_ARG1;
YAP_Term t2=YAP_ARG2;
@ -175,6 +178,10 @@ static int set_x_value(void) {
return TRUE;
}
/** @pred optimizer_get_x(+I,-X)
Get the current value for `x[I]`. Only possible when the optimizer is
initialized or running.
*/
static int get_x_value(void) {
YAP_Term t1=YAP_ARG1;
YAP_Term t2=YAP_ARG2;
@ -202,6 +209,10 @@ static int get_x_value(void) {
/** @pred optimizer_set_g(+I,+G) Set the current value for `g[I]` (the
partial derivative of _F_ with respect to `x[I]`). Can only be called
from the evaluate call back predicate.
*/
static int set_g_value(void) {
YAP_Term t1=YAP_ARG1;
YAP_Term t2=YAP_ARG2;
@ -235,6 +246,10 @@ static int set_g_value(void) {
return TRUE;
}
/** @pred optimizer_get_g(+I,-G)
Get the current value for `g[I]` (the partial derivative of _F_ with respect to `x[I]`). Only possible when the optimizer is
initialized or running.
*/
static int get_g_value(void) {
YAP_Term t1=YAP_ARG1;
YAP_Term t2=YAP_ARG2;
@ -258,7 +273,47 @@ static int get_g_value(void) {
return YAP_Unify(t2,YAP_MkFloatTerm(g[i]));
}
/** @pred optimizer_initialize(+N,+Module,+Evaluate,+Progress)
Create space to optimize a function with _N_ variables (_N_ has to be
integer).
+ _Module</span>_ is the name of the module where the call back
predicates can be found,
+ _Evaluate_ is the call back predicate (arity 3)
to evaluate the function math <span class="math">_F</span>_,
+ _Progress_ is the call back predicate invoked
(arity 8) after every iteration
Example
~~~~
optimizer_initialize(1,user,evaluate,progress)</span>
~~~~
The evaluate call back predicate has to be of the type
`evaluate(-F,+N,+Step)`. It has to calculate the current function
value _F_. _N_ is the
size of the parameter vector (the value which was used to initialize
LBFGS) and _Step_ is the current state of the
line search. The call back predicate can access the current values of
`x[i]` by calling `optimizer_get_x(+I,-Xi)`. Finally, the call back
predicate has to calculate the gradient of _F</span>_
and set its value by calling `optimizer_set_g(+I,+Gi)` for every `1<=I<=N`.
The progress call back predicate has to be of the type
`progress(+F,+X_Norm,+G_Norm,+Step,+N,+Iteration,+LS,-Continue)`. It
is called after every iteration. The call back predicate can access
the current values of _X_ and of the gradient by calling
`optimizer_get_x(+I,-Xi)` and `optimizer_get_g`(+I,-Gi)`
respectively. However, it must not call the setter predicates for <span
class="code"_X_ or _G_. If it tries to do so, the optimizer will
terminate with an error. If _Continue_ is set to 0 (int) the
optimization process will continue for one more iteration, any other
value will terminate the optimization process.
*/
static int optimizer_initialize(void) {
YAP_Term t1 = YAP_ARG1;
int temp_n=0;
@ -293,6 +348,14 @@ static int optimizer_initialize(void) {
return TRUE;
}
/** @pred optimizer_run(-F,-Status)
Runs the optimization, _F is the best (minimal) function value and
Status (int) is the status code returned by libLBFGS. Anything except
0 indicates an error, see the documentation of libLBFGS for the
meaning.
*/
static int optimizer_run(void) {
int ret = 0;
YAP_Term t1 = YAP_ARG1;
@ -352,6 +415,10 @@ static int optimizer_finalize( void ) {
/** @pred optimizer_set_parameter(+Name,+Value)
Set the parameter Name to Value. Only possible while the optimizer
is not running.
*/
static int optimizer_set_parameter( void ) {
YAP_Term t1 = YAP_ARG1;
YAP_Term t2 = YAP_ARG2;
@ -507,6 +574,11 @@ static int optimizer_set_parameter( void ) {
return TRUE;
}
/** @pred optimizer_get_parameter(+Name,-Value)</h3>
Get the current Value for Name
*/
static int optimizer_get_parameter( void ) {
YAP_Term t1 = YAP_ARG1;
YAP_Term t2 = YAP_ARG2;

@ -1 +1 @@
Subproject commit d9488412c50ea2f9df0747ec100737808cd71a5b
Subproject commit 63368e2b9f066d224b534d213fd34c20f353a94b

View File

@ -32,14 +32,17 @@ implementing constraint handlers, such as Holzbaur's CLPQR, Fruewirth
and Holzbaur's CHR, and CLP(BN).
Different Prolog systems implement attributed variables in different
ways. Traditionally, YAP has used the interface designed by SICStus
ways. Originally, YAP used the interface designed by SICStus
Prolog. This interface is still
available in the <tt>atts</tt> library, but from YAP-6.0.3 we recommend using
the hProlog, SWI style interface. The main reason to do so is that
most packages included in YAP that use attributed variables, such as CHR, CLP(FD), and CLP(QR),
rely on the SWI-Prolog interface.
available through the <tt>atts</tt> library, and is still used by CLPBN.
From YAP-6.0.3 onwards we recommend using the hProlog, SWI style
interface. We believe that this design is easier to understand and
work with. Most packages included in YAP that use attributed
variables, such as CHR, CLP(FD), and CLP(QR), rely on the SWI-Prolog
interface.
@{
*/
@ -114,23 +117,10 @@ example). The nonterminal `attribute_goals/3` is used to translate
remaining attributes to user-readable goals that, when executed, reinstate
these attributes.
@pred put_attr(+ _Var_,+ _Module_,+ _Value_)
If _Var_ is a variable or attributed variable, set the value for the
attribute named _Module_ to _Value_. If an attribute with this
name is already associated with _Var_, the old value is replaced.
Backtracking will restore the old value (i.e., an attribute is a mutable
term. See also `setarg/3`). This predicate raises a representation error if
_Var_ is not a variable and a type error if _Module_ is not an atom.
*/
:- module('$attributes', [
delayed_goals/4
]).
@ -173,6 +163,20 @@ prolog:get_attr(Var, Mod, Att) :-
arg(2, AttTerm, Att),
attributes:get_module_atts(Var, AttTerm).
/**
@pred put_attr(+ _Var_,+ _Module_,+ _Value_)
If _Var_ is a variable or attributed variable, set the value for the
attribute named _Module_ to _Value_. If an attribute with this
name is already associated with _Var_, the old value is replaced.
Backtracking will restore the old value (i.e., an attribute is a mutable
term. See also `setarg/3`). This predicate raises a representation error if
_Var_ is not a variable and a type error if _Module_ is not an atom.
*/
prolog:put_attr(Var, Mod, Att) :-
functor(AttTerm, Mod, 2),
arg(2, AttTerm, Att),
@ -227,6 +231,46 @@ cvt_to_swi_atts(att(Mod,Attribute,Atts), ModAttribute) :-
ModAttribute =.. [Mod, YapAtts, Attribute],
cvt_to_swi_atts(Atts, YapAtts).
/** @pred copy_term(? _TI_,- _TF_,- _Goals_)
Term _TF_ is a variant of the original term _TI_, such that for
each variable _V_ in the term _TI_ there is a new variable _V'_
in term _TF_ without any attributes attached. Attributed
variables are thus converted to standard variables. _Goals_ is
unified with a list that represents the attributes. The goal
`maplist(call, _Goals_)` can be called to recreate the
attributes.
Before the actual copying, `copy_term/3` calls
`attribute_goals/1` in the module where the attribute is
defined.
*/
prolog:copy_term(Term, Copy, Gs) :-
term_attvars(Term, Vs),
( Vs == []
-> Gs = [],
copy_term(Term, Copy)
; findall(Term-Gs,
'$attributes':residuals_and_delete_attributes(Vs, Gs, Term),
[Copy-Gs])
).
residuals_and_delete_attributes(Vs, Gs, Term) :-
attvars_residuals(Vs, Gs, []),
delete_attributes(Term).
attvars_residuals([]) --> [].
attvars_residuals([V|Vs]) -->
( { get_attrs(V, As) }
-> attvar_residuals(As, V)
; []
),
attvars_residuals(Vs).
%% @}
%
% wake_up_goal is called by the system whenever a suspended goal
% resumes.
@ -341,10 +385,6 @@ dif(X,Y) ? ;
no
~~~~~
*/
prolog:call_residue_vars(Goal,Residue) :-
attributes:all_attvars(Vs0),
@ -369,53 +409,6 @@ prolog:call_residue_vars(Goal,Residue) :-
'$ord_remove'([V1|Vss], Vs0s, Residue)
).
%% from SWI
%% copy_term(+Term, -Copy, -Gs) is det.
%
% Creates a regular term Copy as a copy of Term (without any
% attributes), and a list Gs of goals that when executed reinstate
% all attributes onto Copy. The nonterminal attribute_goals//1, as
% defined in the modules the attributes stem from, is used to
% convert attributes to lists of goals.
/** @pred copy_term(? _TI_,- _TF_,- _Goals_)
Term _TF_ is a variant of the original term _TI_, such that for
each variable _V_ in the term _TI_ there is a new variable _V'_
in term _TF_ without any attributes attached. Attributed
variables are thus converted to standard variables. _Goals_ is
unified with a list that represents the attributes. The goal
`maplist(call, _Goals_)` can be called to recreate the
attributes.
Before the actual copying, `copy_term/3` calls
`attribute_goals/1` in the module where the attribute is
defined.
*/
prolog:copy_term(Term, Copy, Gs) :-
term_attvars(Term, Vs),
( Vs == []
-> Gs = [],
copy_term(Term, Copy)
; findall(Term-Gs,
'$attributes':residuals_and_delete_attributes(Vs, Gs, Term),
[Copy-Gs])
).
residuals_and_delete_attributes(Vs, Gs, Term) :-
attvars_residuals(Vs, Gs, []),
delete_attributes(Term).
attvars_residuals([]) --> [].
attvars_residuals([V|Vs]) -->
( { get_attrs(V, As) }
-> attvar_residuals(As, V)
; []
),
attvars_residuals(Vs).
/** @pred _Module_:attribute_goal( _-Var_, _-Goal_)
User-defined procedure, called to convert the attributes in _Var_ to

View File

@ -17,7 +17,7 @@
:- use_system_module( '$_errors', ['$do_error'/2]).
/** @defgroup Tabling Tabling
@ingroup YAPBuiltins
@ingroup YAPExtensions
@{
*YAPTab* is the tabling engine that extends YAP's execution

View File

@ -16,8 +16,20 @@
*************************************************************************/
/**
@ingroup Threads
@addtogroup Threads
@defgroup Threads Threads
@ingroup YAPExtensions
@{
@page YAPThreads Threads in YAP
YAP implements a SWI-Prolog compatible multithreading
library. Like in SWI-Prolog, Prolog threads have their own stacks and
only share the Prolog <em>heap</em>: predicates, records, flags and other
global non-backtrackable data. The package is based on the POSIX thread
standard (Butenhof:1997:PPT) used on most popular systems except
for MS-Windows.
*/
:- system_module( '$_threads', [current_mutex/3,
@ -70,57 +82,7 @@
:- use_system_module( '$_errors', ['$do_error'/2]).
/** @pred thread_at_exit(: _Term_)
Run _Goal_ just before releasing the thread resources. This is to
be compared to `at_halt/1`, but only for the current
thread. These hooks are ran regardless of why the execution of the
thread has been completed. As these hooks are run, the return-code is
already available through thread_property/2 using the result of
thread_self/1 as thread-identifier. If you want to guarantee the
execution of an exit hook no matter how the thread terminates (the thread
can be aborted before reaching the thread_at_exit/1 call), consider
using instead the `at_exit/1` option of thread_create/3.
*/
/** @pred thread_create(: _Goal_)
Create a new Prolog detached thread using default options. See thread_create/3.
*/
/** @pred thread_create(: _Goal_, - _Id_)
Create a new Prolog thread using default options. See thread_create/3.
*/
/** @pred thread_signal(+ _ThreadId_, : _Goal_)
Make thread _ThreadId_ execute _Goal_ at the first
opportunity. In the current implementation, this implies at the first
pass through the <em>Call-port</em>. The predicate thread_signal/2
itself places _Goal_ into the signalled-thread's signal queue
and returns immediately.
Signals (interrupts) do not cooperate well with the world of
multi-threading, mainly because the status of mutexes cannot be
guaranteed easily. At the call-port, the Prolog virtual machine
holds no locks and therefore the asynchronous execution is safe.
_Goal_ can be any valid Prolog goal, including throw/1 to make
the receiving thread generate an exception and trace/0 to start
tracing the receiving thread.
*/
:- meta_predicate
thread_initialization(0),
thread_at_exit(0),
@ -146,6 +108,12 @@ volatile(P) :-
'$do_volatile'(P,M) :- dynamic(M:P).
/** @defgroup Creating_and_Destroying_Prolog_Threads Creating and Destroying Prolog Threads
@ingroup Threads
@{
*/
:- initialization('$init_thread0').
'$init_thread0' :-
@ -195,6 +163,12 @@ volatile(P) :-
recorda(Key, exception(Stat), _)
).
/** @pred thread_create(: _Goal_)
Create a new Prolog detached thread using default options. See thread_create/3.
*/
thread_create(Goal) :-
G0 = thread_create(Goal),
'$check_callable'(Goal, G0),
@ -211,6 +185,13 @@ thread_create(Goal) :-
recorda(Key, exception(resource_error(memory)),_)
).
/** @pred thread_create(: _Goal_, - _Id_)
Create a new Prolog thread using default options. See thread_create/3.
*/
thread_create(Goal, Id) :-
G0 = thread_create(Goal, Id),
'$check_callable'(Goal, G0),
@ -228,6 +209,49 @@ thread_create(Goal, Id) :-
recorda(Key, exception(resource_error(memory)),_)
).
/**
@pred thread_create(: _Goal_, - _Id_, + _Options_)
Create a new Prolog thread (and underlying C-thread) and start it
by executing _Goal_. If the thread is created successfully, the
thread-identifier of the created thread is unified to _Id_.
_Options_ is a list of options. Currently defined options are:
+ stack
Set the limit in K-Bytes to which the Prolog stacks of
this thread may grow. If omitted, the limit of the calling thread is
used. See also the commandline `-S` option.
+ trail
Set the limit in K-Bytes to which the trail stack of this thread may
grow. If omitted, the limit of the calling thread is used. See also the
commandline option `-T`.
+ alias
Associate an alias-name with the thread. This named may be used to
refer to the thread and remains valid until the thread is joined
(see thread_join/2).
+ at_exit
Define an exit hook for the thread. This hook is called when the thread
terminates, no matter its exit status.
+ detached
If `false` (default), the thread can be waited for using
thread_join/2. thread_join/2 must be called on this thread
to reclaim the all resources associated to the thread. If `true`,
the system will reclaim all associated resources automatically after the
thread finishes. Please note that thread identifiers are freed for reuse
after a detached thread finishes or a normal thread has been joined.
See also thread_join/2 and thread_detach/1.
The _Goal_ argument is <em>copied</em> to the new Prolog engine.
This implies further instantiation of this term in either thread does
not have consequences for the other thread: Prolog threads do not share
data from their stacks.
*/
thread_create(Goal, Id, Options) :-
G0 = thread_create(Goal, Id, Options),
'$check_callable'(Goal,G0),
@ -540,11 +564,46 @@ thread_exit(Term) :-
fail.
'$run_at_thread_exit'(_).
/** @pred thread_at_exit(: _Term_)
Run _Goal_ just before releasing the thread resources. This is to
be compared to `at_halt/1`, but only for the current
thread. These hooks are ran regardless of why the execution of the
thread has been completed. As these hooks are run, the return-code is
already available through thread_property/2 using the result of
thread_self/1 as thread-identifier. If you want to guarantee the
execution of an exit hook no matter how the thread terminates (the thread
can be aborted before reaching the thread_at_exit/1 call), consider
using instead the `at_exit/1` option of thread_create/3.
*/
thread_at_exit(Goal) :-
'$check_callable'(Goal,thread_at_exit(Goal)),
'$thread_self'(Id0),
recordz('$thread_exit_hook',[Id0|Goal],_).
/**
@}
*/
/**
@defgroup Monitoring_Threads Monitoring Threads
@ingroup Threads
Normal multi-threaded applications should not need these the predicates
from this section because almost any usage of these predicates is
unsafe. For example checking the existence of a thread before signalling
it is of no use as it may vanish between the two calls. Catching
exceptions using catch/3 is the only safe way to deal with
thread-existence errors.
These predicates are provided for diagnosis and monitoring tasks.
@{
*/
/** @pred current_thread(+ _Id_, - _Status_)
@ -591,6 +650,238 @@ current_thread(Id, Status) :-
'$mutex_id_alias'(Id, Id).
thread_property(Prop) :-
'$check_thread_property'(Prop, thread_property(Prop)),
'$thread_self'(Id),
'$thread_property'(Prop, Id).
/** @pred thread_property(? _Id_, ? _Property_)
Enumerates the properties of the specified thread.
Calling thread_property/2 does not influence any thread. See also
thread_join/2. For threads that have an alias-name, this name can
be used in _Id_ instead of the numerical thread identifier.
_Property_ is one of:
+ status( _Status_)
The thread status of a thread (see below).
+ alias( _Alias_)
The thread alias, if it exists.
+ at_exit( _AtExit_)
The thread exit hook, if defined (not available if the thread is already terminated).
+ detached( _Boolean_)
The detached state of the thread.
+ stack( _Size_)
The thread stack data-area size.
+ trail( _Size_)
The thread trail data-area size.
+ system( _Size_)
The thread system data-area size.
*/
thread_property(Id, Prop) :-
( nonvar(Id) ->
'$check_thread_or_alias'(Id, thread_property(Id, Prop))
; '$enumerate_threads'(Id)
),
'$check_thread_property'(Prop, thread_property(Id, Prop)),
'$thread_id_alias'(Id0, Id),
'$thread_property'(Prop, Id0).
'$enumerate_threads'(Id) :-
'$max_threads'(Max),
Max1 is Max-1,
between(0,Max1,Id),
'$thread_stacks'(Id, _, _, _).
'$thread_property'(alias(Alias), Id) :-
recorded('$thread_alias', [Id|Alias], _).
'$thread_property'(status(Status), Id) :-
'$mk_tstatus_key'(Id, Key),
( recorded(Key, Exit, _) ->
Status = Exit
; Status = running
).
'$thread_property'(detached(Detached), Id) :-
( '$thread_detached'(Id,Detached) -> true ; Detached = false ).
'$thread_property'(at_exit(M:G), Id) :-
'$thread_run_at_exit'(G,M).
'$thread_property'(stack(Stack), Id) :-
'$thread_stacks'(Id, Stack, _, _).
'$thread_property'(trail(Trail), Id) :-
'$thread_stacks'(Id, _, Trail, _).
'$thread_property'(system(System), Id) :-
'$thread_stacks'(Id, _, _, System).
threads :-
format(user_error,'------------------------------------------------------------------------~n',[]),
format(user_error, '~t~a~48+~n', 'Thread Detached Status'),
format(user_error,'------------------------------------------------------------------------~n',[]),
thread_property(Id, detached(Detached)),
thread_property(Id, status(Status)),
'$thread_id_alias'(Id, Alias),
format(user_error,'~t~q~30+~33|~w~42|~q~n', [Alias, Detached, Status]),
fail.
threads :-
format(user_error,'------------------------------------------------------------------------~n',[]).
'$check_thread_or_alias'(Term, Goal) :-
var(Term), !,
'$do_error'(instantiation_error, Goal).
'$check_thread_or_alias'(Term, Goal) :-
\+ integer(Term), \+ atom(Term), !,
'$do_error'(domain_error(thread_or_alias, Term), Goal).
'$check_thread_or_alias'(Term, Goal) :-
atom(Term), \+ recorded('$thread_alias',[_|Term],_), !,
'$do_error'(existence_error(thread, Term), Goal).
'$check_thread_or_alias'(Term, Goal) :-
integer(Term), \+ '$valid_thread'(Term), !,
'$do_error'(existence_error(thread, Term), Goal).
'$check_thread_or_alias'(_,_).
'$check_thread_property'(Term, _) :-
var(Term), !.
'$check_thread_property'(alias(_), _) :- !.
'$check_thread_property'(detached(_), _) :- !.
'$check_thread_property'(at_exit(_), _) :- !.
'$check_thread_property'(status(_), _) :- !.
'$check_thread_property'(stack(_), _) :- !.
'$check_thread_property'(trail(_), _) :- !.
'$check_thread_property'(system(_), _) :- !.
'$check_thread_property'(Term, Goal) :-
'$do_error'(domain_error(thread_property, Term), Goal).
'$check_mutex_or_alias'(Term, Goal) :-
var(Term), !,
'$do_error'(instantiation_error, Goal).
'$check_mutex_or_alias'(Term, Goal) :-
\+ integer(Term), \+ atom(Term), !,
'$do_error'(domain_error(mutex_or_alias, Term), Goal).
'$check_mutex_or_alias'(Term, Goal) :-
atom(Term), \+ recorded('$mutex_alias',[_|Term],_), !,
'$do_error'(existence_error(mutex, Term), Goal).
'$check_mutex_or_alias'(Term, Goal) :-
% integer(Term), \+ '$valid_mutex'(Term), !,
integer(Term), \+ recorded('$mutex_alias',[Term|_],_), !,
'$do_error'(existence_error(mutex, Term), Goal).
'$check_mutex_or_alias'(_,_).
'$check_mutex_property'(Term, _) :-
var(Term), !.
'$check_mutex_property'(alias(_), _) :- !.
'$check_mutex_property'(status(Status), Goal) :- !,
( var(Status) ->
true
; Status = unlocked ->
true
; Status = locked(_, _) ->
true
; '$do_error'(domain_error(mutex_property, status(Status)), Goal)
).
'$check_mutex_property'(Term, Goal) :-
'$do_error'(domain_error(mutex_property, Term), Goal).
'$mk_tstatus_key'(Id0, Key) :-
atomic_concat('$thread_exit_status__',Id0,Key).
/** @pred thread_statistics(+ _Id_, + _Key_, - _Value_)
Obtains statistical information on thread _Id_ as `statistics/2`
does in single-threaded applications. This call returns all keys
of `statistics/2`, although only information statistics about the
stacks and CPU time yield different values for each thread.
+ mutex_statistics
Print usage statistics on internal mutexes and mutexes associated
with dynamic predicates. For each mutex two numbers are printed:
the number of times the mutex was acquired and the number of
collisions: the number times the calling thread has to
wait for the mutex. The collision-count is not available on
Windows as this would break portability to Windows-95/98/ME or
significantly harm performance. Generally collision count is
close to zero on single-CPU hardware.
+ threads
Prints a table of current threads and their status.
*/
thread_statistics(Id, Key, Val) :-
format("not implemented yet~n",[]).
%% @}
/** @defgroup Signalling_Threads Signalling Threads
@ingroup Threadas
These predicates provide a mechanism to make another thread execute some
goal as an <em>interrupt</em>. Signalling threads is safe as these
interrupts are only checked at safe points in the virtual machine.
Nevertheless, signalling in multi-threaded environments should be
handled with care as the receiving thread may hold a <em>mutex</em>
(see with_mutex/2). Signalling probably only makes sense to start
debugging threads and to cancel no-longer-needed threads with throw/1,
where the receiving thread should be designed carefully do handle
exceptions at any point.
@}
*/
/** @defgroup Thread_Synchronisation Thread Synchronisation
@ingroup Threads
@{
All
internal Prolog operations are thread-safe. This implies two Prolog
threads can operate on the same dynamic predicate without corrupting the
consistency of the predicate. This section deals with user-level
<em>mutexes</em> (called <em>monitors</em> in ADA or
<em>critical-sections</em> by Microsoft). A mutex is a
<em>MUT</em>ual <em>EX</em>clusive device, which implies at most one thread
can <em>hold</em> a mutex.
Mutexes are used to realise related updates to the Prolog database.
With `related', we refer to the situation where a `transaction' implies
two or more changes to the Prolog database. For example, we have a
predicate `address/2`, representing the address of a person and we want
to change the address by retracting the old and asserting the new
address. Between these two operations the database is invalid: this
person has either no address or two addresses, depending on the
assert/retract order.
Here is how to realise a correct update:
~~~~~
:- initialization
mutex_create(addressbook).
change_address(Id, Address) :-
mutex_lock(addressbook),
retractall(address(Id, _)),
asserta(address(Id, Address)),
mutex_unlock(addressbook).
~~~~~
*/
/** @pred mutex_create(? _MutexId_)
@ -849,6 +1140,23 @@ mutex_property(Mutex, Prop) :-
Status = locked(Thread, Count)
).
%% @}
/** @defgroup Thread_Communication Thread communication
@ingroup Threads
Prolog threads can exchange data using dynamic predicates, database
records, and other globally shared data. These provide no suitable means
to wait for data or a condition as they can only be checked in an
expensive polling loop. <em>Message queues</em> provide a means for
threads to wait for data or conditions without using the CPU.
Each thread has a message-queue attached to it that is identified
by the thread. Additional queues are created using
`message_queue_create/2`.
@{
*/
message_queue_create(Id, Options) :-
nonvar(Id), !,
@ -1018,6 +1326,13 @@ message_queue_property(Id, Prop) :-
recorded('$queue', q(Alias,_,_,Id,_), _).
/** @pred thread_send_message(+ _Term_)
Places _Term_ in the message-queue of the thread running the goal.
Any term can be placed in a message queue, but note that the term is
copied to the receiving thread and variable-bindings are thus lost.
This call returns immediately.
*/
thread_send_message(Term) :-
'$thread_self'(Id),
thread_send_message(Id, Term).
@ -1201,6 +1516,94 @@ thread_peek_message(Queue, Term) :-
'$unlock_mutex'(Mutex),
fail.
/** @defgroup Signalling_Threads Signalling Threads
@ingroup Threadas
These predicates provide a mechanism to make another thread execute some
goal as an <em>interrupt</em>. Signalling threads is safe as these
interrupts are only checked at safe points in the virtual machine.
Nevertheless, signalling in multi-threaded environments should be
handled with care as the receiving thread may hold a <em>mutex</em>
(see with_mutex/2). Signalling probably only makes sense to start
debugging threads and to cancel no-longer-needed threads with throw/1,
where the receiving thread should be designed carefully do handle
exceptions at any point.
@{
*/
/** @pred thread_sleep(+ _Time_)
Make current thread sleep for _Time_ seconds. _Time_ may be an
integer or a floating point number. When time is zero or a negative value
the call succeeds and returns immediately. This call should not be used if
alarms are also being used.
*/
thread_sleep(Time) :-
var(Time), !,
'$do_error'(instantiation_error,thread_sleep(Time)).
thread_sleep(Time) :-
integer(Time), !,
( Time > 0 ->
'$thread_sleep'(Time,0,_,_)
; true
).
thread_sleep(Time) :-
float(Time), !,
( Time > 0.0 ->
STime is integer(float_integer_part(Time)),
NTime is integer(float_fractional_part(Time))*1000000000,
'$thread_sleep'(STime,NTime,_,_)
; true
).
thread_sleep(Time) :-
'$do_error'(type_error(number,Time),thread_sleep(Time)).
thread_signal(Id, Goal) :-
'$check_thread_or_alias'(Id, thread_signal(Id, Goal)),
'$check_callable'(Goal, thread_signal(Id, Goal)),
'$thread_id_alias'(Id0, Id),
( recorded('$thread_signal', [Id0| _], R), erase(R), fail
; true
),
recorda('$thread_signal', [Id0| Goal], _),
'$signal_thread'(Id0).
'$thread_gfetch'(G) :-
'$thread_self'(Id),
recorded('$thread_signal',[Id|G],R),
erase(R).
%% @}
/** @defgroup Threads_and_Dynamic_Predicates Threads and Dynamic Predicates
@ingroup Threads
@{
Besides queues threads can share and exchange data using dynamic
predicates. The multi-threaded version knows about two types of
dynamic predicates. By default, a predicate declared <em>dynamic</em>
(see dynamic/1) is shared by all threads. Each thread may
assert, retract and run the dynamic predicate. Synchronisation inside
Prolog guarantees the consistency of the predicate. Updates are
<em>logical</em>: visible clauses are not affected by assert/retract
after a query started on the predicate. In many cases primitive from
thread synchronisation should be used to ensure application invariants on
the predicate are maintained.
Besides shared predicates, dynamic predicates can be declared with the
thread_local/1 directive. Such predicates share their
attributes, but the clause-list is different in each thread.
*/
/** @pred thread_local( _+Functor/Arity_)
@ -1257,228 +1660,8 @@ thread_local(X) :-
'$do_error'(type_error(callable,X),thread_local(Mod:X)).
/** @pred thread_sleep(+ _Time_)
Make current thread sleep for _Time_ seconds. _Time_ may be an
integer or a floating point number. When time is zero or a negative value
the call succeeds and returns immediately. This call should not be used if
alarms are also being used.
*/
thread_sleep(Time) :-
var(Time), !,
'$do_error'(instantiation_error,thread_sleep(Time)).
thread_sleep(Time) :-
integer(Time), !,
( Time > 0 ->
'$thread_sleep'(Time,0,_,_)
; true
).
thread_sleep(Time) :-
float(Time), !,
( Time > 0.0 ->
STime is integer(float_integer_part(Time)),
NTime is integer(float_fractional_part(Time))*1000000000,
'$thread_sleep'(STime,NTime,_,_)
; true
).
thread_sleep(Time) :-
'$do_error'(type_error(number,Time),thread_sleep(Time)).
thread_signal(Id, Goal) :-
'$check_thread_or_alias'(Id, thread_signal(Id, Goal)),
'$check_callable'(Goal, thread_signal(Id, Goal)),
'$thread_id_alias'(Id0, Id),
( recorded('$thread_signal', [Id0| _], R), erase(R), fail
; true
),
recorda('$thread_signal', [Id0| Goal], _),
'$signal_thread'(Id0).
'$thread_gfetch'(G) :-
'$thread_self'(Id),
recorded('$thread_signal',[Id|G],R),
erase(R).
thread_property(Prop) :-
'$check_thread_property'(Prop, thread_property(Prop)),
'$thread_self'(Id),
'$thread_property'(Prop, Id).
/** @pred thread_property(? _Id_, ? _Property_)
Enumerates the properties of the specified thread.
Calling thread_property/2 does not influence any thread. See also
thread_join/2. For threads that have an alias-name, this name can
be used in _Id_ instead of the numerical thread identifier.
_Property_ is one of:
+ status( _Status_)
The thread status of a thread (see below).
+ alias( _Alias_)
The thread alias, if it exists.
+ at_exit( _AtExit_)
The thread exit hook, if defined (not available if the thread is already terminated).
+ detached( _Boolean_)
The detached state of the thread.
+ stack( _Size_)
The thread stack data-area size.
+ trail( _Size_)
The thread trail data-area size.
+ system( _Size_)
The thread system data-area size.
*/
thread_property(Id, Prop) :-
( nonvar(Id) ->
'$check_thread_or_alias'(Id, thread_property(Id, Prop))
; '$enumerate_threads'(Id)
),
'$check_thread_property'(Prop, thread_property(Id, Prop)),
'$thread_id_alias'(Id0, Id),
'$thread_property'(Prop, Id0).
'$enumerate_threads'(Id) :-
'$max_threads'(Max),
Max1 is Max-1,
between(0,Max1,Id),
'$thread_stacks'(Id, _, _, _).
'$thread_property'(alias(Alias), Id) :-
recorded('$thread_alias', [Id|Alias], _).
'$thread_property'(status(Status), Id) :-
'$mk_tstatus_key'(Id, Key),
( recorded(Key, Exit, _) ->
Status = Exit
; Status = running
).
'$thread_property'(detached(Detached), Id) :-
( '$thread_detached'(Id,Detached) -> true ; Detached = false ).
'$thread_property'(at_exit(M:G), Id) :-
'$thread_run_at_exit'(G,M).
'$thread_property'(stack(Stack), Id) :-
'$thread_stacks'(Id, Stack, _, _).
'$thread_property'(trail(Trail), Id) :-
'$thread_stacks'(Id, _, Trail, _).
'$thread_property'(system(System), Id) :-
'$thread_stacks'(Id, _, _, System).
threads :-
format(user_error,'------------------------------------------------------------------------~n',[]),
format(user_error, '~t~a~48+~n', 'Thread Detached Status'),
format(user_error,'------------------------------------------------------------------------~n',[]),
thread_property(Id, detached(Detached)),
thread_property(Id, status(Status)),
'$thread_id_alias'(Id, Alias),
format(user_error,'~t~q~30+~33|~w~42|~q~n', [Alias, Detached, Status]),
fail.
threads :-
format(user_error,'------------------------------------------------------------------------~n',[]).
'$check_thread_or_alias'(Term, Goal) :-
var(Term), !,
'$do_error'(instantiation_error, Goal).
'$check_thread_or_alias'(Term, Goal) :-
\+ integer(Term), \+ atom(Term), !,
'$do_error'(domain_error(thread_or_alias, Term), Goal).
'$check_thread_or_alias'(Term, Goal) :-
atom(Term), \+ recorded('$thread_alias',[_|Term],_), !,
'$do_error'(existence_error(thread, Term), Goal).
'$check_thread_or_alias'(Term, Goal) :-
integer(Term), \+ '$valid_thread'(Term), !,
'$do_error'(existence_error(thread, Term), Goal).
'$check_thread_or_alias'(_,_).
'$check_thread_property'(Term, _) :-
var(Term), !.
'$check_thread_property'(alias(_), _) :- !.
'$check_thread_property'(detached(_), _) :- !.
'$check_thread_property'(at_exit(_), _) :- !.
'$check_thread_property'(status(_), _) :- !.
'$check_thread_property'(stack(_), _) :- !.
'$check_thread_property'(trail(_), _) :- !.
'$check_thread_property'(system(_), _) :- !.
'$check_thread_property'(Term, Goal) :-
'$do_error'(domain_error(thread_property, Term), Goal).
'$check_mutex_or_alias'(Term, Goal) :-
var(Term), !,
'$do_error'(instantiation_error, Goal).
'$check_mutex_or_alias'(Term, Goal) :-
\+ integer(Term), \+ atom(Term), !,
'$do_error'(domain_error(mutex_or_alias, Term), Goal).
'$check_mutex_or_alias'(Term, Goal) :-
atom(Term), \+ recorded('$mutex_alias',[_|Term],_), !,
'$do_error'(existence_error(mutex, Term), Goal).
'$check_mutex_or_alias'(Term, Goal) :-
% integer(Term), \+ '$valid_mutex'(Term), !,
integer(Term), \+ recorded('$mutex_alias',[Term|_],_), !,
'$do_error'(existence_error(mutex, Term), Goal).
'$check_mutex_or_alias'(_,_).
'$check_mutex_property'(Term, _) :-
var(Term), !.
'$check_mutex_property'(alias(_), _) :- !.
'$check_mutex_property'(status(Status), Goal) :- !,
( var(Status) ->
true
; Status = unlocked ->
true
; Status = locked(_, _) ->
true
; '$do_error'(domain_error(mutex_property, status(Status)), Goal)
).
'$check_mutex_property'(Term, Goal) :-
'$do_error'(domain_error(mutex_property, Term), Goal).
'$mk_tstatus_key'(Id0, Key) :-
atomic_concat('$thread_exit_status__',Id0,Key).
/** @pred thread_statistics(+ _Id_, + _Key_, - _Value_)
Obtains statistical information on thread _Id_ as `statistics/2`
does in single-threaded applications. This call returns all keys
of `statistics/2`, although only information statistics about the
stacks and CPU time yield different values for each thread.
+ mutex_statistics
Print usage statistics on internal mutexes and mutexes associated
with dynamic predicates. For each mutex two numbers are printed:
the number of times the mutex was acquired and the number of
collisions: the number times the calling thread has to
wait for the mutex. The collision-count is not available on
Windows as this would break portability to Windows-95/98/ME or
significantly harm performance. Generally collision count is
close to zero on single-CPU hardware.
+ threads
Prints a table of current threads and their status.
*/
thread_statistics(Id, Key, Val) :-
format("not implemented yet~n",[]).
%% @}
/**

View File

@ -16,7 +16,7 @@
*************************************************************************/
/** @defgroup InputOutput Input/Output Predicates
/** @defgroup YAP_InputOutput Input/Output Predicates
@ingroup YAPBuiltins
@{

View File

@ -50,6 +50,7 @@
:- use_module(library(utf8)).
/** <module> Analysing and constructing URL
@ingroup SWILib
This library deals with the analysis and construction of a URL,
Universal Resource Locator. URL is the basis for communicating locations