opencog / atomspace

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

Evaluatable in non-logical link inside BindLink clause #132

Closed williampma closed 8 years ago

williampma commented 9 years ago

Just thought I would throw this out there. Doing cog-bind on the following craziness

(BindLink
    (VariableList (stv 1.000000 0.000000)
        (VariableNode "$A") ; [80]
        (VariableNode "$B") ; [92]
        (VariableNode "$C") ; [103]
    )
    (MemberLink (stv 1.000000 1.000000)
        (BindLink (stv 1.000000 0.000000)
            (VariableList (stv 1.000000 0.000000)
                (TypedVariableLink (stv 1.000000 0.000000)
                    (VariableNode "$A") ; [80]
                    (TypeNode "ConceptNode") ; [100]
                ) ; [101]
                (TypedVariableLink (stv 1.000000 0.000000)
                    (VariableNode "$B") ; [92]
                    (TypeNode "ConceptNode") ; [100]
                ) ; [102]
                (TypedVariableLink (stv 1.000000 0.000000)
                    (VariableNode "$C") ; [103]
                    (TypeNode "ConceptNode") ; [100]
                ) ; [104]
            ) ; [105]
            (AndLink (stv 1.000000 0.000000)
                (InheritanceLink (stv 1.000000 0.000000)
                    (VariableNode "$A") ; [80]
                    (VariableNode "$B") ; [92]
                ) ; [106]
                (InheritanceLink (stv 1.000000 0.000000)
                    (VariableNode "$B") ; [92]
                    (VariableNode "$C") ; [103]
                ) ; [107]
                (NotLink (stv 1.000000 0.000000)
                    (EqualLink (stv 1.000000 0.000000)
                        (VariableNode "$A") ; [80]
                        (VariableNode "$C") ; [103]
                    ) ; [108]
                ) ; [109]
            ) ; [110]
            (ExecutionOutputLink (stv 1.000000 0.000000)
                (GroundedSchemaNode "scm: pln-formula-simple-deduction") ; [111]
                (ListLink (stv 1.000000 0.000000)
                    (InheritanceLink (stv 1.000000 0.000000)
                        (VariableNode "$A") ; [80]
                        (VariableNode "$B") ; [92]
                    ) ; [106]
                    (InheritanceLink (stv 1.000000 0.000000)
                        (VariableNode "$B") ; [92]
                        (VariableNode "$C") ; [103]
                    ) ; [107]
                    (InheritanceLink (stv 1.000000 0.000000)
                        (VariableNode "$A") ; [80]
                        (VariableNode "$C") ; [103]
                    ) ; [112]
                ) ; [113]
            ) ; [114]
        ) ; [115]
        (ConceptNode "URE") ; [116]
    ) ; [118]
    (ListLink
        (VariableNode "$A") ; [80]
        (VariableNode "$B") ; [92]
        (VariableNode "$C") ; [103]
    )
)

gives me

ERROR: In procedure cog-bind: Unknown logical connective (MemberLink (stv 1.000000 1.000000)
...

I stumbled upon this when the BC algorithm tried to backward chain an untyped (VariableNode "$stuff") target (from modus ponens rule), which match to everything in the atomspace. Then since the variables inside the interior MemberLink are by current algorithmic definition "free", the MemberLink is added as a target as a "Variable Fullfillment Query", and then generate the above error when trying to ground it.

jswiergo commented 9 years ago

What I see in the code of pattern matcher you cannot use MemberLink as a top link in the query, because it is not evaluatable. I guess if you add EvaluationLink around that top link it should work. For me it sounds logical, though I have not got much experience with this type system.

linas commented 9 years ago

We should ask @ngeiswei about this. When he simplified the format of the BindLink, I think that the top level link could be anything, in which case, its treated as a single clause.

In the good old days, it had to have the format

   AndLink
       clause 1
       clause 2
       ...
       clause N

Later on, the top could be AndLink, SequentialAndLink or ChoiceLink (and nothing else). Today, if it is not one of these three, but something else, then we could/should assume there is only one clause total to be satisfied. I guess that last part is not implemented/fully supported.

A short-term work-around is to wrap the MemberLink with an AndLink.

williampma commented 9 years ago

What I found is that doing a simpler version

(cog-bind
  (BindLink 
   (VariableList (VariableNode "$A"))
   (MemberLink (InheritanceLink (VariableNode "$A") (ConceptNode "dog")))
   (ListLink (VariableNode "$A"))))

doesn't generate the error. So I think there's something special with the one at the top.

williampma commented 9 years ago

Ah, so it's not just a MemberLink thing. In fact, it happens on any non-logical link with evaluatable inside. For example, the follow also generates the error.

(BindLink
    (VariableList (stv 1.000000 0.000000)
        (VariableNode "$A") ; [80]
        (VariableNode "$B") ; [92]
    )
    (ListLink (stv 1.000000 1.000000)
        (EqualLink (stv 1.000000 0.000000)
            (VariableNode "$A") ; [80]
            (VariableNode "$B") ; [103]
        ) ; [108]
        (ConceptNode "URE") ; [116]
    ) ; [118]
    (ListLink
        (VariableNode "$A") ; [80]
        (VariableNode "$B") ; [92]
    )
)
ngeiswei commented 9 years ago

Looks like a PM bug to me (I have no more clue sorry).

jswiergo commented 9 years ago

This is case 4) explained here: https://github.com/opencog/atomspace/blob/master/opencog/query/PatternMatchEngine.cc#L1127-L1141 Seems hard to solve in general.

