Chase Derivation Skeleton #
It is time to define the chase [BV84].
We are going to introduce slightly different representations and the ChaseDerivationSkeleton is arguably the most basic but also most versatile one.
We only demand a PossiblyInfiniteList of ChaseNodes that is non-empty such that the next ChaseNode always results from a trigger application. However, we do not care so far if the trigger is active or even loaded.
We also do not care here whether the derivation is "fair".
The ChaseDerivation Structure #
The backbone of the ChaseDerivationSkeleton is a PossiblyInfiniteList of ChaseNodes with two conditions.
- We enforce that there is at least an initial
ChaseNode. - At each step in the derivation, either there exists a trigger that yields the next node or there is no next node.
- branch : PossiblyInfiniteList N
- triggers_exist (b2 : PossiblyInfiniteList N) : b2 <:+ self.branch → ∀ (before : N), before ∈ b2.head → ∀ (after : N), after ∈ b2.tail.head → ChaseNode.succ before after
Instances For
Basic Definitions #
Here we introduce some auxiliary definitions and theorems and we lift some of the machinery of the underlying PossiblyInfiniteList to ChaseDerivationSkeleton.
Membership of ChaseNodes in the ChaseDerivationSkeleton directly corresponds to membership in the PossiblyInfiniteList.
Equations
- ChaseDerivationSkeleton.instMembership = { mem := fun (cd : ChaseDerivationSkeleton N obs rules) (node : N) => node ∈ cd.branch }
An element is a member of the derivation iff it occurs at some index in the underlying branch.
Each suffix of the underlying PossiblyInfiniteList is itself a ChaseDerivationSkeleton as long as its head is not none.
Equations
- cd.derivation_for_branch_suffix l2 suffix l2_head_some = { branch := l2, isSome_head := l2_head_some, triggers_exist := ⋯ }
Instances For
The head of the ChaseDerivationSkeleton is the initial ChaseNode. We know that this is never none.
Instances For
The head is a member.
The "next" ChaseNode #
For a ChaseDerivationSkeleton derivation, its next node is the ChaseNode immediately following the head.
We mainly introduce a couple of theorems here that abstract away the triggers_exist condition from the ChaseDerivationSkeleton definition.
Instances For
The next node is a member.
The fact set of the next ChaseNode consists exactly of the facts from head and the result of the trigger that introduces next.
ChaseDerivationSkeleton Suffixes #
We define a suffix relation on ChaseDerivationSkeleton simply as the suffix relation of the underlying PossiblyInfiniteList.
Instances For
Equations
- One or more equations did not get rendered due to their size.
Instances For
Unfolds the definition of the suffix relation.
Members of our suffix are also our members.
Each ChaseNode in the ChaseDerivationSkeleton induces a subderivation.
Tail #
If next exists, we can drop the first element from the ChaseDerivationSkeleton and obtain a new ChaseDerivationSkeleton, which, inspired by the PossiblyInfiniteList, we call the tail.
Equations
- cd.tail next_some = cd.derivation_for_branch_suffix cd.branch.tail ⋯ next_some
Instances For
A node is a member if and only if it is either the head or it is a member of the tail.
A derivation is a suffix of another if and only if both are the same or the first is a suffix of the second's tail.
Induction Principle for Members #
Similar to PossiblyInfiniteList.mem_rec, we define an induction principle to show
properties of ChaseNodes in a ChaseDerivationSkeleton.
For this, we introduce ChaseDerivationSkeleton.Node as the subtype of ChaseNode that features a membership proof.
Instances For
A Node of our suffix can be cast into our Node type.
Equations
- ChaseDerivationSkeleton.Node.cast_suffix suffix node = ⟨node.val, ⋯⟩
Instances For
If we want to show a motive for all nodes in a derivation, it is enough to show the motive for the head and for the next node in each abitrary subderivation where the motive already holds for the head. This can be used with the induction tactic.
A node is a member of the tail if and only if there is a subderivation where the node is in the next position. Part of this proof uses the induction principle defined above.
Only Finitely many Generated Facts #
The generated facts of node in a ChaseDerivationSkeleton are all facts that are not part of the initial fact set.
For each node, the set of generated facts is finite since each trigger only introduces finitely many new facts.
The generated facts of a chase node are the facts that orruc in the node but not in the initial chase node.
Equations
- cd.generatedFacts node f = (f ∈ ChaseNode.ingoingFacts obs rules node ∧ ¬f ∈ ChaseNode.outgoingFacts obs rules cd.head)
Instances For
The generatedFacts are always finite.
Predecessor Relation #
We can define a predecessor relation (≼) on ChaseDerivation.Node.
At this point, it does not have many properties. On Proper ChaseDerivations it will be a total order.
A node $n$ is a predecessor of a node $m$ if there is a subderivation there $n$ is the head and $m$ is an arbitrary member.
Equations
Instances For
Equations
- One or more equations did not get rendered due to their size.
Instances For
The predecessor relation is stable across suffixes. That is, predecessor in our suffix are also predecessor for us. We only need to cast the nodes.
The predecessor relation is reflexive.
The predecessor relation is total.
We also define a strict version of the predecessor relation (≺) in the obvious way.
A node is a strict predecessor of another if it is a predecessor but not equal.
Instances For
Equations
- One or more equations did not get rendered due to their size.
Instances For
As for the predecessor relation, we can show that the relation is stable across suffixes given that we cast the nodes.
The strict predecessor relation is irreflexive.
The strict predecessor relation is total.
A predecessor is either equal or a strict predecessor.
If a node is a strict successor of the head, then it is at least a successor of the next element.
RegularChaseDerivationSkeleton #
In general, the ChaseDerivationSkeleton does not enforce a specific node type to be able to define machinery for Skolem, restricted, and core chase all at the same time. Some specific results, we can only show for the Skolem and restricted chase, which is what we do here.
We use the RegularChaseDerivationSkeleton as an abbreviation for a ChaseDerivationSkeleton that uses the RegularChaseNode implementation where the ingoing and outgoing facts of each node are always the same (as opposed to the core chase where the outgoing facts would be a core of the ingoing facts).
Equations
- RegularChaseDerivationSkeleton obs rules = ChaseDerivationSkeleton (RegularChaseNode obs rules) obs rules
Instances For
Subset Monotonicity of Facts in ChaseNodes #
Since ChaseNodes always extend the previous facts, the fact sets can only be growing along the ChaseDerivationSkeleton.
Each member's facts contain the head facts. Note that this extends to arbitrary pairs of members since each member always induces a subderivation where it acts as the head.
A first implication of facts_node_subset_every_mem is that, considering one of our subderivations, each of our members either has all of its facts contained in the head of the subderivation or it is itself a member of the subderivation.
Only Finitely many Generated Facts #
Here we cover the special case for RegularChaseDerivationSkeletons.
Each node's facts are formed by the initial facts and its generatedFacts.
The generatedFacts are always finite.
Predecessor Relation #
Here we cover the special case for RegularChaseDerivationSkeletons.
The facts of our predecessor are a subset of our facts.
Chase Result #
Here, we define the result of a ChaseDerivationSkeleton, which is simply the FactSet that is the union of all facts of all ChaseNodes.
Instances For
Every node's facts occur in the result.
The result of our suffix is the same our result.
For each (finite) list of facts in the result, there is a node that that contains all of them.
If a trigger is loaded for the result, then it is loaded for some node in the derivation.