You can check the state of a finite domain variable with the functions in the FD.reflect
module. The FD.reflect.dom
function seems especially useful in this context.
To get the current domain of every field in a record, you can map this function over records:
declare
fun {GetDomains Vec}
{Record.map Vec FD.reflect.dom}
end
The initial result in your example would be:
vec(a:[1#100] b:[1#100] c:[1#100])
Now you can compare the result of this function before and after adding constraints, to see if anything happens.
Two limitations:
- This will only work with constraints which actually change the domain of at least one variable. Some constraints change the constraint store but do not change any domains, for example an equality constraint with an unbound variable.
- Using reflection like this does not work well with concurrency, i.e. if constraints are added from multiple threads, this will introduce race conditions.
If you need an example on how to use the GetDomains
function in a loop, let me know...
EDIT: With a hint from an old mailing list message, I came up with this general solution which should work with all types of constraints. It works by speculatively executing a constraint in a subordinate computation space.
declare
Vec = vec(a:{FD.int 1#100} b:{FD.int 1#100} c:{FD.int 1#100})
%% A number of constraints as a list of procedures
Constraints =
[proc {$} Vec.a <: 50 end
proc {$} Vec.b =: Vec.a end
proc {$} Vec.b <: 50 end
proc {$} Vec.a =: Vec.b end
]
%% Tentatively executes a constraint C (represented as a procedure).
%% If it is already entailed by the current constraint store, returns false.
%% Otherwise merges the space (and thereby finally executes the constraint)
%% and returns true.
fun {ExecuteConstraint C}
%% create a compuation space which tentatively executes C
S = {Space.new
proc {$ Root}
{C}
Root = unit
end
}
in
%% check whether the computation space is entailed
case {Space.askVerbose S}
of succeeded(entailed) then false
else
{Wait {Space.merge S}}
true
end
end
for C in Constraints I in 1..4 break:Break do
{System.showInfo "Trying constraint "#I#" ..."}
if {Not {ExecuteConstraint C}} then
{System.showInfo "Constraint "#I#" is already entailed. Stopping."}
{Break}
end
{Show Vec}
end
{Show Vec}