What we can do in your case is to introduce UniqueLink instead of

  (NotLink (stv 1.000000 0.000000)
      (EqualLink (stv 1.000000 0.000000)
          (VariableNode "$A") ; [80]
          (VariableNode "$C") ; [103]
        ) ; [108]
   )

This is what @linas has suggested how to deal with elimination rules: https://github.com/opencog/atomspace/issues/86#issuecomment-118571213

Then there will be one less virtual atom in your first example (UniqueLink is supposed to be UnorderedLink). However what to do with ExecutionOutputLink remains open question. I think your intention is to match it without any execution. So it should be quoted somehow. Does the QuoteLink do the job? Do you have any other ideas?

williampma commented 9 years ago

Hummm... I thought about the QuoteLink possibility, but it seems it is impossible to QuoteLink the evaluatable/virtual atom without ended up QuoteLink-ing the variables as well.

Maybe the way to do it is, any evaluatable not inside a logical link should just be matched as a normal atom?

linas commented 9 years ago

William's last suggestion seems best: any evaluatable not inside a logical link should just be matched as a normal atom.

I would like to have @ngeiswei think about this, instead of saying "I don't know", because this is a general atomspace representation question, and not just a pattern-matcher question. Some link types are truth-valued (for example, the EqualLink) and it is not obvious what should happen when these are inside of non-logical links (e.g. the ListLink) For now, William's answer seems like the best answer, but its a bit confusing in general.

I have thought about, and wrote some preliminary code to make the above user-configurable, via callback, but left it partly-finished, pending use-cases that really do need more complex behavior.

linas commented 9 years ago

Yes, it's exactly case 4.

There is a check here: https://github.com/opencog/atomspace/blob/master/opencog/query/PatternMatchEngine.cc#L1117 and, since EqualLink is "evaluatable", it is evaluated, and then, the containing ListLink or MemberLink causes the error to be thrown. The "evaluatable" flag is pre-compted, at the time that the bind link is defined. We could change this so that a term is "evaluatable" if and only if it is contained in another link that expects a truth value (i.e. a logical link). If it is not contained in this way, then it is not evaluatable.

The "is_evaluatable" check is based on these bits:

https://github.com/opencog/atomspace/blob/master/opencog/query/Pattern.h#L108-L111 https://github.com/opencog/atomspace/blob/master/opencog/query/Pattern.h#L121

These are computed here: https://github.com/opencog/atomspace/blob/master/opencog/atoms/bind/PatternLink.cc#L433-L476

specifically: https://github.com/opencog/atomspace/blob/master/opencog/atoms/bind/PatternLink.cc#L519 and L530 and line 539 ...

I had planed to do something similar for "exectuable terms" -- terms that could be executed, resulting in an atom -- but never got very far with that.

linas commented 9 years ago

Anyway, @ngeiswei (and I guess Ben and Matt Ikle should weigh in, too ...) do you now see what the problem is? When pattern matching, some links can be evaluated to yield a truth value; others can be executed, yielding an atom; in either case, its not obvious what to do when these are not nested in a way that "makes sense".

It would be nice to have a good answer...

ngeiswei commented 9 years ago

It's a complex issue and I haven't digested all the PM inner workings to spot THE problem..

Personally I would have approached the pattern matching problem the other way around, assuming a pattern is a predicate ([Atom] -> TV), and give some predicate construct (let's call it BelongLink) to allow to check whether an hypergraph belongs to the atomspace. For instance the problematic pattern above (William's compact version) would have been expressed as follows:

