Interaction between CHR and CLP(R)

,

Reading Constraint Handling Rules (2009) by Thom Frühwirth.

In p.65, it says that

The wake-up policy of an implementation is a function wakeup(S, c,B) that defines which CHR constraints of S are woken by adding the constraint c to the built-in store B. We say that these constraints are woken (triggered) by c. One never wakes constraints that have become ground (i.e. that only contain fixed (determined) variables that are bound to ground terms). In practice, only CHR constraints which may potentially cause a rule to fire are woken. This is the case if the newly added built-in constraint further constrains variables of the constraint. If the same built-in constraints are added a second time, this should not wake any CHR constraints.

It seems theoretical that CHR constraints can be woken by more than just =. So I’d like to confirm whether the SWI-Prolog implementation of CHR could interact with CLP(R).

I wrote the following program:

%% test.pl
:- use_module(library(chr)).
:- use_module(library(clpr)).
:- chr_constraint lss/2.

lss(X,Y) <=> entailed(X<Y) | writeln("rule fired").

?- lss(X,Y).
lss($VAR(X),$VAR(Y)).

?- lss(X,Y), {X<Y}.
rule fired
lss($VAR(X),$VAR(Y)),
{$VAR(Y)= $VAR(X)+ $VAR(_A),$VAR(_A)>0.0}.

Notice the result of the 2nd query, rule fired but the constraint lss did not be deleted.

On the surface it seems that CHR can interact with CLP(R), but actually not.

See the following example,

:- use_module(library(chr)).
:- use_module(library(clpr)).
:- chr_constraint lss/2, foo/0.

lss(X,Y) <=> entailed(X<Y) | foo, writeln("rule fired").

?- lss(X,Y).
lss($VAR(X),$VAR(Y)).

?- lss(X,Y), {X<Y}.
rule fired
lss($VAR(X),$VAR(Y)),
{$VAR(Y)= $VAR(X)+ $VAR(_A),$VAR(_A)>0.0}.

Noticed that the writeln("rule fired") was called, but foo did not be added to the store, so IMO the rule did not actually be fired.

The conclusion is that the current implementation of CHR can not interact with other libraries (except built-in =). Confusingly printing rule fired may be a bug and it may be related to A strange behavior of CHR package

What really confuses me is that if {X<Y} can not wake-up lss, it should not touch anything about the rule (and lss) when {X<Y} called, However, it obvious touched!

Compare the following two programs

%% wake-up by `=`, correct!
lss(X,Y) <=> writeln("guard1") ,entailed(X=Y), writeln("guard2") | foo, writeln("rule fired").

?- lss(X,Y), writeln("q1"), X=Y, writeln("q2").
guard1
q1
guard1
guard2
rule fired
q2
X = $VAR(Y),
foo.

vs

%% wake-up by `{X<Y}`, printing logs are mess!
lss(X,Y) <=> writeln("guard1") ,entailed(X<Y), writeln("guard2") | foo, writeln("rule fired").

?- lss(X,Y), writeln("q1"), {X<Y}, writeln("q2").
guard1
q1
q2
guard1
guard2
rule fired
lss($VAR(X),$VAR(Y)),
{$VAR(Y)= $VAR(X)+ $VAR(_A),$VAR(_A)>0.0}.

I confirm this is buggy and not expected behavior. {X<Y} should trigger entailed/1, fire the rule, AND remove lss. The idea that the rule fires and the left side doesn’t go away is an abomination to CHR.

It would be nice, If {X<Y} could trigger entailed/1, fire the rule and remove lss, but I think the current implementation does not.

See SWI-Prolog -- CHR Syntax and Semantics

A suspended constraint is eligible as a passive constraint for an active constraint. The other way it may interact again with the rules is when a variable appearing in the constraint becomes bound to either a non-variable 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.

They only discuss reactive when variables be bounded.

It is a bit sad…

Bound but possibly not to ground. Nevertheless there is no case where you should see “rule fired” yet lss is not removed from the store.

1 Like