opencog / atomspace

The OpenCog (hyper-)graph database and graph rewriting system
https://wiki.opencog.org/w/AtomSpace
Other
801 stars 225 forks source link

How to use DefineLink to define a type-checked pattern #298

Closed amebel closed 8 years ago

amebel commented 8 years ago

Thought of using the pattern defining "pattern" demonstrated @ https://github.com/opencog/atomspace/blob/master/examples/pattern-matcher/define.scm#L92.

Am I missing something? see below for detail

Defined Predicates and scheme function

(define (cog-type-equal? atom type-node )
"
  Returns True-SimpleTruthValue '(stv 1 1)' if the 'atom' type is the equal to
  the type described by 'type-node' name

  type-node:
    - A TypeNode with a name equal to

  atom:
    - atom that being checked for its type being equal to the one named by the
      'type-node'.
"
    ; Check paramater
    (if (not (equal? (cog-type type-node) 'TypeNode))
        (error "Expected TypeNode got: " type-node)
    )

    (let ((type-checked (cog-name type-node))
          (atom-type (symbol->string (cog-type atom))))

        (if (equal? type-checked  atom-type)
             (stv 1 1)
             (stv 0 1)
        )
    )
)

(DefineLink
    (DefinedPredicateNode "OpenPsi: demand-pattern")
    (PresentLink
        (InheritanceLink
            (VariableNode "Demand")
            (ConceptNode "OpenPsi: Demand"))

        (EvaluationLink
            (PredicateNode "must_have_value_within")
            (ListLink
                (VariableNode "Demand")
                (VariableNode "min_acceptable_value")
                (VariableNode "max_acceptable_value")))
        (EvaluationLink
            (PredicateNode "Psi: acts-on")
            (ListLink
                (GroundedSchemaNode "scm: psi-demand-updater")
                (VariableNode "Demand")))))

(DefineLink
    (DefinedPredicateNode "is-concept?")
    (EvaluationLink
        (GroundedPredicateNode "scm: cog-type-equal?")
        (ListLink
            (VariableNode "Demand")
            (TypeNode "ConceptNode"))))

The GetLinks

(define get-demand
    (GetLink (DefinedPredicateNode "OpenPsi: demand-pattern")))

(define check-demand
    (GetLink (DefinedPredicateNode "is-concept?")))

(define get-type-checked-demand
    (GetLink (AndLink
        (DefinedPredicateNode "is-concept?")
        (DefinedPredicateNode "OpenPsi: demand-pattern"))))

Atomspace content


(EvaluationLink
   (PredicateNode "Psi: acts-on")
   (ListLink
      (GroundedSchemaNode "scm: psi-demand-updater")
      (ConceptNode "OpenPsi: Certainty" (stv 0.60000002 0.99999982))
   )
)
(EvaluationLink
   (PredicateNode "must_have_value_within")
   (ListLink
      (ConceptNode "OpenPsi: Certainty" (stv 0.60000002 0.99999982))
      (NumberNode "0.800000" (av 0 0 0))
      (NumberNode "1.000000" (av 0 0 0))
   )
)
(InheritanceLink
   (ConceptNode "OpenPsi: Certainty" (stv 0.60000002 0.99999982))
   (ConceptNode "OpenPsi: Demand")
)

(EvaluationLink
   (PredicateNode "Psi: acts-on")
   (ListLink
      (GroundedSchemaNode "scm: psi-demand-updater")
      (PredicateNode "OpenPsi: Certainty" (stv 0.60000002 0.99999982))
   )
)
(EvaluationLink
   (PredicateNode "must_have_value_within")
   (ListLink
      (PredicateNode "OpenPsi: Certainty" (stv 0.60000002 0.99999982))
      (NumberNode "0.800000" (av 0 0 0))
      (NumberNode "1.000000" (av 0 0 0))
   )
)
(InheritanceLink
   (PredicateNode "OpenPsi: Certainty" (stv 0.60000002 0.99999982))
   (ConceptNode "OpenPsi: Demand")
)

Commands

guile>  (cog-execute! get-demand)
(SetLink (av 0 0 0)
   (ListLink
      (ConceptNode "OpenPsi: Certainty" (stv 0.60000002 0.99999982))
      (NumberNode "0.800000" (av 0 0 0))
      (NumberNode "1.000000" (av 0 0 0))
   )

   (ListLink
      (PredicateNode "OpenPsi: Certainty" (stv 0.60000002 0.99999982))
      (NumberNode "0.800000" (av 0 0 0))
      (NumberNode "1.000000" (av 0 0 0))
   )
)

guile> (cog-execute! check-demand)
(SetLink
)

guile> (cog-execute! get-type-checked-demand)
(SetLink
)

guile> (cog-type-equal? (ConceptNode "OpenPsi: Certainty") (TypeNode "ConceptNode"))
(stv 1 0.99999982)
guile> (cog-type-equal? (PredicateNode "OpenPsi: Certainty") (TypeNode "ConceptNode"))
(stv 0 0.99999982)

Expected result


guile> (cog-execute! get-type-checked-demand)

(SetLink (av 0 0 0)
   (ListLink
      (ConceptNode "OpenPsi: Certainty" (stv 0.60000002 0.99999982))
      (NumberNode "0.800000" (av 0 0 0))
      (NumberNode "1.000000" (av 0 0 0))
   )
linas commented 8 years ago

Its not working as expected for the same reason as an earlier bug report/question (which I'm not finding right now): The variable you are testing is never given a value for it. So, step by step:

(DefineLink
    (DefinedPredicateNode "is-concept?")
    (EvaluationLink
        (GroundedPredicateNode "scm: cog-type-equal?")
        (ListLink
            (VariableNode "Demand")
            (TypeNode "ConceptNode"))))

(GetLink (DefinedPredicateNode "is-concept?"))

expands out to this:

(GetLink
    (EvaluationLink
        (GroundedPredicateNode "scm: cog-type-equal?")
        (ListLink
            (VariableNode "Demand")
            (TypeNode "ConceptNode"))))

If you were to run just that, you'd get the empty set, because at no point did you provide any directive that would give the variable node any kind of a value. Since there are no values, the scm: cog-type-equal? is never run. What you wanted is something like this:

(GetLink
    (PresentLink (VariableNode "Demand"))
    (EvaluationLink
        (GroundedPredicateNode "scm: cog-type-equal?")
        (ListLink
            (VariableNode "Demand")
            (TypeNode "ConceptNode"))))

which will iterate over every atom in the atomspace, and apply the scm: cog-type-equal? function to it. Running the above will then simply give you every ConceptNode in the atomspace.

To use the DefineLink, you could do it like this, for example:

(GetLink 
    (PresentLink (VariableNode "Demand"))
    (DefinedPredicateNode "is-concept?"))

again: every possible atom is found, and then the DefinedPredicateNode is applied to it.

This is not very efficient, though. Iterating over every possible atom in the atomspace is not going to be fast. It would be more efficient to specify an explicit type constraint in the GetLink (i.e. use VariableList to explicitly specify the variable and its type), instead of letting GetLink find the variable implicitly. Viz:

(GetLink
     (TypedVariableLink (VariableNode "Demand") (TypeNode "ConceptNode"))
     (PresentLink (VariableNode "Demand"))

will return the same set, but more efficiently

amebel commented 8 years ago

Putting aside the efficiency issue, I have tried to give the variable a value as you described.

(DefineLink
    (DefinedPredicateNode "OpenPsi: demand-pattern")
    (PresentLink
        (InheritanceLink
            (VariableNode "Demand")
            (ConceptNode "OpenPsi: Demand"))

        (EvaluationLink
            (PredicateNode "must_have_value_within")
            (ListLink
                (VariableNode "Demand")
                (VariableNode "min_acceptable_value")
                (VariableNode "max_acceptable_value")))
        (EvaluationLink
            (PredicateNode "Psi: acts-on")
            (ListLink
                (GroundedSchemaNode "scm: psi-demand-updater")
                (VariableNode "Demand")))))

(define get-type-checked-demand
    (GetLink (AndLink
        (DefinedPredicateNode "is-concept?")
        (DefinedPredicateNode "OpenPsi: demand-pattern"))))

guile> (cog-execute! get-type-checked-demand)
(SetLink
)
amebel commented 8 years ago

removing the AndLink has no difference

(define get-type-checked-demand
    (GetLink
        (DefinedPredicateNode "is-concept?")
        (DefinedPredicateNode "OpenPsi: demand-pattern")))

guile>  (cog-execute! get-type-checked-demand)
(SetLink
)

changing the order of the defined predicates, gives result but not expected. It seems to have only evaluated the first defined-predicate

guile>   get-type-checked-demand
(GetLink (av 0 0 0)
   (DefinedPredicateNode "OpenPsi: demand-pattern")
   (DefinedPredicateNode "is-concept?")
)

guile>  (cog-execute! get-type-checked-demand)
(SetLink (av 0 0 0)
   (ListLink
      (ConceptNode "OpenPsi: Certainty" (stv 0.60000002 0.99999982))
      (NumberNode "0.800000" (av 0 0 0))
      (NumberNode "1.000000" (av 0 0 0))
   )
   (ListLink
      (PredicateNode "OpenPsi: Certainty" (stv 0.60000002 0.99999982))
      (ConceptNode "0.800000")
      (ConceptNode "1.000000")
   )
)
amebel commented 8 years ago

adding an AndLink on the reverse ordered gives

guile>   get-type-checked-demand
(GetLink (av 0 0 0)
   (AndLink
      (DefinedPredicateNode "OpenPsi: demand-pattern")
      (DefinedPredicateNode "is-concept?")
   )
)

guile>  (cog-execute! get-type-checked-demand)
(SetLink
)
linas commented 8 years ago

Ah ... OK. In this case, the problem occurs because the PresentLink is not yet fully implemented and tested. :-) Specifically, a search is made for PresentLinks, but that search does not go deep enough. It doesn't go deep enough, because it was not clear who would nest them deeply, or what that would mean, or how they should work when the are nested.

Pull request #302 should fix this, I think.

amebel commented 8 years ago

Note: the links below are different even though github render them as same

The following give result thus the merge fix's them. pattern in https://github.com/opencog/atomspace/issues/298#issuecomment-140252629 and https://github.com/opencog/atomspace/issues/298#issuecomment-140260938 makes sense in that they keep with PatternLink signature. Thanks :-)

Still not resolved

linas commented 8 years ago

This one: https://github.com/opencog/atomspace/issues/298#issuecomment-140260508 . is a mal-formed GetLink. The GetLink should have an optional variable decl, and a body, and nothing more. Having two atoms make it unclear: are they suupposed to be anded togehter, or'ed? something else? I'm changing the code to check this, and to throw.

amebel commented 8 years ago

Yes, they have to be And/Or Linked. Thanks, all is good, for now :-)