(BelongLink
    (ListLink (stv 1.000000 1.000000)
        (EqualLink (stv 1.000000 0.000000)
            (VariableNode "$A") ; [80]
            (VariableNode "$B") ; [103]
        ) ; [108]
        (ConceptNode "URE") ; [116]
)

So in the PM matcher lingo everything would be virtual if not told otherwise (BelongLink used for that).

Would that fundamentally fix the issue, probably not. It seems to me generally the problem is that not enough is explicitly specified, right?

I mean how do you match the following pattern

(EqualLink (VariableNode "$X") (VariableNode "$Y))

? Can you at all? Or can you match it via using SignatureLink?

ngeiswei commented 9 years ago

If I'm right a whole clause is either virtual or not. I mean a part cannot be virtual while another part of it wouldn't, right? So what about using a VirtualLink on top of each virtual clause? Or symmetrically using a BelongLink on top of each non virtual ones?

bgoertzel commented 9 years ago

Nil -- I'm not sure exactly what you mean by "virtual" here? Is it the same as "quoted" (what we get via wrapping something in a QuoteLink)?

On Mon, Jul 13, 2015 at 5:48 AM, ngeiswei notifications@github.com wrote:

If I'm right a whole clause is either virtual or not. I mean a part cannot be virtual while another part of it wouldn't, right? So what about using a VirtualLink on top of each virtual clause? Or symmetrically using a BelongLink on top of each non virtual ones?

— Reply to this email directly or view it on GitHub https://github.com/opencog/atomspace/issues/132#issuecomment-120875353.

Ben Goertzel, PhD http://goertzel.org

"The reasonable man adapts himself to the world: the unreasonable one persists in trying to adapt the world to himself. Therefore all progress depends on the unreasonable man." -- George Bernard Shaw

williampma commented 9 years ago

I mean how do you match the following pattern

(EqualLink (VariableNode "$X") (VariableNode "$Y))

Couldn't it match to (EqualLink (VariableNode "$A") (VariableNode "$B")) given that $X and $Y are untyped?

bgoertzel commented 9 years ago

yes I would think so...

On Mon, Jul 13, 2015 at 5:56 AM, William Ma notifications@github.com wrote:

I mean how do you match the following pattern

(EqualLink (VariableNode "$X") (VariableNode "$Y))

Couldn't it match to (EqualLink (VariableNode "$A") (VariableNode "$B")) given that $X and $Y are untyped?

— Reply to this email directly or view it on GitHub https://github.com/opencog/atomspace/issues/132#issuecomment-120878249.

Ben Goertzel, PhD http://goertzel.org

"The reasonable man adapts himself to the world: the unreasonable one persists in trying to adapt the world to himself. Therefore all progress depends on the unreasonable man." -- George Bernard Shaw

ngeiswei commented 9 years ago

I just tried

scheme@(guile-user) [1]> (cog-bind (BindLink (EqualLink (VariableNode "X") (VariableNode "Y")) (ListLink (VariableNode "X") (VariableNode "Y"))))
$2 = (SetLink
)

so it doesn't match to anything, I think it assumes it's a virtual clause.

Ben a virtual clause is a clause that is a predicate rather than a pattern, so for instance

GreaterThan X Y

is a virtual clause, it doesn't try to find that in the atomspace instead it uses as a constraint to filter out matches (could be used here for instance if X and Y match number nodes, etc).

ngeiswei commented 9 years ago

So "virtual" is almost the opposite of "quote". But QuoteLink is even stronger as is assumes the VariableNode are quoted as well (they only match themselves).

ngeiswei commented 9 years ago

I suggest we re-implement the pattern matcher Nil's way, everything is predicate and turn the atomspace into a LambdaLink graveyard.

ngeiswei commented 9 years ago

Or wrap virtual clauses into a VirtualLink...

bgoertzel commented 9 years ago

I have thought about this a bit now...

Of course, related issues are encountered in LISP, and are dealt with there via the quote and backquote mechanism, see e.g. discussion at

http://stackoverflow.com/questions/134887/when-to-use-quote-in-lisp

where they consider examples in which you want to evaluate only parts of some complex expression...

What LISP does is to evaluate everything by default, and then you need to override that with quotes and backquotes if you want to...

Here the question is whether we treat "logical links" as evaluable or not, and then whether we treat links wrapping logical links as evaluable or not.

I'm not sure "any evaluatable not inside a logical link should just be matched as a normal atom" can work in general, because sometimes it will be complex to tell if an evaluatable is going to be inside a logical link or not, after a whole expression is done being unraveled and evaluated. Subtle and annoying issues of evaluation order could arise here. For instance, suppose the logical link that is wrapped around the evaluatable link, is not directly there in the pattern being matched but is produced by some ExecutionOutputLink? Then what if this ExecutionOutputLink happens to get executed after the evaluatable link is evaluated? Thing seem to get pretty messy...

It would seem best to make things explicit. That is, we could say

-- the default for any link type except those on a certain list (ExecutionOutputLink, GreaterThanLink, VariableNode, whatever) is to match exactly rather than evaluate

-- if we want to evaluate a certain instance of one of these link types, then we have to add some special marker, which would be the inverse of a QuoteLink ... say a DoThisLink.. (in this case we might want to rename QuoteLink as DontDoThisLink ;D) ...

This becomes a little awkward, because we then have two types of Atoms

and when we want those of the first type to be literally matched we use QuoteLink, and when we want those of the second type to be evaluated or executed, we use DoThisLink

So in William's example

(BindLink (VariableList (stv 1.000000 0.000000) (VariableNode "$A") ; 80 ; [92] ) (ListLink (stv 1.000000 1.000000) (EqualLink (stv 1.000000 0.000000) (VariableNode "$A") ; 80 ; [103] ) ; 108 ; [116] ) ; 118 ; 80 ; [92] ) )

it would just try to match the exact pattern given, i.e. to find $A, $B so that

(ListLink (stv 1.000000 1.000000)
    (EqualLink (stv 1.000000 0.000000)
        (VariableNode "$A") ; [80]
        (VariableNode "$B") ; [103]
    ) ; [108]
    (ConceptNode "URE") ; [116]
)

(where the EqualLink and ListLInk are not evaluated)

On the other hand, if we wanted the EqualLink to be evaluated then we'd need to wrap it in a DoThisLink, and in that case the expression would be matched by

ListLink

True

ConceptNode "URE"

if the pattern matcher found any $A, $B that were equal

-- Ben

On Sun, Jul 12, 2015 at 11:01 PM, William Ma notifications@github.com wrote:

Hummm... I thought about the QuoteLink possibility, but it seems it is impossible to QuoteLink the evaluatable/virtual atom without ended up QuoteLink-ing the variables as well.

Maybe the way to do it is, any evaluatable not inside a logical link should just be matched as a normal atom?

— Reply to this email directly or view it on GitHub https://github.com/opencog/atomspace/issues/132#issuecomment-120792949.

Ben Goertzel, PhD http://goertzel.org

"The reasonable man adapts himself to the world: the unreasonable one persists in trying to adapt the world to himself. Therefore all progress depends on the unreasonable man." -- George Bernard Shaw

ngeiswei commented 9 years ago

We could make everything explicit, or assume that some atoms are evaluable (or evaluatable, not sure I understand the distinction). But I'm thinking in cases the link itself is a function (like EqualLink) maybe we could benefit from introducing a special FunQuoteLink to quote only the functional part of the link.

If executions were only relying on EvaluationLink or ExecutionOutputLink then you could always quote the predicate or schema, like if you'd want to match

ExecutionOutputLink
   GPN "plus"
   ListLink
       VariableNode "$X"
       VariableNode "$Y"

you could write the pattern

ExecutionOutputLink
   QuoteLink
       GPN "plus"
   ListLink
       VariableNode "$X"
       VariableNode "$Y"

to unambiguously tell that you don't want to execute it. But you can't do that for an EqualLink, thus a FunQuoteLink.

The other option is to use UnquoteLink (or DontDoThisLink as Ben coins it), but it seems a FunQuoteLink might allows to get more compact patterns in many practical cases.

bgoertzel commented 9 years ago

How would FunQuoteLink handle logical links like EqualsLink etc. ?

On Mon, Jul 13, 2015 at 8:58 AM, ngeiswei notifications@github.com wrote:

We could make everything explicit, or assume that some atoms are evaluable (or evaluatable, not sure I understand the distinction). But I'm thinking in cases the link itself is a function (like EqualLink) maybe we could benefit to introduce a special FunQuoteLink to quote only the functional part of the link.

If executions were only relying on EvaluationLink or ExecutionOutputLink then you could always quote the predicate or schema, like if you'd want to match

ExecutionOutputLink GPN "plus" ListLink VariableNode "$X" VariableNode "$Y"

you could write the pattern

ExecutionOutputLink QuoteLink GPN "plus" ListLink VariableNode "$X" VariableNode "$Y"

to unambiguously tell that you don't want to execute it. But you can't do that for an EqualLink, thus a FunQuoteLink.

The other option is to use UnquoteLink (or DontDoThisLink as Ben coins it), but it seems a FunQuoteLink might allows to get more compact patterns in many practical cases.

— Reply to this email directly or view it on GitHub https://github.com/opencog/atomspace/issues/132#issuecomment-120919863.

Ben Goertzel, PhD http://goertzel.org

"The reasonable man adapts himself to the world: the unreasonable one persists in trying to adapt the world to himself. Therefore all progress depends on the unreasonable man." -- George Bernard Shaw

jswiergo commented 9 years ago

When pattern matching, some links can be evaluated to yield a truth value; others can be executed, yielding an atom; in either case, its not obvious what to do when these are not nested in a way that "makes sense".

This is probably due to historical design, but what if every link that is evaluable/executable yield only atoms? Instead of truth value yield TrueValueNode or something like that? Maybe there is something I am not aware? Then there would be no problem with nesting such atoms for example within ListLink. Sometimes types of atoms would not match but it may happen for many other types too and could report type error.

Having that, quoted evaluatable links would be matched without evaluation, unquoted would be matched after evaluation, replaced by the atom being a result of evaluation/execution.

Just throwing the idea up, not sure how poor it is :-)

bgoertzel commented 9 years ago

On Mon, Jul 13, 2015 at 10:48 AM, Jacek Świergocki <notifications@github.com

wrote:

When pattern matching, some links can be evaluated to yield a truth value; others can be executed, yielding an atom; in either case, its not obvious what to do when these are not nested in a way that "makes sense".

This is probably due to historical design, but what if every link that is evaluable/executable yield only atoms? Instead of truth value yield TrueValueNode or something like that? Maybe there is something I am not aware?

That would not be problematic so far as I know.... To consider that when e.g. InheritanceLink is evaluated it yields a TruthValueNode...

Then there would be no problem with nesting such atoms for example within ListLink. Sometimes types of atoms would not match but it may happen for many other types too and could report type error.

Having that, quoted evaluatable links would be matched without evaluation, unquoted would be matched after evaluation, replaced by the atom being a result of evaluation/execution.

I am not sure that we want "match after evaluation" to be the default for logical link types though.

Almost all the time, when e.g. InheritanceLink occurs in a pattern to be matched, it is intended to be literally matched and not matched-after-evaluation...

So it seems that the default for logical links should be match-literally ...

-- Ben

ngeiswei commented 9 years ago

FunQuoteLink

Definition

Quote only the functional part of a functional link.

Example

Imagine you want to match the following without executing the EqualLink, but you still want to execute its arguments, you can't use a QuoteLink (cause you want to execute the arguments), but you can use a FunQuoteLink, to quote only the Equal part:

FunQuoteLink
   EqualLink
      ExecutionOutputLink
         GSN "ToBeRunAtPMTime-1"
      ExecutionOutputLink
         GSN "ToBeRunAtPMTime-2"

Is that clear?

ngeiswei commented 9 years ago

GSN "ToBeRunAtPMTime-1" and GSN "ToBeRunAtPMTime-2" will still be executed at PM time. So it's really like writing

('equal arg1 arg2)

in LISP.

bgoertzel commented 9 years ago

Yeah, now I get it... this seems a useful mechanism, sure... basically your FunQuoteLink is like a LISP quote, and the current QuoteLink is like a LISP '( ... )

I don't care what they're named, but both of these seem useful mechanisms...

Still I think the default for logical links should be literal matching, so we still need QuoteLink, UnquoteLink (my DoThisLink) and LocalQuoteLink/FunQuoteLink/whatever ...

Anyway I think the matter is conceptually clear now -- we just need to add a bit more language mechanism to make it convenient to explicitly specify a full spectrum of behaviors...

On Mon, Jul 13, 2015 at 11:01 AM, ngeiswei notifications@github.com wrote:

GSN "ToBeRunAtPMTime-1" and GSN "ToBeRunAtPMTime-2" will still be executed at PM time. So it's really like writing

('equal arg1 arg2)

in LISP.

— Reply to this email directly or view it on GitHub https://github.com/opencog/atomspace/issues/132#issuecomment-120959265.

Ben Goertzel, PhD http://goertzel.org

"The reasonable man adapts himself to the world: the unreasonable one persists in trying to adapt the world to himself. Therefore all progress depends on the unreasonable man." -- George Bernard Shaw

jswiergo commented 9 years ago

I have one more issue. It seems to me that we need to somehow distinguish logical links from the of top of the query that connect clauses to be matched from logical links that are inside part of the clause?

AndLink
   clause1
   OrLink
      clause2
      clause3

The former links should be evaluated by default, because we are not searching for them, the latter should be matched literally by defaut. How can we deal with that?

jswiergo commented 9 years ago

Pattern matcher searches for each clause separately.

bgoertzel commented 9 years ago

It seems to me that we must have a single default behavior for each link type, rather than different defaults for a single link type depending on position.. the latter seems way too confusing to me...

On Mon, Jul 13, 2015 at 11:20 AM, Jacek Świergocki <notifications@github.com

wrote:

I have one more issue. It seems to me that we need to somehow distinguish logical links from the of top of the query that connect clauses to be matched from logical links that are inside part of the clause?

AndLink clause1 OrLink clause2 clause3

The former links should be evaluated by default, because we are not searching for them, the latter should be matched literally by defaut. How can we deal with that?

— Reply to this email directly or view it on GitHub https://github.com/opencog/atomspace/issues/132#issuecomment-120965038.

Ben Goertzel, PhD http://goertzel.org

"The reasonable man adapts himself to the world: the unreasonable one persists in trying to adapt the world to himself. Therefore all progress depends on the unreasonable man." -- George Bernard Shaw

ngeiswei commented 9 years ago

Oh, another good example of LocalQuoteLink (maybe a better name than FunQuoteLink)

LocalQuoteLink
   AndLink
      clause1
      OrLink
         clause2
         clause3

very useful if clause{1..3} contain variables.

ngeiswei commented 9 years ago

@jswiergo yes, if we're to turn black box TV operations (currently in scheme) into atomese we need TVNode, Get/SetTVLink, etc.

linas commented 9 years ago

I still like William's last suggestion seems best: any evaluatable not inside a logical link should just be matched as a normal atom.

LocalQuoteLink and BelongLink seem to be the same thing.

bgoertzel commented 9 years ago

No, that fails sometimes ... I'll type an example a little later ... On Jul 15, 2015 8:00 PM, "Linas Vepštas" notifications@github.com wrote:

I still like William's last suggestion seems best: any evaluatable not inside a logical link should just be matched as a normal atom.

LocalQuoteLink and BelongLink seem to be the same thing.

— Reply to this email directly or view it on GitHub https://github.com/opencog/atomspace/issues/132#issuecomment-121780434.

bgoertzel commented 9 years ago

Well, I was thinking, suppose we have something like

(ExecutionOutputLink
     GroundedSchemaNode "choose_link.py")
     GreaterThanLink
             NumberNode $X
             NumberNode "3"
     EvaluationLink
            GroundedPredicateNode "myfunc.py"
            NumberNode $X

Suppose that choose_link.py internally runs a random number generator, and 50% of the time returns InheritanceLink, and 50% of the time returns ListLink...

Then, until running the ExecutionOutputLink, you cannot know whether the GreaterThanLink is inside a logical link or not...

I guess you could solve this by evaluating the ExecutionOutputLink first. But then the evaluation order becomes important, and in more complex cases you have to pay a lot of attention to which things you're evaluating before which other things.....It's probably solvable but it becomes complicated...

Heh ... how about

(ExecutionOutputLink
     GroundedSchemaNode "choose_link.py"
     [123])
     GreaterThanLink [123]
             NumberNode $X
             NumberNode "3"
     EvaluationLink
            GroundedPredicateNode "myfunc.py"
            NumberNode $X

Then we have a conundrum -- the choice of whether the outside link is a logical link or not, depends on the choice of whether the outside link is a logical link or not...

If we make choose_link.py output InheritanceLink whenever [123] is NOT evaluated, and output ListLink whenever [123] is evaluated, then we have an error...

Of course you can say "just don't do this shit" ... but I have a feeling this sort of problem would arise in some real application before too long...

...

Having context-free rules regarding what is evaluated and what is taken literally, avoids any weird cases...

ben

On Wed, Jul 15, 2015 at 8:13 PM, Ben Goertzel ben@goertzel.org wrote:

No, that fails sometimes ... I'll type an example a little later ... On Jul 15, 2015 8:00 PM, "Linas Vepštas" notifications@github.com wrote:

I still like William's last suggestion seems best: any evaluatable not inside a logical link should just be matched as a normal atom.

LocalQuoteLink and BelongLink seem to be the same thing.

— Reply to this email directly or view it on GitHub https://github.com/opencog/atomspace/issues/132#issuecomment-121780434.

Ben Goertzel, PhD http://goertzel.org

"The reasonable man adapts himself to the world: the unreasonable one persists in trying to adapt the world to himself. Therefore all progress depends on the unreasonable man." -- George Bernard Shaw

linas commented 9 years ago

I kind-of-ish see the point, and "rules that are not context sensitive" is an appealing position... but the example is flawed: If you evaluated GreaterThanLink and the EvaluationLink first, both would turn into TV's, which are not valid arguments for a grounded schema node. So, in this case, bottom-up evaluation would throw an error.

linas commented 9 years ago

I still don't see any particularly appealing solutions. The choices seem to be:

1) Invent a BelongsLink (or ExistsLink) which evaluates to true is the thing it wraps exists in the atomspace (i.e. can be grounded). All top-level clauses in a pattern must then be something that evaluates to true/false. In order to execute grounded schema that are inside an ExistsLink, one also needs to DoExecuteLink. Pros: unambiguous: Cons: verbose.

2) Like 1), except that we infer where the BelongsLink and the DoExecuteLink might naturally lie. Pros: less verbose: Cons: inference causes links to behave in a context-sensitive way.

3) Invent a DoThisLink (or DoEvaluateLink) so that evaluation is never done unless soemthing is wrapped by a DoEvaluateLink. All top-level clauses in a pattern must then be something that can be literally matched. This seems to require a FunQuoteLink and a DoExecuteLink as well. Also, need to invent a new MatchTheseClausesLink to replace the AndLink that is currently used at the top, to specify multiple clauses to match. Pros: unambiguous: Cons: verbose.

4) Like 3) except that we infer where the DoThisLink etc. might naturally lie. Pros: less verbose: Cons: inference causes links to behave in a context-sensitive way. Basically, 4) is like 2)

