Terms #
In this file, we define various kinds of terms that form some of the most basic building blocks of other structures like atoms and rules.
First of all, almost all of our definitions consider a fixed but arbitrary Signature of predicate symbols P, variables V, and constants C. Also every predicate has a fixed arity. Note that P, V, and C can be arbitrary types so there are no requirements in terms of countability or finiteness. However, intuitively you can consider them to be countably infinite sets. This would allow to pick fresh elements for example. In places where we need this property, we express this through the GetFreshInhabitant type class.
Instances For
Skolem Terms #
If you are familiar with existential rules, you may have expected (labelled) nulls to be part of the Signature.
These nulls would act as placeholders that are introduced during the chase to find fresh representatives for existentially quantified variables.
However, implementing this freshness is not really nice to model since it would require is to keep global state around to know
which nulls have already been used. Instead, we act as if the existentially quantified variables where Skolemized. By that, freshly
introduced terms simply become Skolem terms and we can show that these are indeed fresh by design. Some works on existential rules take this view,
first and foremost of course the ones considering the Skolem chase.
As a building block for Skolem terms, we introduce SkolemFS as a Skolem Function Symbol here. This structure captures the rule, disjunct, and (existential) variable for that the Skolem function was introduced. The arity corresponds to the size of the frontier of the rule, i.e. the universal variables that occur in both body and head.
Instances For
Equations
- One or more equations did not get rendered due to their size.
Instances For
With SkolemTerm we mean the Skolemized version of an existential variable. That is, a SkolemTerm only consists of a function symbol (SkolemFS) and a list of universal variables. Beyond that, we allow this inductive structure also to be a plain variable or constant. Thereby, the SkolemTerm can represent any term occurring in a Skolemized rule.
- var {sig : Signature} [DecidableEq sig.C] [DecidableEq sig.V] (v : sig.V) : SkolemTerm sig
- const {sig : Signature} [DecidableEq sig.C] [DecidableEq sig.V] (c : sig.C) : SkolemTerm sig
- func {sig : Signature} [DecidableEq sig.C] [DecidableEq sig.V] (fs : SkolemFS sig) (frontier : List sig.V) (arity_ok : frontier.length = fs.arity) : SkolemTerm sig
Instances For
Equations
- One or more equations did not get rendered due to their size.
- instDecidableEqSkolemTerm.decEq (SkolemTerm.var a) (SkolemTerm.var b) = if h : a = b then h ▸ isTrue ⋯ else isFalse ⋯
- instDecidableEqSkolemTerm.decEq (SkolemTerm.var v) (SkolemTerm.const c) = isFalse ⋯
- instDecidableEqSkolemTerm.decEq (SkolemTerm.var v) (SkolemTerm.func fs frontier arity_ok) = isFalse ⋯
- instDecidableEqSkolemTerm.decEq (SkolemTerm.const c) (SkolemTerm.var v) = isFalse ⋯
- instDecidableEqSkolemTerm.decEq (SkolemTerm.const a) (SkolemTerm.const b) = if h : a = b then h ▸ isTrue ⋯ else isFalse ⋯
- instDecidableEqSkolemTerm.decEq (SkolemTerm.const c) (SkolemTerm.func fs frontier arity_ok) = isFalse ⋯
- instDecidableEqSkolemTerm.decEq (SkolemTerm.func fs frontier arity_ok) (SkolemTerm.var v) = isFalse ⋯
- instDecidableEqSkolemTerm.decEq (SkolemTerm.func fs frontier arity_ok) (SkolemTerm.const c) = isFalse ⋯
Instances For
We may obtain all variables from a SkolemTerm term as the list of all variables occurring in the functional term or, if the term is a plain variable, simply as the singleton list with this one variable.
Equations
- (SkolemTerm.var v).variables = [v]
- (SkolemTerm.const c).variables = []
- (SkolemTerm.func fs vs arity_ok).variables = vs
Instances For
VarOrConst #
We introduce VarOrConst as yet another inductive type representing a term.
This is a function free SkolemTerm, i.e. either a variable or a constant (thus the name).
Having this is a separate type is more convenient for us than restricting the SkolemTerm further.
VarOrConst is used to define FunctionFreeAtom later and is thus also the basic building block of (non-Skolemized) Rules.
As the name suggests, a VarOrConst is either a variable or a constant.
- var {sig : Signature} [DecidableEq sig.C] [DecidableEq sig.V] (v : sig.V) : VarOrConst sig
- const {sig : Signature} [DecidableEq sig.C] [DecidableEq sig.V] (c : sig.C) : VarOrConst sig
Instances For
Equations
- instDecidableEqVarOrConst.decEq (VarOrConst.var a) (VarOrConst.var b) = if h : a = b then h ▸ isTrue ⋯ else isFalse ⋯
- instDecidableEqVarOrConst.decEq (VarOrConst.var v) (VarOrConst.const c) = isFalse ⋯
- instDecidableEqVarOrConst.decEq (VarOrConst.const c) (VarOrConst.var v) = isFalse ⋯
- instDecidableEqVarOrConst.decEq (VarOrConst.const a) (VarOrConst.const b) = if h : a = b then h ▸ isTrue ⋯ else isFalse ⋯
Instances For
A VarOrConst is a variable if it was built using the var constructor.
Equations
- (VarOrConst.var v).isVar = true
- (VarOrConst.const c).isVar = false
Instances For
Given a list of VarOrConst, we can filter out all the variables. Note that we do not use List.filter here since we need to change the list type on the way.
Equations
- VarOrConst.filterVars [] = []
- VarOrConst.filterVars (VarOrConst.var v :: vocs) = v :: VarOrConst.filterVars vocs
- VarOrConst.filterVars (VarOrConst.const c :: vocs) = VarOrConst.filterVars vocs
Instances For
Analogous to filterVars, we can also filter for constants.
Equations
- VarOrConst.filterConsts [] = []
- VarOrConst.filterConsts (VarOrConst.var v :: vocs) = VarOrConst.filterConsts vocs
- VarOrConst.filterConsts (VarOrConst.const c :: vocs) = c :: VarOrConst.filterConsts vocs
Instances For
In the context of a rule and a disjunct (in that rule), we can turn a VarOrConst into a SkolemTerm using the frontier of the rule. This function is used for skolemizing existential variables in rules.
Equations
- One or more equations did not get rendered due to their size.
- VarOrConst.skolemize ruleId disjunctIndex frontier (VarOrConst.const c) = SkolemTerm.const c
Instances For
Each member of filterVars is in the original list (when applyign the var constructor again.)
If a variable is in a list of VarOrConst, then it occurs in filterVars.
Each member of filterConsts is in the original list (when applyign the const constructor again.)
If a constant is in a list of VarOrConst, then it occurs in filterConsts.
The skolemize function is injective. That is, if the produced SkolemTerms are the same, then bey need to result from the same variable. This is important to ensure that introduced Skolem terms are indeed fresh (and unique) in the chase.
Ground Terms #
A GroundTerm is a constant or a functional term with arbitrary nesting of function symbols (SkolemFS).
Aiming to define GroundTerm, we need to define a more basic structure first, where we do not demand yet that function symbol arities are respected.
PreGroundTerms need to be able to model Skolem terms, i.e. function terms. We can represent those conveniently using inductively defined FiniteTrees.
With PreGroundTerms in place, we merely define GroundTerms to be the PreGroundTerms where arity_ok holds.
We then define appropriate constructors and recursion principles on the GroundTerm to make it behave almost like an inductive type with a const and func constructor.
The PreGroundTerm is simply a FiniteTree (SkolemFS sig) sig.C. That is a tree that features Skolem function symbols in its inner nodes and constants in its leaf nodes.
Equations
- PreGroundTerm sig = FiniteTree (SkolemFS sig) sig.C
Instances For
The arity of a functional term is ok if the defined arity of its function symbol matches its number of children and arity_ok also holds for each child. For constants, i.e. the leaf nodes, the arity is trivially ok.
Equations
- One or more equations did not get rendered due to their size.
- PreGroundTerm.arity_ok (FiniteTree.leaf a) = true
Instances For
As mentioned above, a GroundTerm is simply a PreGroundTerm subtype where arity_ok holds.
Equations
- GroundTerm sig = { t : PreGroundTerm sig // PreGroundTerm.arity_ok t = true }
Instances For
A GroundTerm can be direclty constructed from a constant.
Equations
- GroundTerm.const c = ⟨FiniteTree.leaf c, ⋯⟩
Instances For
Also, a GroundTerm can be constructed from a SkolemFS and a list of GroundTerms as long as the length of the list matches the function symbol's arity.
Equations
- GroundTerm.func func ts arity_ok = ⟨FiniteTree.inner func ts.unattach, ⋯⟩
Instances For
We define a cases eliminator for the GroundTerm having a case for each constructor. This allows to use the cases tactic direcly on GroundTerms.
Equations
- One or more equations did not get rendered due to their size.
Instances For
We define an induction eliminator for the GroundTerm having a case for each constructor. This allows to use the induction tactic direcly on GroundTerms.
Equations
- One or more equations did not get rendered due to their size.
Instances For
A GroundTerm that has been constructed from a constants can be converted into this constants again.
Equations
- t.toConst isConst = match eq : t.val with | FiniteTree.leaf c => c | FiniteTree.inner a a_1 => ⋯.elim
Instances For
The depth of a GroundTerm is the depth of the underlying FiniteTree, i.e. the deepest nesting of function symbols (+1).
Equations
- t.depth = FiniteTree.depth t.val
Instances For
The constants occurring in a GroundTerm are exactly the leaves of the underlying FiniteTree.
Equations
Instances For
The functions (i.e. function symbols SkolemFS) occurring in a GroundTerm are exactly the inner labels of the underlying FiniteTree.
Equations
Instances For
Constants have depth 1.
The depth of a function term is the maximum depth of its children + 1.
The constants of a constant are the singleton list with the constant itself.
The constants of a function term are the constants of its children.
A constant has no functions.
The functions of a function term consist of the function symbol of the current term and the function symbols of all its children.