Model-Faithful Acyclicity and its Relatives #
There is plenty of research around sufficient conditions for chase termination.
These are usually conditions on RuleSets. If they are fulfilled, we know that the RuleSet.terminates. If they are not fulfilled, we gain nothing.
Here, we consider variants of Model-Faithful Acyclicity (MFA), Disjunctive MFA (DMFA) and Restricted MFA (RMFA) essentially all at once.
We should note though that technically DMFA and RMFA assume a so-called Datalog-first chase, which always prefers triggers with Datalog rules before all others. So far, we are not modelling this possibility in our chase definitions.
Consequently, we also implement slightly different versions of DMFA and RMFA that simply drop the part that optimizes for Datalog-first sequences.
The modified versions are of course still correct (as we prove) but lifting the restriction of Datalog-first chase comes at the cost of potentially marking fewer rule sets as terminating. Indeed there are rule sets that would terminate for all Datalog-first chases but not for all more liberal application strategies.
In the future, we also aim to formalize the original Datalog-first version.
How does MFA work? #
The idea is almost shockingly simple.
First of all, for MFA, we turn all disjunctions in rules into conjunctions.
Then, we compute the chase on the new rule set and a special database and stop as soon as we see a cyclic function term.
If we see such a term, we do not learn anything about termination.
If we do not see such a term, then the chase computed for MFA will terminate on its own, since there are only finitely many non-cyclic terms.
But then, we can argue that any chase on any database also terminates since MFA basically generalizes all of them.
MFA shows termination of a rule set for the so-called Skolem chase, i.e. if we consider SkolemObsoleteness for the ObsoletenessCondition.
But SkolemObsoleteness is actually the "most non-terminating" of our ObsoletenessConditions so we really are able to show that MFA guarantees termination no matter which ObsoletenessCondition we choose.
See terminates_of_isMfa_with_DeterministicSkolemObsoleteness. Note what we call isMfa in our framework is already a generalized version of MFA that is also able to captures the (modified versions of) DMFA and RMFA by accepting something called MfaObsoletenessCondition. So what we call MFA here is really isMfa with the DeterministicSkolemObsoleteness.
How do DMFA and RMFA work? #
For MFA everything is comparibly simple since there are no disjunctions and we really only care about the Skolem chase.
It is not obvious but in this setting no trigger is every really obsolete unless its exact result is already part of the chase.
But then applying the trigger would not make a difference anyway.
This is different if disjunctions are present or if we consider a stricter ObsoletenessCondition (or both). Less triggers might be active and therefore the chase may terminate in more cases.
MFA would still work but maybe we can do better now. This is exactly the motivation behind DMFA and RMFA, where DMFA is optimized for Skolem chase on disjunctive rules and RMFA is designed for the restricted chase, potentially also with disjunctive rules.
The basic idea remains the same. We just simulate the chase on a special database. However, we now want to forbid certain trigger applications; ones that we call "blocked".
Formally, we can say that a trigger is blocked if we know that whenever it is loaded in a chase, then it is necessarily already obsolete.
To see why this may happen, remember that a trigger might require various facts to be introduced during the chase to become loaded. It can happen that the necessary facts at the same time also make the trigger obsolete, in which case we say that it is blocked.
In our framework, we realize this by using BlockingObsoleteness for the MfaObsoletenessCondition in isMfa.
Blocking is very similar for DMFA and RMFA and essentially only differs in the ObsoletenessCondition that for DMFA would be SkolemObsoleteness and for RMFA would be RestrictedObsoleteness. So what we do is simple: BlockingObsoleteness is simply defined taking a ObsoletenessCondition condition as a parameter. Thereby we obtain an MFA-like condition for any ObsoletenessCondition that one can imagine. So we can express DMFA, RMFA, and everything in-between.
We show in terminates_of_isMfa_with_BlockingObsoleteness that isMfa with any such BlockingObsoleteness guarantees termination.
Our Framework #
Despite the differences between MFA and DMFA/RMFA, you may realize that terminates_of_isMfa_with_DeterministicSkolemObsoleteness and terminates_of_isMfa_with_BlockingObsoleteness essentially use the same proof, namely they just call terminates_of_isMfa.
This result is generic over all possible MfaObsoletenessConditions and just demands that the given MfaObsoletenessCondition has the blocks_obs property with respect to the target ObsoletenessCondition.
For example, the DeterministicSkolemObsoleteness used for (the original) MFA has the blocks_obs property with respect to all ObsoletenessConditions
and the BlockingObsoleteness for a given ObsoletenessCondition $o$ has the blocks_obs property with respect to $o$.
Of course, this is something we need to prove and we do this in DeterministicSkolemObsoleteness.blocks_each_obs and BlockingObsoleteness.blocks_corresponding_obs, respectively.
How to actually check if a trigger is blocked? #
The definition of BlockingObsoleteness and also the proof of BlockingObsoleteness.blocks_corresponding_obs is awefully technical.
To check if a trigger is blocked, we backtrack where the functional terms involved in its mapped body come from.
We can do this, since each function symbol has a rule and disjunct id. Based on this information, we know which trigger must have been applied to make our target trigger loaded. At least almost.
The functional terms contain the mapped frontier, which we can use for reconstruction, but we do not know the mapping for the remaining body variables.
This could be anything. To not cause any interference there, we map them to fresh constants. While this is simply stated on paper, it is quite an effort to do formally. And there is yet another place where we require fresh constants. For reasons beyond what I want to discuss here, to check if a trigger is blocked, we first need to rename all of its constant occurrences apart, which again uses fresh constants.
If you actually aim to understand all the details, then good luck! There are a few doc comments on what happens in the individual files so you can dig into those a bit more. You can also have a look at the papers introducing the notions but this is likely still mind-boggling. Feel free to reach out to me at any point. I will try my best to explain and answer your questions!
At some point we need to map constants from arbitrary chases to the ones in the special database. For this, we map all rule set constants to themselves and all others to the single special_const.
Instances For
Indeed the mfaConstantMapping is the id on all rule set constants.
The mfaConstantMapping is even the id on all rule atoms. (Constant mappings leave variables untouched.)
A MfaObsoletenessCondition is simply a LaxObsoletenessCondition, i.e. besides the actual condition it only has subset monotonicity as its only condition.
- cond : PreTrigger sig → FactSet sig → Prop
Instances For
Equations
- instCoeMfaObsoletenessConditionLaxObsoletenessCondition = { coe := fun (obs : MfaObsoletenessCondition sig) => { cond := obs.cond, monotone := ⋯ } }
Here we define what it means for a MfaObsoletenessCondition to block a ObsoletenessCondition.
Essentially, we say that if the mfa obsoleteness is fulfilled and the trigger is loaded, then also the real obsoleteness condition is fulfilled.
Before that, we filter trggers where already every head result occurs in in the mfa set of facts anyway.
This is safe to do since applying these again would not make a difference.
The necessesity for doing this comes from DeterministicSkolemObsoleteness.blocks_obs. BlockingObsoleteness.blocks_obs works without.
Equations
- One or more equations did not get rendered due to their size.
Instances For
A trigger fulfills DeterministicSkolemObsoleteness if each of its derived heads is already in the fact set in question. Note that this captures the idea of replacing disjunctions with conjunctions, which is part of MFA. We do this nowhere explicitely, so disjunctions always remain in rules, but we implicitly treat them like conjunctions when necessary (like here).
Equations
- One or more equations did not get rendered due to their size.
Instances For
DeterministicSkolemObsoleteness has the blocks_obs property for each ObsoletenessCondition.
A trigger is blocked for its own backtracking if it is obsolete for its own backtracking. Note that the backtracking always requires us to prove that Skolem function terms are well-formed, which is what the additional conditions are for.
Equations
- One or more equations did not get rendered due to their size.
Instances For
A trigger fulfills BlockingObsoleteness if the trigger with renamed-apart constants is blocked for its own backtracking. Note that BlockingObsoleteness only depends on the trigger. The passed fact set is ignored.
Equations
- One or more equations did not get rendered due to their size.
Instances For
BlockingObsoleteness has the blocks_obs condition for the ObsoletenessCondition it was defined for.
This result is not necessary for MFA-like conditions but still interesting, also as a sanity check: The result of every deterministic Skolem ChaseBranch is the same as the parallelDeterminizedChase_result.
The MFA-like conditions all start on a special database, called the "critical instance". We define this here. It consists of all facts that can be build from predicates in the rule set and constants from the ruleset plus a "special constant". Intuitively, this generalizes all possible databases.
Equations
Instances For
The KnowledgeBase for the MFA-like checks consists of the rule set in question and the criticalInstance.
Equations
- rs.mfaKb finite special_const = { db := rs.criticalInstance finite special_const, rules := rs }
Instances For
Constants in the mfaKb are either the special constants or they come from the rule set.
The fact set computed in the MFA-like checks is the parallel determinized chase result (defined in a separete file) for the mfaKb.
Equations
Instances For
We can map every possible ChaseBranch into the mfaSet by replacing all (non-ruleset) constants by the special constant. At least this is the intuition for this behemoth of a theorem statement.
We can extend the result above to the whole result of the ChaseBranch.
If the mfaSet is finite, then the rule set terminates. The argument is that if the mfaSet is finite and every ChaseBranch can be embedded into this set, then each of these ChaseBranches also needs to be finite. This is still a bit involved since we need to show that only finitely many terms can collapse to the same on in the mfaSet.
A rule set isMfa if its mfsSet does not contain a cyclic term.
Equations
Instances For
A rule set terminates if it isMfa. What mainly remains to be shown here is that only finitely many terms are non-cyclic.
MFA correctness - If a rule set is MFA (isMfa with DeterministicSkolemObsoleteness), then it terminates.
DMFA/RMFA correctness - If a rule set is DMFA/RMFA or anything in between (isMfa with BlockingObsoleteness), then it terminates for the respective ObsoletenessCondition.