# Knowledge Engineering for Historians/Primer Composite Elements

## Composing the Basic Elements

editSo far we have been happily conflating a notion that we now need to tease apart. When we write `ConstantineTheGreat`

, we are of course not writing an *entity*; the entity Constantine the Great is no longer among us and cannot be brought back by writing. Rather, we have been manipulating a *term*, namely the term with the unique character string sequence "ConstantineTheGreat", which is supposed to refer to Constantine the Great.

This is not hair-splitting, because once one has terms, it becomes obvious that multiple terms can actually refer to the same entity. (This also gives us a chance to show an equivalence relation in action!)

;; some examples (the first is a classic) equals(MorningStar,EveningStar) equals(FirstWifeOfHenryVIII,CathrineOfArragon)

### Functions — Dependent Terms

editSometimes an entity can be defined in terms of another entity. Indeed, if we look at the second example from the term introduction, it becomes pretty much clear from the term's name that this term is defined in terms of another:

equals(FirstWifeOfHenryVIII,CathrineOfArragon)

In knowledge engineering, this case is expressed via a *function*. A function is a composite term that denotes an entity in terms of one or more other terms (including self-denoting ones such as character strings and numbers). For example, we could rewrite the above example as follows:

equals(NthWifeOfFn(HenryVIII,1),CathrineOfArragon)

Notice the notational convention of appending `Fn`

and capitalizing the expression. The advantages of this approach are several:

- We now have captured additional information (namely the ordinal position) represented in the function rather snuck away in the name of a simple term. This is good because the programs we employ for knowledge representation are challenged when it comes to getting things out of names, but they do pretty well with arguments!
- We can now type self-denotating terms (which will allow us to undo a little cheat we undertook earlier):

;; typing dimensionless scalars MeterFn(272) ;; or tying them to a convention YearFn(272,CE) ;; we can now do a more proper rendition of old Constantine yearOfBirth(ConstantineTheGreat,YearFn(272,CE))

- Consider the alternative to having functional terms; if you were not happy with 272 by itself denoting both a distance and a year, then you would have to create simple terms for each one of them

;; a pointless exercise ..., TheDistanceOf271Meters, TheDistanceOf272Meters, TheDistanceOf273Meters, ... ..., TheYear271CE, TheYear272CE, TheYear273CE ...

Not all representation languages support this feature, though, and here is why: The power of flexibility comes with the price of now having a humongous number of terms in the language. This can introduce problems for the underlying reasoning system. Consequently, some representation languages prefer to keep this problem at bay by not supporting this feature. There, you have to work around the issue with relations and more complex statements.

;; a more complex way if you dont have functions yearOfBirth(ConstantineTheGreat,?X) && typeOfScalar(?X,Year) && valueOfScalar(?X,272)

### Complex Statements

editSo far we had primarily looked at simple statements, but as the last example showed, by introducing some additional material, namely logical connectives and variables, we can say more complex things. The logical connectives that knowledge representation systems usually support are:

- the
`and`

operation, denoted here as`&&`

- the (inclusive-)
`or`

operation, denoted here as`||`

- the unary negation operator, denoted here as
`~`

We also need to briefly talk about *quantifiers*, which specify constraints on variables. There are basically two flavors of quantifier: the *existential quantifier*, which says that there is at least one of this kind (there exists one, therefore *existential*); and the *universal quantifier*, which says that the following is true for all entities that satisfy the properties. Let's briefly reconsider our non-functional birth year of Constantine example:

;; we had basically treated existential quantification as assumed thereExists(?X, yearOfBirth(ConstantineTheGreat,?X) && typeOfScalar(?X,Year) && valueOfScalar(?X,272)) ;; all birth years are years forAll(?X, forAll(?Y, yearOfBirth(?Y,?X) && typeOfScalar(?X,Year)))

### Rules — Patterns of Relationship

editNow that we know about complex statements, we can turn our attention to a whole variety of complex statements called *rules*. Rules are like being able to say many things at the same time; they state a pattern for making statements of specific type. This is not only a notational convenience, but allows one to make statements about entities that one has not even encountered yet. For example, the statement that all people have a mother is true for people that are not even born yet.

Notationally, we will use the `implies`

operator, which takes a precondition and a postcondition (or antecedent and consequent), and states that if the precondition is true, then the post-condition is true also.

;; all people have a mother implies(forAll(?X,person(?X)), thereExists(?Y,motherOf(?Y,?X))

Since the antecedent is implicitly universal, many languages permit to leave the `forAll`

off:

;; with functional speak we get the veryt terse implies(person(?X),motherOf(MotherFn(?X),?X))