The "inference" here is kind-of-like "type inference": certain operations just don't make sense in certain situations; ergo they can't be right, and a different inference must be made. So 4) is like 2) and uses inference to figure out the right thing to do.

Choices 1) and 3), by contrast, will have many invalid formulations, and will result in lots of errors being thrown unless everything is just so. Choices 1 and 3 are kind-of-like "strict type checking" or "compile-time type-checking".

choice 5) do all of the above: inference is done, unless the user wants to have strict type checking, in which case, the DoThisLink, etc must all be explicitly used.

bgoertzel commented 9 years ago

I think it could be OK to have a solution that

-- uses inference for "simple" cases, i.e. where the links required for inference are all explicitly there in the expression

-- in complex cases where inference doesn't work for some reason, throws an error and asks the user to explicitly specify things

That way simple PM queries will "just work", but complex behaviors will also be specifiable by advanced users...

So, I guess that's 6,

6) Do inference where it's easy and obvious (which does entail context-dependent interpretation), otherwise make the user specify things and do strict type-checking

... ben

On Thu, Jul 16, 2015 at 7:49 AM, Linas Vepštas notifications@github.com wrote:

I still don't see any particularly appealing solutions. The choices seem to be:

1) Invent a BelongsLink (or ExistsLink) which evaluates to true is the thing it wraps exists in the atomspace (i.e. can be grounded). All top-level clauses in a pattern must then be something that evaluates to true/false. In order to execute grounded schema that are inside an ExistsLink, one also needs to DoExecuteLink. Pros: unambiguous: Cons: verbose.

