Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support executing ungrounded Schemata/Predicates #48

Closed
ngeiswei opened this issue May 19, 2015 · 15 comments
Closed

Support executing ungrounded Schemata/Predicates #48

ngeiswei opened this issue May 19, 2015 · 15 comments

Comments

@ngeiswei
Copy link
Member

Disclaimer

I'm writing that based solely on

http://wiki.opencog.org/w/Scheme#cog-execute.21

and

http://wiki.opencog.org/w/ExecutionLink

I didn't try to run cog-execute! to actually see what is or not supported.

Proposal

Given

ExecutionLink
   SchemaNode "S"
   <Inputs>
   <Output>
[1]

and

ExecutionOutputLink
   SchemaNode "S"
   <Inputs>
[2]

If cog-execute! is called on [2] it should return the output defined in [1].

Dealing with Multiple Outputs

If there are more than one output for the same inputs, then it may either

  1. raise an error,
  2. return the distribution of outputs,
  3. or select one according to that distribution.

The distribution would be defined by the TVs on the ExecutionLinks (TVs representing probabilities according to http://wiki.opencog.org/w/OpenCogPrime:FunctionNotation#Execution_Links).

It seems acceptable if, for starter, it simply raises an error. Maybe the other options should be delegated to other functions than cog-execute!.

Motivation Behind the Proposal

That way whether you store a value using an ExecutionLink, a GroundedSchemaNode or a PutLink, the way to obtain it would be almost the same, a call of cog-execute! over an ExecutionOutputLink or GetLink.

@ngeiswei
Copy link
Member Author

The following page talks about the TV semantics on an ExecutionLink, it is its probability of returning a certain output given the inputs.

http://wiki.opencog.org/w/OpenCogPrime:FunctionNotation#Execution_Links

@linas
Copy link
Member

linas commented May 19, 2015

Let me clarify one point that urgently needs clarification: the word "return" means different things in different contexts. When you call a scheme/python function it "returns" a value (which may be an atom, a TV, or none of the above) As a side-effect, the scheme/python function may also put something into the atomspace.

When you say "return" above, I think you mean "place into the atomspace as a side-effect". Maybe. I'm not sure, I'm confused.

Let me explain what cog-execute! currently does. .. err I am writing up http://wiki.opencog.org/w/Cog-execute! right now. More discussion later.

@linas
Copy link
Member

linas commented May 20, 2015

OK, I've written up http://wiki.opencog.org/w/Cog-evaluate! http://wiki.opencog.org/w/Cog-execute! and http://wiki.opencog.org/w/Cog-reduce!

The short answer is: cog-execute! always returns an atom, or undefined-handle. If you want it to return something some particular format, such as that proposed above, then you should write your scheme or python callback to return the particular form that you want. This is not hard to do. Alternately, you/we could invent another function, say cog-execute-output! that returns the format that you want. I think it would take maybe 3-7 lines of scheme code to implement cog-execute-output! on top of the existing cog-execute! -- its simply a cut-n-paste of arguments and results into a template. This is not challenging. The only question is where to put that code: in one of the modules, e.g. the query module, or in in one of the utility files.

@ngeiswei
Copy link
Member Author

I'm about to read all that, but already I see that you suggest to not use cog-execute! for that job but rather another function.

However there's perhaps a deeper question. We're gonna need, sooner or later, a way to convert ungrounded schemata into grounded ones, or at least a way to "execute" ungrounded schemata. I wonder whether we want to have that in the main cog-execute! function or a separate one. I don't have the answer I'm just wondering. Or maybe we want to split cog-execute! into 2 functions

  1. cog-grounded-execute!
  2. cog-ungrounded-execute!

and have cog-execute! call one or the other depending on whether the schema is grounded or not.

Just wondering...

@ngeiswei
Copy link
Member Author

I read. Again that doesn't allows me to take a decision as to whether cog-execute! should handle ungrounded schemata.

Just to be absolutely clear of what I mean (as I haven't provided an example in the proposal above): suppose we have

ExecutionLink
   SchemaNode "weather-in"
   ConceptNode "France"
   ConceptNode "Sunny"

Which indicates that the schema

weather-in(France) = Sunny

They I would like to be able to do

(cog-execute! (ExecutionOutputLink (SchemaNode "weather-in") (ConceptNode "France")))

and get in return

(ConceptNode "Sunny")

If I do

(cog-execute! (ExecutionOutputLink (SchemaNode "weather-in") (ConceptNode "UK")))

and I don't have any ExecutionLink record of UK's wheather, then it would raise an exception (or return undefined handle).

If I have multiple records of the weather in France, then it would raise an exception or perhaps return a distribution of weathers, etc.

@ngeiswei
Copy link
Member Author

Or maybe we should forbid such a thing as an ExecutionOutputLink over an ungrounded schema node, that is the following should perhaps not be valid Atomese code

ExecutionOutputLink
   (SchemaNode "weather-in")
   ...

And we should only allow ExecutionOutputLink over grounded schemata, or clear-box schemata (like PlusLink, etc.), or combinations thereof.

It's a bit tricky and I'm not sure what is the right decision. Is it gonna bite us in the future if we add ungrounded execution in cog-execution!? In particular how is the PM gonna chew that?

@linas
Copy link
Member

linas commented May 21, 2015

The weather-in-france example is trivial and can be done in maybe 1 or 2 lines of scheme code.  So I don't see what the problem is. Just write the utility function for it, its not hard.

This file: https://github.com/opencog/atomspace/blob/master/opencog/scm/utilities.scm is filed with utilities of this sort. The code you want is this:

(define (nils-exec atom)
   (gdr (car (cog-chase-link 'ExecutionLink 'ListLink (gar atom)))))

Try it... the following should work:

guile
(use-modules ((opencog)))
(load-from-path "utilities.scm")

(ExecutionLink
   (SchemaNode "weather-in")
   (ListLink
      (ConceptNode "France")
      (ConceptNode "Sunny")))

(define french-weather
   (ExecutionOutputLink 
      (SchemaNode "weather-in") (ConceptNode "France")))

(define (nils-exec atom)
   (gdr (car (cog-chase-link 'ExecutionLink 'ListLink (gar atom)))))

(nils-exec french-weather)

ant the output will be

(ConceptNode "Sunny")

Note that at no point is there any pattern matching, any variable, any variable substitution, any unification, any evaluation of any callbacks or any use of C++ code except for the bare-bones-basic atompsace API of creating atoms, and getting their incoming and outgoing sets.

cog-execute! was invented to solve more complex problems than this. now, cog-execute could have been written in pure scheme, in maybe 10-15 lines of code, except that it would have struggled to call python callbacks, and also, would not have helped with the guts of the pattern matcher. But if you don't need the pattern matcher, or python, then its .. I dunno ... pretty trivial.

@linas
Copy link
Member

linas commented May 21, 2015

FYI, this is also why I say that PutLink and GetLink are trivial, kind of too trivial to bother with if you are not using them outside of the pattern matcher. They only become non-trivial when you have variables that occur inside of them. But, as I mentioned before, AssignLink and friends do this in a better, more general way.

Note also: most patterns that have variables in them are so simple, that you don't really need the pattern matcher, and you don't need BindLink, or any of that cruft. If you look at the PLN rules that the forward/backaward chainer are applying, they are all really pretty simple, having maybe one or two variables in them. You really really don't need the big-ass heavyweight machinery of the pattern-matcher to solve these: you could have solved them in .. I dunno 10-20-30 lines of scheme code, maybe 50-100 lines of c++ code. Recall Jade did this (or tried to do this) in python, in last-years PLN. For what PLN needs, that kind of simple pattern matching is enough.

What the pattern matcher does is to solve the general problem, with N variables and M clauses in it. This starts to become really hard for N,M>2 but if N=1 or 2 and M=1 or 2, like it is for PLN, then those cases are essentially trivial, and can be exhaustively enumerated by hand.

@linas
Copy link
Member

linas commented May 21, 2015

Just to be clear: the nils-exec scheme snippet shows exactly how trivial it is: it performs a kind-of "pattern match" in one line of code. It implicitly has three variables in it: X Y and Z and you give it a question "whats the X in Y" and it answers Z. You just do this:

(nils-exec (ExecutionOutputLink X Y))

and it will return Z. So, where's another variant:

(define (get-link x y)
   (nils-exec (ExecutionOutputLink (SchemaNode x) (ConceptNode y))))

(get-link "weather-in" "France")

which should return (ConceptNode "Sunny") and you can do

(define (put-link x y z)
   (ExecutionLink (SchemaNode x)
      (ListLink (ConceptNode y) (ConceptNode z))))

(put-link "weather-in" "England" "rainy")
(get-link "weather-in" "England")

should return "rainy"

@linas
Copy link
Member

linas commented May 21, 2015

If the above sounds harsh, then please do recall, there is no such thing as "trivial code", there is only "buggy trivial code". I ran the above, and it failed. The correct code is this:

(define (nils-exec atom)
   (gdr (car 
      (filter (lambda (elt) (equal? (gar elt) (gdr atom)))
         (cog-chase-link 'ExecutionLink 'ListLink (gar atom))))))

which is now 4 lines of code. And of course, put-link should delete the old state before setting the new state:

(define (put-link x y z)
   (cog-delete (ExecutionLink (SchemaNode x)
      (ListLink (ConceptNode y) (get-link x y))))
   (ExecutionLink (SchemaNode x)
      (ListLink (ConceptNode y) (ConceptNode z))))

so that the following works:

(put-link "weather-in" "England" "cloudy")
(get-link "weather-in" "England")
(put-link "weather-in" "England" "sunny and warmer")
(get-link "weather-in" "England")

@ngeiswei
Copy link
Member Author

Thanks, Linas. Part of my question is whether this code should be integrated to cog-execute! I would probably say yes, but maybe that would violate the "do one thing and do it well" principle.

@ngeiswei
Copy link
Member Author

I don't mean this code (given its a scheme code and cog-execute! is written in C++), I mean this functionality. If you think it shouldn't, I'll add some C++ code for it and a scheme binding called cog-execute-ungrounded! (unless a better name comes up).

@linas
Copy link
Member

linas commented May 22, 2015

Two remarks, one positive, one negative. First, the negative one:

  1. I strongly, sharply and completely object to modifying cog-execute! The function that you describe is totally different and completely unrelated to what cog-execute does. They are completely different things, and trying to mash them together would be very wrong. More generally, we should only implement "basic core functions". If someone needs some whizzy, shiny utility, hey, it should be easy to build on top of the core functions. As I show above: you want a whizzy shiny utility, so .. stick it in some utility library, if you wish. I know that, as a matter of course, that a month or two later, @williampma or @misgeatgit or @amebel will want something similar but slightly different, and they too should be allowed to create the similar-but-slightly different code. I have no objection to your adding nils-exec to the utilities.scm: it already contains nearly two dozen routines that are almost identical to nils-exec, except that they're different: some run parallel threads, some offer additional debugging features, etc. There's nothing about the nils-exec code that makes it more basic, or more fundamental or more important than any of these other utils. Its just another whiz-bang neat trick you can do with atoms.

  2. I've completely recanted on PutLink and GetLink. This is because I realized that the code for PutLink has already been written: its currently called "BetaRedexLink" I'm putting together the wiki page here: http://wiki.opencog.org/w/PutLink

@ngeiswei
Copy link
Member Author

I agree with that, thanks for the feedback.

@linas
Copy link
Member

linas commented Aug 13, 2016

closing, I think this is a resolved issue.

@linas linas closed this as completed Aug 13, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants