Chase Termination for Linear (Multi-Head) Rules #
This file contains an attempt of formalizing reductions from one of our recent papers where we show that chase termination is decidable for linear existential rules [GLMON25].
The file contains code contributed by Laila in a student project covering preliminary definitions from the paper up until the mixed derivation. The contents are in an early stage of development. The code will be extended in the future and likely be reworked in the process.
The following definitions around Atom Positions aren't used in the rest of this file yet but could hopefully make some definitions and proofs for linear chase termination a bit easier.
An AtomPos consists of a GeneralizedAtom and a Number i that refers to the term at Position i in that Atom
- a : GeneralizedAtom sig T
Instances For
i is a valid index for a GeneralizedAtom a if it refers to an actual term of the atom a
Instances For
We apply a TermMapping to an AtomPos by applying the Mapping to the Atom and keeping the same positional Number
Equations
- AtomPos.mapping h pos = { a := h.apply_generalized_atom pos.a, i := Fin.cast ⋯ pos.i }
Instances For
It doesn't matter if we first get the term from a AtomPos and then apply a TermMapping or if we first apply the mapping on the AtomPos and the retrieve the Term
We get the same result if we first apply a TermMapping to an atom and then build an AtomPos from the result or vice versa
Equations
- instInhabitedPreGroundTermOfC = { default := FiniteTree.leaf default }
Linear Existential Rule #
A linear rule is an existential Rule that has only a single atom in the body. Here we additionally restrict the rule heads to be a conjunction of exactly two head atoms (usually linear rule heads admit conjunctions of an arbitrary numberof atoms).
A Rule is linear if it's body consists of exactli one atom
Equations
- rule.isLinear = (List.length rule.body = 1)
Instances For
Equations
- rule.exactlyTwoHeadAtoms det = (List.length rule.head[0] = 2)
Instances For
- rule : Rule sig
- exactlyTwoHeadAtoms : self.rule.exactlyTwoHeadAtoms ⋯
Instances For
This function returns the body of a linear rule
Instances For
This function returns the head of a linear rule as a Pair of the two head-atoms
Instances For
An integer i is frontier position in the body of a rule, if the term at the i'th position in the body atom is a frontier variable
Equations
Instances For
If i is a frontier position in the body of a rule r, then the term at this position occurs in the head of the rule
if v is a frontier variable of rule r, then v occurs in the body of r
i is frontier position in the first head atom of a rule, if the term at the i'th position in that atom is a frontier variable
Equations
Instances For
i is frontier position in the first head atom of a rule iff the term at this position is a variable and also occurs in the rulebody
i is frontier position in the second head atom of a rule, if the term at the i'th position in that atom is a frontier variable
Equations
Instances For
i is frontier position in the second head atom of a rule iff the term at this position is a variable and also occurs in the rulebody
- rules : Set (LinearRule sig)
Instances For
This function modifies the Substitution s such that v ↦ c and otherwise s is the same as before
Instances For
This function modifies the Substitution s such that t ↦ gt and returns the modified substitution if possible. Otherwise it returns Option.none The parameter 'vars' serves as a list of variables for which the substition is already 'properly' defined and cannot be changed anymore
Equations
- matchVarorConst s (VarOrConst.const c) gt vars = if gt = GroundTerm.const c then some s else none
- matchVarorConst s (VarOrConst.var v) gt vars = if v ∈ vars then if gt = s v then some s else none else some (extend_Substitutution s v gt)
Instances For
if 'matchVarOrConst s t gt' returns an actual substitution (Option.some subs) then subs applied on t will return gt
If a variable v occurs in vars, then the resulting substitution from any call of matchVarorConst (with vars) will behave on v exactly as the substituion before the call
If possible, this function returns substitution subs s.t. subs the List of VarOrConst to the List of GroundTerms (elementwise). Variables in 'vars' need to be mapped exactly as in Substitution s. If such a substitution is not possible, the function returns Option.none
Equations
- One or more equations did not get rendered due to their size.
- matchTermList s vars [] = some s
Instances For
Variables that occur in vars are (in the resulting substitution from matchTermList) mapped exactly as in Substitution s
The resulting substitution s from matchTermList (if there is one) will map for each pair of l the first element(VarOrConst) to the second one (GroundTerm) when s is applied to l
If there exists a substitution than maps the first element to the second in each pair of l, then matchTermList will find such a substitution
A ground substitution is a homomorphism from an atom to a fact. This function returns such a GroundSubstitution if there exists one. (Otherwise returns Option.none)
Equations
Instances For
If GroundSubstitution.from_atom_and_fact finds a Substitution s, then s applied on the atom retruns exactly the fact
If a substitution is returned by GroundSubstitution.from_atom_and_fact,then the atom and fact have the same number of terms.
If a substitution is returned by GroundSubstitution.from_atom_and_fact,then every number i is less than than the length of the term list of the atomm iff it is also less than the term list lenght of the fact
GroundSubstitution.from_atom_and_fact finds a substituition iff there exists one that maps the atom to the fact
A PreTrigger consists of a rule and a substitution form the rulebody to a fact. Here we get this substitution via GroundSubstitution.from_atom_and_fact
Equations
- PreTrigger.from_rule_and_fact rule fact = Option.map (fun (subs : GroundSubstitution sig) => { rule := rule.rule, subs := subs }) (GroundSubstitution.from_atom_and_fact rule.body fact)
Instances For
A rule can be appiled to a fact, if there exists a homomorphism from the rulebody to the fact (iff PreTrigger.from_rule_and_fact is some).
The result of the Rule Applycation is then given by trg.mapped_head and consist of two facts (that are obtained from the rulehaed by applying the substitution and skolemization)
Equations
- One or more equations did not get rendered due to their size.
Instances For
If ruleApply returns some value for a rule and a fact, then PreTrigger.from_rule_and_fact also returns some value for the same rule and fact
If ruleApply returns some for a rule and a fact, then this means, that rulebody and fact have the same number of terms in their resp. atom
The resulting first Atom from ruleApply (if it doesn'r return none) hase the same number of terms as the first head atom of the rule
The resulting second Atom from ruleApply (if it doesn'r return none) hase the same number of terms as the second head atom of the rule
If i is a frontier-Position in the first head of the rule, then there exists some position j in fact such that ruleApply rule fact will map the term at the frontier-Position to the term at position j in the fact.
If some positions in the first atom of the rule head and the body contain the same term, then the heads position of the second fact produced by ruleApply will contain the term that occurs at the rule bodies position in the fact that is given as parameter to ruleApply.
If some positions in rule head and body contain the same term, then the heads position of the second fact produced by ruleApply will contain the term that occurs at the rule bodies position in the fact that is given as parameter to ruleApply.
If i is a position in the first rule head containing a non-frontier-variable (i.e. an existential variable),then ruleApply will map the term at this position to a functional term (a SkolemFunction)
If i is a position in the second rule head containing a non-frontier-variable (i.e. an existential variable),then ruleApply will map the term at this position to a functional term (a SkolemFunction)
an AddressSymbol consists of a Linear Rule and a Number 0 or 1 that references the first(0) or second(1) head of that rule
- rule : LinearRule sig
- headIndex : Fin 2
Instances For
This function defines the set of all possible Address symbols of a rule set
Equations
- addressSymbols rs sym = (sym.rule ∈ rs.rules)
Instances For
An Address consists of an initial fact from the fat set and a list of address symbols from the rule set. The paper considers them a a word wu ∈ (fact set)(addressSymbols)* which allows talking about prefixes of addresses
- path : List { sym : AddressSymbol sig // sym ∈ addressSymbols rs }
Instances For
This definition returns true iff the immediate prefix of an address (i.e. the same Address just with the Address-path being shortend by the first symbol) is contained is Set f
Equations
Instances For
A forest is a set of addresses with the following two properties: (1) the fact set is fully contained in the forest and (2) for each addresses all its prefixae are in the forest too
- isPrefixClosed (a : Address fs rs) : a ∈ self.f → immed_prefix_address_in_set a self.f
Instances For
A forest is subforest of another one if it is a subset
Equations
- g.subforest_of f = (g.f ⊆ f.f)
Instances For
The subforest relation is reflexive
A Fact set can be seen as a forest too where all adresses have an empty path
Equations
Instances For
The Labelling Function maps an address to a fact if possible. The fact is created by successively applying the rules of the address symbols. Starting from the initial atom of the address, the rule of the first address symbol is applied then from the result one takes the head atom that is referenced by the address symbol and applies the naxt rule onto that. As rule applycation may fail (if there is no homomorphism) the labelling can also return none
Equations
- One or more equations did not get rendered due to their size.
Instances For
The oblivious chase representation is the forest of all addresses where the labelling function returns Option.some fact
Equations
- oblivious_chase fs rs = { f := fun (addr : Address fs rs) => (labellingFunction addr).isSome = true, fs_contained := ⋯, isPrefixClosed := ⋯ }
Instances For
The materialization of a forest is the set of all facts that can be produced by labellings from addresses of the forest
Equations
Instances For
For all Addresses that are part of a subforest of the obllivious chase the labbeling function returns some fact
A trigger consists of a Linear rule from the rule set and an address such that there exists an homomorphism from the rulebody to the labelling of the address
Instances For
from the trigger's rule on can bild two address symbols (one for each head). The Appplication of the trigger produces the two addresses that arise from adding one of those address symbols each to the trigger's address
Equations
- One or more equations did not get rendered due to their size.
Instances For
If you call ruleApply on the trigger's rule and labelling of the address, then you get Option.some value
The labelling of the addresses produced by the trigger applicstion is some
this function gives a shortcut for retrieving the actual labellings for the addresses created by the trigger application
Equations
- pi.labelling_of_apply = (ruleApply pi.rule.val ((labellingFunction pi.addr.val).get ⋯)).get ⋯
Instances For
this shows that the schortcut of labelling_of_apply is actually correct
The predicates of the first atom of the trigger'st rule head and the first fact produced by labelling_of_apply are the same
The predicates of the second atom of the rule head and the second fact produced by labelling_of_apply are the same
The number of terms in the first atom of the trigger's rule head and in the first fact produced by labelling_of_apply are the same
The number of terms in the second atom of the trigger's rule head and in the second fact produced by labelling_of_apply are the same
The atom in the trigger's rule's body has the same number of terms ar the fact produced by the labelling of the trigger's address
If some positions idxH,idxB in the trigger's first rule head and body (resp.) contain the same term (this is then either a frontier variable or constant), then the first fact produced by labelling_of_apply contains the same term at position idxH, as the labelling of the trigger's address contains at idxB.
If some positions idxH,idxB in the trigger's second rule head and body (resp.) contain the same term (this is then either a frontier variable or constant), then the second fact produced by labelling_of_apply contains the same term at position idxH, as the labelling of the trigger's address contains at idxB.
A trigger appears in a forest, if it's address is part of the forest
Instances For
A trigger is active in a forest, if it's address is part of that forest, but at least one of the addresses that are produced by trigger application isn't part of the forest.
Equations
Instances For
A forest-address is just an address that occurs in a specific forest
Instances For
every forest address where the forest is subforest of the oblivious chase is labelled to Option.some ... by the labellingFunction
A forest_trigger of a forest is a trigger that appears in that specific forest
Equations
- LinearRuleTrigger.forest_Trigger g = { trg : LinearRuleTrigger fs rs // trg.appears_in_forest g }
Instances For
Two addresses b1, b2 are Blocking team for a trigger iff ...(See definition 11 in the paper). Note that this definition slighliy differs from the definition in the paper in the sense that we don't requite h to be the identity on ⟨u⟩ but only on the frontier-positional terms in ⟨u⟩
Equations
- One or more equations did not get rendered due to their size.
Instances For
these are the three conditions from the alternative blocking-team definition. If they hold true then b1 and b2 are a plocking team for the trigger (see Observation 12 in the paper). Note that we needed to add the treatment of constants at condition two.
- b1_label : Fact sig
- b2_label : Fact sig
- second : (∀ (j : Nat) (lt_fst : j < pi.val.rule.val.head.fst.terms.length), (is_frontier_position_fst pi.val.rule.val j lt_fst ∨ ∃ (c : sig.C), pi.val.rule.val.head.fst.terms[j] = VarOrConst.const c) → pi.val.labelling_of_apply.fst.terms[j] = self.b1_label.terms[j]) ∧ ∀ (j : Nat) (lt_snd : j < pi.val.rule.val.head.snd.terms.length), (is_frontier_position_snd pi.val.rule.val j lt_snd ∨ ∃ (c : sig.C), pi.val.rule.val.head.snd.terms[j] = VarOrConst.const c) → pi.val.labelling_of_apply.snd.terms[j] = self.b2_label.terms[j]
- third : (∀ (i j : Nat), pi.val.labelling_of_apply.fst.terms[i]? = pi.val.labelling_of_apply.fst.terms[j]? → self.b1_label.terms[i]? = self.b1_label.terms[j]?) ∧ (∀ (i j : Nat), pi.val.labelling_of_apply.fst.terms[i]? = pi.val.labelling_of_apply.snd.terms[j]? → self.b1_label.terms[i]? = self.b2_label.terms[j]?) ∧ ∀ (i j : Nat), pi.val.labelling_of_apply.snd.terms[i]? = pi.val.labelling_of_apply.snd.terms[j]? → self.b2_label.terms[i]? = self.b2_label.terms[j]?
Instances For
this is just a helper theorem to simplify the expression cond.b1_label.terms[List.idxOf pi.val.labelling_of_apply.fst.terms[i] pi.val.labelling_of_apply.fst.terms] Maybe this could be stated in a more general result (?)
this is just a helper theorem to simplify the expression cond.b2_label.terms[List.idxOf pi.val.labelling_of_apply.snd.terms[i] pi.val.labelling_of_apply.snd.terms]
this shows the equivalence of the two definitons for blocking teams (This is the proof for observation 12 in the paper)
returns the resulting forest that arises if one adds the result of pi.apply to forest g if pi is a Trigger that is active in g
Equations
Instances For
the original forest g is a subforest of the one produced by active_trigger_apply_resulting_forest
A PossiblyInfiniteList of triggers is called PreChaseDerivation
Equations
- PreChaseDerivation fs rs = PossiblyInfiniteList (LinearRuleTrigger fs rs)
Instances For
This structure defines two conditions that must hold for the correspondence between a trigger and two forests. It is be needed to define chase derivations. (1) the trigger must be active in the forest 'before' (2) adding the application of the trigger to forest 'before' results in the forest 'after'
- active : trg.isActive_in_forest before
Instances For
A forest sequence is valid for a PreChaseDerivation-trigger sequence, if it (1) starts with the fact set and then (2) for each number n on which the trigger sequence is defined, the trg_application_condition holds for that trigger together with the forests at positions n and n+1 in the forest-sequence
Equations
- One or more equations did not get rendered due to their size.
Instances For
if two forest sequences are both valid for the same trigger-sequence, then they are equal
every forest that occurs in a valid forest-sequence is subforest of the oblivious chase
A chase derivation consists of a Possibly infinite trigger sequence, together with a forest sequence that is valid for the trigger sequence
- trigger_seq : PreChaseDerivation fs rs
- forest_seq : PossiblyInfiniteList (Forest fs rs)
- cond : self.trigger_seq.forest_seq_valid self.forest_seq
Instances For
If the trigger sequence of a chasederivation is defined (Option.isSome) at position n the so is the forest sequence
if the forest sequence is defined (Option.isSome) at position n+1 then the trigger sequence is defined at position n
for every n, the trigger in the trigger sequence at position n (if there is some) is active in the forest of the forest-sequence at position n
for every n, the trigger in the trigger sequence at position n (if there is some) appears in the forest of the forest-sequence at position n
every forest in the forest sequence is subforest of its successor forest in that sequence
every forest in the forest sequence is subforest of all its successor forests in that sequence
a chase forest is defined as the union of all forests that occur in the forest sequence of the chase derivation. This is also a forest.
Equations
Instances For
the chase forest is subforest of the oblivious chase
a chase derivation is called oblivous, if its chase forest equals the oblivious chase representation (defined by oblivious_chase)
Equations
- deriv.is_oblivious = (deriv.chaseForest = oblivious_chase fs rs)
Instances For
In a chase derivation, the trigger at position n in the trigger sequence is not blocked in forest at position n (in the forest sequence), if there doesn't exist a blocking team for the trigger in that forest.
Equations
- One or more equations did not get rendered due to their size.
Instances For
a chese derivation is called restricted if no trigger of the trigger-sequence is blocked in its corresponding forest
Equations
- deriv.is_resricted = ∀ (n : Nat), LChaseDerivation.trg_n_not_blocked_in_forest n deriv
Instances For
a chase derivation is called fair, if every trigger that is active in the chaseForest of that derivation also has a blocking team in the chaseForest
Equations
- One or more equations did not get rendered due to their size.
Instances For
Derivation deriv1 is a subsequence of deriv2, if it can be created from deriv2 by dropping 'unneccessary' elements.
Equations
- One or more equations did not get rendered due to their size.
Instances For
A mixed derivation consists of a oblivious chase derivation m, a restricted chase derivation r that is subsequence of m and we additionally have the condition that every trigger of m at position n that also occurs somewhere in r is not blocked in the forest at position n from m
- m : LChaseDerivation fs rs
- r : LChaseDerivation fs rs
- sub : self.r.subsequence self.m
- trg_blocked (n : Nat) : ∃ (trg : LinearRuleTrigger fs rs), PossiblyInfiniteList.get? self.m.trigger_seq n = some trg ∧ trg ∈ self.r.trigger_seq → trg_n_not_blocked_in_forest n self.m