improve docs
This commit is contained in:
parent
582efcf6eb
commit
8eec3113be
273
C/arrays.c
273
C/arrays.c
@ -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_.
|
||||
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
@ -24,7 +24,7 @@ static char SccsId[] = "%W% %G%";
|
||||
|
||||
The following predicates are used to manipulate atoms:
|
||||
|
||||
|
||||
\toc
|
||||
|
||||
*/
|
||||
|
||||
|
261
C/cmppreds.c
261
C/cmppreds.c
@ -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.
|
||||
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
|
38
C/eval.c
38
C/eval.c
@ -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.
|
||||
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
|
89
C/init.c
89
C/init.c
@ -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>
|
||||
|
91
C/parser.c
91
C/parser.c
@ -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:
|
||||
*
|
||||
|
361
C/scanner.c
361
C/scanner.c
@ -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;
|
||||
}
|
||||
|
||||
|
||||
/// @}
|
||||
|
12
H/eval.h
12
H/eval.h
@ -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
|
||||
|
||||
|
||||
|
36
config.h.in
36
config.h.in
@ -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
|
||||
|
||||
|
127
docs/chr.md
127
docs/chr.md
@ -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`).
|
||||
|
||||
@}
|
||||
|
||||
|
||||
@}
|
||||
|
||||
@}
|
||||
|
||||
@}
|
||||
|
||||
@}
|
||||
|
||||
@}
|
||||
*/
|
||||
|
@ -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)
|
||||
|
||||
@}
|
||||
|
||||
@}
|
||||
|
||||
|
@ -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 \
|
||||
|
179
docs/threads.md
179
docs/threads.md
@ -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).
|
||||
~~~~~
|
||||
|
||||
|
||||
|
||||
@}
|
81
docs/yap.md
81
docs/yap.md
@ -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
|
||||
|
@ -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.
|
||||
|
||||
*/
|
||||
|
||||
|
@ -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)).
|
||||
|
@ -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, _)
|
||||
).
|
||||
|
||||
|
||||
/**
|
||||
@}
|
||||
*/
|
||||
|
@ -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
|
||||
|
@ -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 ),
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
|
484
os/pl-file.c
484
os/pl-file.c
@ -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),
|
||||
|
217
os/pl-fmt.c
217
os/pl-fmt.c
@ -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);
|
||||
}
|
||||
|
||||
//! @}
|
||||
|
@ -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*/
|
||||
|
||||
/// @}
|
||||
|
153
os/pl-write.c
153
os/pl-write.c
@ -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
|
||||
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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).
|
||||
|
||||
%% @}
|
||||
|
||||
|
@ -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
|
@ -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
|
@ -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
|
@ -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),
|
||||
|
@ -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
|
@ -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
|
||||
|
@ -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
|
||||
|
727
pl/threads.yap
727
pl/threads.yap
@ -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",[]).
|
||||
%% @}
|
||||
|
||||
|
||||
/**
|
||||
|
@ -16,7 +16,7 @@
|
||||
*************************************************************************/
|
||||
|
||||
|
||||
/** @defgroup InputOutput Input/Output Predicates
|
||||
/** @defgroup YAP_InputOutput Input/Output Predicates
|
||||
@ingroup YAPBuiltins
|
||||
@{
|
||||
|
||||
|
@ -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
|
||||
|
Reference in New Issue
Block a user