next up previous contents index
Next: 1.3 constraintLib: a library Up: 1.2 Attributed Variables Previous: 1.2 Attributed Variables   Contents   Index

1.2.1 Lowlevel Interface

Attributes of variables are pairs of attribute module names and values. An attribute module name can be any atom. A value can be any XSB value (term, variable, atom, ...). Any variable has at most one attribute for a particular attribute module. Attribute modules are distinct from XSB modules: although it is most efficient to keep each handlers for each attribute module in their own XSB module.

Attributes can be manipulated with the following three predicates (get_attr/3, put_attr/3 and del_attr/2) defined in the module machine.

get_attr(-Var,+Mod, ?Val)
machine
Gets the value of the attribute of Var in attribute module Mod. Non-variable terms in Var cause a type error. Val will be unified with the value of the attribute, if it exists. Otherwise the predicate fails.

put_attr(-Var,+Mod, ?Val)
machine
Sets the value of the attribute of Var in attribute module Mod. Non-variable terms in Var cause a type error. The previous value of the attribute is overwritten, if it exists.

del_attr(-Var, +Mod)
machine
Removes the attribute of Var in attribute module Mod. Non-variable terms in Var cause a type error. The previous value of the attribute is removed, if it exists.

One has to extend the default unification algorithm for used attributes by installing a handler in the following way:

:- install_verify_attribute_handler( $+Mod, -AttrValue, -Target, +Handler$)

The install_verify_attribute_handler/4 predicate is defined in module machine. $Mod$ is the attribute Module and $Handler$ is a term with arguments $AttrValue$ and $Target$. The $Handler$ term has to correspond to a handler predicate that takes the value of the attribute ($AttrValue$) and the term that the attributed value is bound to ($Target$) as arguments. To get good efficiency, it is usually best to keep the handlers for each attribute module in separate XSB modules.

The handler is called after the unification of an attributed variable with a term or other attributed variable, if the attributed variable has an attribute in the corresponding module. The two arguments of the unification are already bound at the time the handler is called, i.e. the handler is a post-unify handler.

Here, by giving the implementation of a simple finite domain constraint solver (see the file fd.P below), we show how these lowlevel predicates for attributed variables can be used. In this example, an attribute in the module fd is used and the value of this attribute is a list of terms.

%% File: fd.P
%%
%% A simple finite domain constrait solver implemented using the lowlevel 
%% attributes variables interface.  

:- import put_attr/3, get_attr/3, del_attr/3, 
   install_verify_attribute_handler/4 from machine.
:- import member/2 from basics.

:- install_verify_attribute_handler(fd,AttrValue,Target,fd_handler(AttrValue,Target)).

fd_handler(Da, Target) :-
        (var(Target),                       % Target is an attributed variable
         get_attr(Target, fd, Db) ->        % has a domain
           intersection(Da, Db, [E|Es]),    % intersection not empty
           (Es = [] ->                      % exactly one element
              Target = E                    % bind Var (and Value) to E
           ;  put_attr(Target, fd, [E|Es])  % update Var's (and Value's)
           )
        ;  member(Target, Da)               % is Target a member of Da?
        ).

intersection([], _, []).
intersection([H|T], L2, [H|L3]) :-
        member(H, L2), !,
        intersection(T, L2, L3).
intersection([_|T], L2, L3) :-
        intersection(T, L2, L3).

domain(X, Dom) :- 
        var(Dom), !, 
        get_attr(X, fd, Dom). 
domain(X, List) :- 
        List = [El|Els],                     % at least one element 
        (Els = []                            % exactly one element
         -> X = El                           % implied binding 
        ;  put_attr(Fresh, fd, List),        % create a new attributed variable
           X = Fresh                         % may call verify_attributes/2
        ).

show_domain(X) :-                            % print out the domain of X
        var(X),                              % X must be a variable
        get_attr(X, fd, D),
        write('Domain of '), write(X),
        write(' is '), writeln(D).


next up previous contents index
Next: 1.3 constraintLib: a library Up: 1.2 Attributed Variables Previous: 1.2 Attributed Variables   Contents   Index
Terrance Swift 2007-10-06