It has been recently brought to my attention that some recent version of FlatZinc supports half-reified predicates:
Half-reified predicates essentially represent constraints that are implied by a Boolean variable rather than being equivalent to one.
source: docs
Q:
- do all global predicates have a
_reifversion now? - do all global predicates have a
_impversion too?
Looking at the content of share/minizinc/ I can see that inside std only nosets.mzn uses _imp predicates, so my impression is that it is not yet mandatory to support _imp predicates. Q: Is this correct?
Looking at the docs, I found this:
Solver libraries should therefore provide reified versions of constraints whenever possible. The library contains files
fzn__reif.mznfor this purpose.source: docs
If I interpret it correctly, it is not necessary to support _reif predicates because they are already redefined in share/minizinc (although it can be beneficial for performance). Q: Is this correct?
Most often predicates (calls),
R(...), are used as an actual constraint:constraint R(...). The question when processing the expressionR(...)is now if it can be given directly to the solver or if it has a redefinition that needs to be evaluated.If the predicate is used in a more complex expression
B \/ R(...), then we cannot just give the solver the callR(...)because we don't want to enforceR(...). Instead we want to know if the relationship described byR(...)holds. This is what we call a reification.For this reason, there must be a
R_reif(..., r)predicate that forcesr <-> R(...). Essentially this give the truth value ofR(...). Again, when the compiler is given the expressionR_reif(...,r), then it will see if it can be given directly to the solver or if there is a redefinition available. If both of these are unavailable, then the compiler will try to generate a redefinition from the redefinition ofR(...). If this also fails, then the compiler will stop the compilation.If we look back at our example,
B \/ R(...), then one might note that usingr <-> R(...)is more than what is necessary. IfR(...)is false, then we still needBto betrueand ifBisfalsewe still want to forceR(...); however, we know that nothing will forceR(...)to becomefalse. We sayR(...)is in a positive context. In this case that means that havingr -> R(...)is enough. This is referred to as a half-reification.In MiniZinc it is possible to introduce a
R_imp(..., r)predicate to provide a separate half-reified predicate. This can again be something that is directly passed into the solver or a redefinition. If the compiler has to reify a expressionR(...)and sees that it is in a positive context, then it will try first to see if it can findR_imp(..., r)and otherwise fall-back toR_reif(..., r). Note that if a redefinition is generated, then the context of the call propagates inward and half reifications can still occur in the redefinition.To summarise and answer your questions directly:
_reifcan be defined explicitly or can be generated through the generation from their redefinition._reifpredicate that can be implemented as_impby the solver (including FlatZinc builtins)._reifpredicates; however, there are several required_reifpredicates in the FlatZinc builtins that do need support. If these predicates are not redefined or implemented by the solver, then the solver cannot support the generated FlatZinc.