2) Like 1), except that we infer where the BelongsLink and the DoExecuteLink might naturally lie. Pros: less verbose: Cons: inference causes links to behave in a context-sensitive way.

3) Invent a DoThisLink (or DoEvaluateLink) so that evaluation is never done unless soemthing is wrapped by a DoEvaluateLink. All top-level clauses in a pattern must then be something that can be literally matched. This seems to require a FunQuoteLink and a DoExecuteLink as well. Also, need to invent a new MatchTheseClausesLink to replace the AndLink that is currently used at the top, to specify multiple clauses to match. Pros: unambiguous: Cons: verbose.

4) Like 3) except that we infer where the DoThisLink etc. might naturally lie. Pros: less verbose: Cons: inference causes links to behave in a context-sensitive way. Basically, 4) is like 2)

The "inference" here is kind-of-like "type inference": certain operations just don't make sense in certain situations; ergo they can't be right, and a different inference must be made. So 4) is like 2) and uses inference to figure out the right thing to do.

Choices 1) and 3), by contrast, will have many invalid formulations, and will result in lots of errors being thrown unless everything is just so. Choices 1 and 3 are kind-of-like "strict type checking" or "compile-time type-checking".

choice 5) do all of the above: inference is done, unless the user wants to have strict type checking, in which case, the DoThisLink, etc must all be explicitly used.

