Deep types

From OpenCog
Jump to: navigation, search

See also type signature and type checking. The SignatureLink implements a form of "deep types" for the pattern matcher. The FuzzyLink implements a "deep type" that is imprecise, allowing approximate matches. The current, primary use of deep types is to control the type of a VariableNode during pattern matching, either strictly, or in a fuzzy manner.

The general theory for deep types is discussed in the wiki page on type constructors. It is not exactly clear what this page is proposing, that is not already done ... is the proposal here to somehow integrate with PLN? Use them more widely in .. some new situation?

Deep Types for Atoms

We can associate additional type info (constituting what I’ll call a “Deep Type”) with any Atom using the TypedAtomLink.

The term “Deep Type” is used to distinguish the types we’re talking about here, namely, all of the types built with the type constructors, from the predefined “atom types”. Two instances of the PredicateNode type both have the same Atom type, “PredicateNode.” But they may have different deep types if they represent predicates taking different sorts of arguments.

So for example, if we have

ExecutionLink

GroundedSchemaNode “py:plus” ListLink NumberNode “2” NumberNode “3” NumberNode “5”

then the GSN labeled “py:plus” would have the function signature

ArrowLink
   ListLink
       TypeNode "NumberNode"
       TypeNode "NumberNode"
   TypeNode "NumberNode"

This indicates that it takes, as input, two NumberNodes, and returns a single NumberNode.

The ArrowLink is used to specify functions in this manner. The SignatureLink is used to declare input and output signatures. The TypedAtomLink is used to declare "global" signatures for functions. The declaration of variable-length lists is being explored with a combination of IntervalLink and TypeSetLink.

Or if we have

EvaluationLink

PredicateNode “eat” ListLink ConceptNode “Ben” ConceptNode “steak”

Then the PredicateNode labeled “eat” would have deep type

ArrowLink
   ListLink
       TypeNode "ConceptNode"
       TypeNode "ConceptNode"
   TypeNode "TruthValue"

which represents the mapping the PredicateNode actually carries out.

If we had

EvaluationLink

PredicateNode “quickly” ListLink ConceptNode “eat_101”

Then the PredicateNode labeled “quickly” would have deep type

ArrowLink
   ArrowLink
       ListLink
           TypeNode "ConceptNode"
           TypeNode "ConceptNode"
       TypeNode "TruthValue"
   TypeNode "TruthValue"

That is, “quickly” is represented as mapping (mappings from pairs of ConceptNodes into TruthValues) into TruthValues.

The real power of using types here is seen with ExecutionOutputLinks. Suppose for instance we have the fragment

ExecutionOutputLink

GroundedSchemaNode “py:deduction” ListLink InheritanceLink $X $Y InheritanceLink $Y $Z

(note that this fragment must exist within a larger Atom construct that contains other Atoms quantifying $X, $Y and $Z, but we don’t need to write that out for the point we’re making at the moment).

Associating the type

ArrowLink
    ListLink
        TypeNode "InheritanceLink"
        TypeNode "InheritanceLink"
    TypeNode "InheritanceLink"

with the GSN “py:deduction” makes it clear what type of output to expect from the ExecutionOutputLink. This can be very useful if e.g. one wants to do backward chaining from the ExecutionOutputLink.

The value of assigning deep types to ListLinks comes when one has GSNs whose output are ListLinks.

Then it can be valuable to be able to specify that a certain GSN produces a list or set of a certain type. For instance, if one has a GSN for “append” (that appends two ListLinks) then one has the parametrized deep type,

(List of T, List of T) ==> List of T

meaning that if the argument lists are lists of elements of type T, so is the output list. To construct a "List of T" types one needs to use the IntervalLink to specify the min and max length of the allowed list, together with the TypeSetLink. The "List of T" type is currently heavily used in ghost, to specify regex-like matching patterns for GlobNodes.

Deep Types and Evaluation2Member

One example illustrating the value of all this is the creation of a general-purpose Evaluation2Member rule. For a single-argument predicate, we can say

EvaluationLink
	P
	X

is equivalent to

MemberLink
	X
	SatisfyingSet
		P

In general, we can think about a parameterized rule

Evaluation2Member(m,k) 

for dealing with the k'th argument of a predicate that takes an argument-list of length m

For two-argument predicates, we can look at two variations,

Evaluation2Member(2,1) 

which is

Implication
    Evaluation
        D
        List
	    A
            B
    Member
        A
        SatisfyingSet
           $V
           Evaluation
               D 
               List
		$V
               	B

and

Evaluation2Member(2,2) 

which is

Implication
    Evaluation
        D
        List
	    A
            B
    Member
        B
        SatisfyingSet
           $V
           Evaluation
               D 
               List
		A
               	$V

These are OK so far as they go, but it would be much nicer to have a general rule for

    Evaluation
        D
        L

for the case where L is a list of length m. In this case there will be k different basic rules, one corresponding to each position 1 thru m. E.g. we can write a rule such as

Evaluation2Member(*,k)

(the * meaning that it holds for all m) of the form

ForAllLink $D, $L, $k
Implication
    Evaluation
        $D
        $L
    Member
        ExecutionOutputLInk
            GSN “ElementAt”
            ListLink
               ListLink $L
               NumberNode $k
        SatisfyingSet
            Variable $V
            ExecutionOutputLink
               GSN “Insert”
               ListLink
                   ListLink $L
                   Variable $V
                   NumberNode $k
 

Where do deep types come in here? The point is, the GSN “Insert” should have type

(List of T, T) ==> List of T

as well as

(List of T, List of T) ==> List of T

and the GSN "ElementAt" should have type

List of T ==> T

Deep Types and backward chaining

Then the backward chainer can utilize Evaluation2Member(*,k) properly, based on knowledge of what (deep) type its output is going to have. For instance, if $L is a list of ConceptNodes, then the deep type signature of "ElementAt" lets us know that the output of

        ExecutionOutputLInk
            GSN “ElementAt”
            ListLink $L
            NumberNode $k

is a ConceptNode. This is very helpful because it tells us that

    Member
        ExecutionOutputLInk
            GSN “ElementAt”
            ListLink $L
            NumberNode $k
        SatisfyingSet
            Variable $V
            ExecutionOutputLink
               GSN “Insert”
               ListLink $L
               Variable $V
               NumberNode $k

is of the form

Member
    ConceptNode X
    ConceptNode Y

And this means that if the backward chainer is looking for some rule that can output a MemberLink between two ConceptNodes, it should potentially consider applying Evaluation2Member(*,k) to a PredicateNode which is applied to a list of m ConceptNodes.

Without the deep type signature associated with "ElementAt", the backward chainer would have no way of knowing that the Evaluation2Member rule should be considered in this context, because it would simply encounter the ExecutionOutputLink and not know what it was going to output.