— Reply to this email directly or view it on GitHub https://github.com/opencog/atomspace/issues/132#issuecomment-121934739.

Ben Goertzel, PhD http://goertzel.org

"The reasonable man adapts himself to the world: the unreasonable one persists in trying to adapt the world to himself. Therefore all progress depends on the unreasonable man." -- George Bernard Shaw

ngeiswei commented 8 years ago

Personal Taste

I kinda liked the QuoteLink, UnquoteLink, LocalQuoteLink, LocalUnquoteLink terminology.

The Proposal

Here's what I suggest

  1. By default everything is quoted. You've got to explicitly use UnquoteLink or LocalUnquoteLink to evaluate
  2. Remove the optional root AndLink (for multiple clauses) and have instead BindLink take an arbitrary arity. That way we don't need to create a new AndBindLink just for that, or start inferring stuff about what is quoted and what is not.

That's definitely the way I go about that. I know it's gonna make expressing evaluatable things more verbose but at the benefit of not having to struggle with weird corner cases and ambiguities. If some patterns start emerging then we can always create functions (scheme or even Atomese) to simplify writing them, but trying to compress too much the primitives is a bad idea.

Example

So for instance the deduction rule would be expressed as followed

    (BindLink
        (VariableList
                (VariableNode "$A")
                (VariableNode "$B")
                (VariableNode "$C"))
        (InheritanceLink
            (VariableNode "$A")
            (VariableNode "$B")
        )
        (InheritanceLink
            (VariableNode "$B")
            (VariableNode "$C")
        )
        ; To avoid matching (Inheritance A B) and (Inheritance B A)
        (UnquoteLink
            (NotLink
                (EqualLink
                    (VariableNode "$A")
                    (VariableNode "$C")
                )
            )
        )
        (ExecutionOutputLink
            (GroundedSchemaNode "scm: pln-formula-simple-deduction")
            (ListLink
                (InheritanceLink
                    (VariableNode "$A")
                    (VariableNode "$B"))
                (InheritanceLink
                    (VariableNode "$B")
                    (VariableNode "$C")
                )
                (InheritanceLink
                    (VariableNode "$A")
                    (VariableNode "$C")
                )
            )
        )
    )
ngeiswei commented 8 years ago

So the first argument of BindLink would still be the optional variables. The last one the rewrite rule. The ones in between the clauses. I think it is unambiguous and compact (which leaves room for some extra UnquoteLinks).

What do you guys say?

ngeiswei commented 8 years ago

Oh, I didn't realize but you still need the assumption that VariableNode are unquote. Well, if that's just that I think it's OK. Hmmm...

ngeiswei commented 8 years ago

Yeah, I mean variables are declared in the first arg of BindLink, I think it is extremely unambiguous that they are unquoted. So, yes, that is the way I would go about it. We could always keep the current BindLink and create a new PMLink that follows that syntax and keep the BindLink around till everythink has been converted to PMLink and we're sure we like it.

williampma commented 8 years ago

How would you go about pattern matching literally on UnquoteLink/QuoteLink? If a part of the clause inside the QuoteLink you want to unquote, and a part of the clause inside a UnquoteLink you want to quote, etc.

I actually prefer a solution without introducing more atom types, because any atom types introduced will eventually need to be matched literally (since the pattern is auto-generated by code).

ngeiswei commented 8 years ago

I think using LocalQuoteLink should do the trick, for instance to match

UnquoteLink
    VariableNode "$X"

you'd write

PMLink
   VariableNode "$X"
   LocalQuoteLink
       UnquoteLink
          VariableNode "$X"
   <rewrite>

an UnquoteLink can undo a QuoteLink but not a LocalQuoteLink cause it's on the link type itself.

Now I wonder whether

PMLink
   QuoteLink
      VariableNode "$X"
   <rewrite>

would match things like

QuoteLink
   ConceptNode "A"

or

VariableNode "$X"

BindLink would match the latter. If we use BindLink convention it means we assume that a QuoteLink over a quoted expression quotes variables. I guess that would be OK.

Introducing new links means indeed taking care of how to match them, but it's still simpler than keeping track of what is evaluatable and what is not.

Ultimately I don't mind having the quote being escaped by what is evaluatable, as long as the behavior is well documented. But the more complicated it gets the harder it is to well document anyway.

bgoertzel commented 8 years ago

The OpenCog HK team has discussed this F2F with Cassio a bit earlier this week...

The general conclusion was that, ugly as it is, introducing systematic use of QuoteLink and UnquoteLink is probably the only way to go...

Of course, we could syntactically sugar this in the Scheme/python shells somehow if we want to, but in terms of the Atomspace representation, QuoteLink/UnquoteLink are basically right... and other options are going to confuse people even more...

ben

On Tue, Jul 28, 2015 at 3:31 PM, ngeiswei notifications@github.com wrote:

I think using LocalQuoteLink should do the trick, for instance to match

UnquoteLink VariableNode "$X"

you'd write

PMLink VariableNode "$X" LocalQuoteLink UnquoteLink VariableNode "$X"

an UnquoteLink can undo a QuoteLink but not a LocalQuoteLink cause it's on the link type itself. Now I wonder whether PMLink QuoteLink VariableNode "$X" would match things like QuoteLink ConceptNode "A" or VariableNode "$X" BindLink would match the latter. If we use BindLink convention it means we assume that a QuoteLink over a quoted expression quotes variables. I guess that would be OK. Introducing new links means indeed taking care of how to match them, but it's still simpler than keeping track of what is evaluatable and what is not. Ultimately I don't mind having the quote being escaped by what is evaluatable, as long as the behavior is well documented. But the more complicated it gets the harder it is to well document anyway. — Reply to this email directly or view it on GitHub https://github.com/opencog/atomspace/issues/132#issuecomment-125483152.

Ben Goertzel, PhD http://goertzel.org

"The reasonable man adapts himself to the world: the unreasonable one persists in trying to adapt the world to himself. Therefore all progress depends on the unreasonable man." -- George Bernard Shaw

williampma commented 8 years ago

Humm... I wasn't aware of reaching a conclusion.

bgoertzel commented 8 years ago

Hah .. OK, maybe only Cassio and I reached a conclusion in our own minds ;D

Our conclusion was just to copy LISP, which seems to be Nil's inclination also...

What is your current preferred option?

ben

On Fri, Aug 14, 2015 at 5:13 PM, William Ma notifications@github.com wrote:

Humm... I wasn't aware of a reaching a conclusion.

— Reply to this email directly or view it on GitHub https://github.com/opencog/atomspace/issues/132#issuecomment-131034839.

Ben Goertzel, PhD http://goertzel.org

"The reasonable man adapts himself to the world: the unreasonable one persists in trying to adapt the world to himself. Therefore all progress depends on the unreasonable man." -- George Bernard Shaw

williampma commented 8 years ago

Does the LISP method allows you to evaluate part of the stuff inside quote? I recall Cassio mentioned UnquotedVariableNode, but what if you want to match UnquotedVariableNode literally (ie. you want to quote the UnquotedVariableNode)?

I don't think the system can have "unquote" anything since it is possible to lead to conflict. The solution will have to contain only "quoting".

Maybe Nil's LocalQuoteLink that only works on link would work (with QuoteLink works on everything), and no "unquote" anywhere.

As I said, since the pattern are auto-generate (as oppose to someone defining it by hand), if the atom is in the AtomSpace, it will be Pattern Matched eventually.

Suppose at one point we want to ground $A & $B in

EqualLink
  $A
  $B

without evaluating the EqualLink, then we added the following

LocalQuoteLink
  EqualLink
    $A
    $B

Now that the above is in the AtomSpace, we might at some step want to ground

LocalQuoteLink
  EqualLink
    $A
    $B

while matching the LocalQuoteLink as is, while grounding $A & $B, and not evaluating the EqualLink. Then do we add

LocalQuoteLink
   LocalQuoteLink
     EqualLink
       $A
       $B

what happens to the EqualLink now that the LocalQuoteLink wrapping it is not evaluated... is the EqualLink now executed?? I guess we should add

LocalQuoteLink
   LocalQuoteLink
      LocalQuoteLink
        EqualLink
          $A
          $B

so that the outer LocalQuoteLink quote the middle one, and the inner one quote the EqualLink. Now that this atom is in the AtomSpace, how to match it as is, while grounding $A, $B, so we add

LocalQuoteLink
 LocalQuoteLink
   LocalQuoteLink
    LocalQuoteLink
     LocalQuoteLink
      LocalQuoteLink
       LocalQuoteLink
        EqualLink
          $A
          $B

Maybe this is correct, and that's what needed. Kind of like doing printf("\\\\\\\\\\\\\\n") to print 6 \ in C.

williampma commented 8 years ago

There might be strange confusing interaction between LocalQuoteLink & QuoteLink though.

Suppose again we have

  EqualLink
    $A
    $B

which we want to match literally without grounding, we do

QuoteLink
  EqualLink
    $A
    $B

Now that the above is in the AtomSpace, we want to match as is, so if we do

LocalQuoteLink
  QuoteLink
    EqualLink
      $A
      $B

we will ended up not evaluating the QuoteLink, and ended up making EqualLink evaluatable, and $A & $B ground-able.

So maybe the solution is to only have QuoteLink (no LocalQuoteLink) but makes it only work on its top atom, so

QuoteLink
  EqualLink
    QuoteLink
       $A
    QuoteLink
       $B

is needed to quote the original atom.

bgoertzel commented 8 years ago

To be more exact about how LISP works, look at the Backquote specification

http://www.gnu.org/software/emacs/manual/html_node/elisp/Backquote.html

So I think the LISP backquote is like our QuoteLink, and the LISP comma (embedded in a backquoted expression somewhere) is like our proposed (and perhaps badly named) UnquoteLink ...

I'm not sure if we have use for some analogue of the LISP splicing operator " ,@ " ...

LISP also has quasiquotes, which get complificated...

http://3e8.org/pub/scheme/doc/Quasiquotation%20in%20Lisp%20(Bawden).pdf

-- Ben

On Fri, Aug 14, 2015 at 6:16 PM, William Ma notifications@github.com wrote:

There might be strange confusing interaction between LocalQuoteLink & QuoteLink though.

Suppose again we have

EqualLink $A $B

which we want to match literally without grounding, we do

QuoteLink EqualLink $A $B

Now that the above is in the AtomSpace, we want to match as is, so if we do

LocalQuoteLink QuoteLink EqualLink $A $B

we will ended up not evaluating the QuoteLink, and ended up making EqualLink evaluatable, and $A & $B ground-able.

So maybe the solution is to only have QuoteLink (no LocalQuoteLink) but makes it only work on its top atom, so

QuoteLink EqualLink QuoteLink $A QuoteLink $B

is needed to quote the original atom.

— Reply to this email directly or view it on GitHub https://github.com/opencog/atomspace/issues/132#issuecomment-131059516.

Ben Goertzel, PhD http://goertzel.org

"The reasonable man adapts himself to the world: the unreasonable one persists in trying to adapt the world to himself. Therefore all progress depends on the unreasonable man." -- George Bernard Shaw