opencog / atomspace

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

Question about ForAllLink #2018

Closed stellarspot closed 5 years ago

stellarspot commented 5 years ago

I have cat and dog which are mammalia and have 4 legs. And ant which is insect and has 6 legs. Is it right to use ForAllLink for a question like: Find a class each member of it has 4 legs?

The code below shows nothing as result instead of expected cat and dog:

(use-modules (opencog) (opencog query) (opencog exec))

(define cat (Concept "cat"))
(define dog (Concept "dog"))
(define mammalia (Concept "mammalia"))

(define ant (Concept "ant"))
(define insect (Concept "insect"))

(define key (Predicate "legs-number"))

(define (legs-number who legs)
 (Evaluation key who (Number legs)))

(Inheritance cat mammalia)
(Inheritance dog mammalia)
(legs-number cat 4)
(legs-number dog 4)

(Inheritance ant insect)
(legs-number ant 6)

; Find $X that
; For All (Inheritance $Y $X)
; (legs-number $Y 4)

(define pattern
 (Bind
  (Variable "$X")
  (ForAll
   (Variable "$Y")
   (And
    (Inheritance
     (Variable "$Y")
     (Variable "$X"))
    (Evaluation
     key
     (Variable "$Y")
     (NumberNode 4))))
  (Variable "$X")))

(display
 (cog-execute! pattern)
)
linas commented 5 years ago

This will do what you want (I think)

(define pattern
    (Bind
      ;; Variable declarations: Search requires two variables
      (VariableList (Variable "$X") (Variable "$Y"))
      (And
         (Inheritance (Variable "$Y") (Variable "$X"))
         (Evaluation key (Variable "$Y") (Number 4)))

      ;; Return only one of the two variables
      (Variable "$X")))

Comments:

linas commented 5 years ago

Thinking to myself... perhaps BindLink should be renamed to ForAllLink ... BindLinks has the structure

for all x,y,z,...
    if p(x,y,z,...)
    then return q(x,y,z,...)

so BindLink could also be called "ImpliesLink" or "DeduceLink" or "FindLink", "SelectLink", "FilterLink" ... its a naming problem.

linas commented 5 years ago

I re-read your post. Actually, what you want is to return Y not X:

(define pattern
    (Bind
      ;; Search requires two variables
      (VariableList (Variable "$X") (Variable "$Y"))
      (And
         (Inheritance (Variable "$Y") (Variable "$X"))
         (Evaluation key (Variable "$Y") (NumberNode 4)))

      ;; Return one of the two variables
      (Variable "$Y")))
vsbogd commented 5 years ago

The code below shows nothing as result instead of expected cat and dog:

Should it be "The code below shows nothing as result instead of expected cat and dog mammalia" ?

stellarspot commented 5 years ago

Should it be "The code below shows nothing as result instead of expected cat and dog mammalia" ?

Yes, I am sorry. The purpose of the sample was to find mammalia and not insect.

stellarspot commented 5 years ago

I need something that I can use in Bind link and evaluates to true if it is true for all arguments. For example if I have predicates p(x, y) and p(y, z) and I want find z for the given x so for all y such p(y, z) it is also p(x, y)

Here z is mammalia or insect from the first sample, y is cat, dog, or ant and x are 4 or legs.

linas commented 5 years ago

I don't understand the last question. The BindLink found all y for which both p(y, z) and p(x, y) are true. (the answer was y can be dogs and cats and z is mamalia and that is exactly what the examples above found)

So can I conclude that your question was answered, or is there a different question?

stellarspot commented 5 years ago

The result of the code

(define pattern
 (Bind
  ;; Search requires two variables
  (VariableList (Variable "$X") (Variable "$Y"))
  (And
   (Inheritance (Variable "$Y") (Variable "$X"))
   (Evaluation key (Variable "$Y") (NumberNode 4)))

  ;; Return one of the two variables
  (Variable "$Y")))

gives:

(SetLink
   (ConceptNode "cat")
   (ConceptNode "dog")
)

But the required results should be

(SetLink
   (ConceptNode "mammalia")
)

That is why I tried to use ForAllLink in the BindLink, because I need to find classes each member of which has 4 legs.

linas commented 5 years ago

Did you actually try running the examples I provided?

stellarspot commented 5 years ago

Yes. Below is the full code that I run. I have also added dragon class which contains Wyvern dragon with 2 legs and Western style Dragon with 4 legs.

(use-modules (opencog) (opencog query) (opencog exec))

(define key (Predicate "legs-number"))
(define (legs-number who legs)
 (Evaluation key who (Number legs)))

; Mamalia
(define mammalia (Concept "mammalia"))
(define cat (Concept "cat"))
(define dog (Concept "dog"))

(Inheritance cat mammalia)
(Inheritance dog mammalia)
(legs-number cat 4)
(legs-number dog 4)

; Insect
(define insect (Concept "insect"))
(define ant (Concept "ant"))

(Inheritance ant insect)
(legs-number ant 6)

; Dragon
(define dragon (Concept "dragon"))
(define wyvern (Concept "wyvern"))
(define western-style-dragon (Concept "Western Style Dragon"))

(Inheritance wyvern dragon)
(Inheritance western-style-dragon dragon)
(legs-number wyvern 2)
(legs-number western-style-dragon 4)

(define pattern
 (Bind
  ;; Search requires two variables
  (VariableList (Variable "$X") (Variable "$Y"))
  (And
   (Inheritance (Variable "$Y") (Variable "$X"))
   (Evaluation key (Variable "$Y") (NumberNode 4)))

  ;; Return one of the two variables
  (Variable "$Y")))

(display
 (cog-execute! pattern)
)

The result is:

(SetLink
   (ConceptNode "Western Style Dragon")
   (ConceptNode "cat")
   (ConceptNode "dog")
)

The result contains cat and dog which is ok because mammalia consists of only animals with 4 legs. But it also returns Western Style Dragon which is not expected because dragon class contains not only dragons with 4 legs but with 2 legs as well.

Given the example I need to find classes each member of each has 4 legs. Mammalia is right answer because all members have 4 legs. Dragon is incorrect answer, because it elements have both 4 and 2 legs.

stellarspot commented 5 years ago

Here is a rephrased sample.

Suppose there are baskets which can contain fruits, vegetables, or both. The task is to find baskets each item of each is fruit.

(define fruite (Concept "Fruite"))
(define vegetable (Concept "Vegetable"))

(define apple (Concept "Apple"))
(define orange (Concept "Orange"))

(define potato (Concept "Potato"))
(define cucumber (Concept "Cucumber"))

(Inheritance apple fruite)
(Inheritance orange fruite)
(Inheritance potato vegetable)
(Inheritance cucumber vegetable)

(define basket1 (Concept "Basket 1"))
(define basket2 (Concept "Basket 2"))
(define basket3 (Concept "Basket 3"))

(Member apple basket1)
(Member orange basket1)

(Member apple basket2)
(Member potato basket2)

(Member potato basket2)
(Member cucumber basket2)

Expected answer is basket1 (both apple and orange are fruits). Basket 2 is not expected as answer because it contains not only fruits (apple and potato).

amebel commented 5 years ago

@stellarspot correct me if I am wrong

  1. The following query is saying, Find me all atoms (Variable "$Y") that have 4 legs and inherit from any class (Variable "$X").

    (define pattern
    (Bind
    ;; Search requires two variables
    (VariableList (Variable "$X") (Variable "$Y"))
    (And
    (Inheritance (Variable "$Y") (Variable "$X"))
    (Evaluation key (Variable "$Y") (NumberNode 4)))
    
    ;; Return members of the classes
    (Variable "$Y")))

    Thus you get the right answer

    (SetLink
    (ConceptNode "Western Style Dragon")
    (ConceptNode "cat")
    (ConceptNode "dog")
    )
  2. The following query is saying, Find me all classes (Variable "$X") that have members (Variable "$Y") with 4 legs.

    (define pattern
    (Bind
    ;; Search requires two variables
    (VariableList (Variable "$X") (Variable "$Y"))
    (And
    (Inheritance (Variable "$Y") (Variable "$X"))
    (Evaluation key (Variable "$Y") (NumberNode 4)))
    
    ;; Return the classes
    (Variable "$X")))

    This gives

    (SetLink
    (ConceptNode "mammalia")
    (ConceptNode "dragon")
    )
  3. But these are not what you want. "Dragon is incorrect answer, because it's elements have both 4 and 2 legs." So what you want to query is, Find me all classes (Variable "$X") that have members (Variable "$Y") with 4 legs, but with no members with 2 legs. Is that right?

stellarspot commented 5 years ago

So what you want to query is, Find me all classes (Variable "$X") that have members (Variable "$Y") with 4 legs, but with no members with 2 legs. Is that right?

Yes, it is right. I need to find all classes (Variable "$X") that have members (Variable "$Y") and each member of this class has only 4 legs (not 2, 5, or 6).

Or, using the example with baskets, I need to find baskets which contain only fruits.

linas commented 5 years ago

You can use NotLink when you want to invert the meaning of matches (for example, not equal to two legs). You can use AbsentLink to exclude presence of things (baskets where some items must be absent).

Once you start asking for complicated queries, then you have to be clever in how you design them. It's not always easy to design a query that returns just the right amount.

amebel commented 5 years ago
(define pattern                                                               
 (Bind                                                                        
  ;; Search requires 3 variables                                              
  (VariableList (Variable "x") (Variable "y0") (Variable "y1"))               
  (And                                                                        
   ;; The query makes sense if there is atleast two members, because the      
   ;; exclusion is in comparison to other members of the class.               
   (Inheritance (Variable "y0") (Variable "x"))                               
   (Inheritance (Variable "y1") (Variable "x"))                               

   ;; Don't campare a member with it self as it will satisfy the constraint.  
   (Not (Identical (Variable "y0") (Variable "y1")))

   (Evaluation key (Variable "y0") (NumberNode 4))                            
   (Absent                                                                    
        (Evaluation key (Variable "y1") (NumberNode 2))))                     

  ;; Return the class                                                      
 (Variable "x")))                                                             

It returns

(SetLink
   (ConceptNode "mammalia")
)

The above works for excluding classes with 2 legs, so will need to be extended to handle other number of legs

amebel commented 5 years ago

If you change the leg of ants to 4 the above wouldn't return insects because it assumes at least two members.

vsbogd commented 5 years ago

@AmeBel , I believe the original question is: Find me all classes (Variable "$X") where all of members have 4 legs

stellarspot commented 5 years ago

The above works for excluding classes with 2 legs, so will need to be extended to handle other number of legs

Yes, that is right. That is why it is a question about ForAllLink.

For example, there are baskets that contain balls with different colors (Bisque, Beige, Plum and so on). How can I write a query to find baskets that contain only green balls?

My assumption was that ForAllLink is designed to make such kind of queries. Is it possible to use a universal quantification inside the BindLink?

linas commented 5 years ago

My assumption was that ForAllLink is designed to make such kind of queries.

The ForAllLink is not implemented, and it doesn't do anything. My best possible advice is to forget about it, and pretend it doesn't exist.

Is it possible to use a universal quantification inside the BindLink?

The BindLink is always universally quantified. That is it's primary mode of operation.

amebel commented 5 years ago

@vsbogd Yes, extending the absent link to all possible numbers isn't possible, and the following gives empty set, so I am baffled.

(define pattern                                                                
 (Bind                                                                         
  ;; Search requires 4 variables                                               
  (VariableList (Variable "n") (Variable "x") (Variable "y0") (Variable "y1")) 
  (And                                                                         
   ;; The query makes sense if there is atleast two members, because the       
   ;; exclusion is in comparison to other members of the class.                
   (Inheritance (Variable "y0") (Variable "x"))                                
   (Inheritance (Variable "y1") (Variable "x"))                                

   ;; Don't compare a member with it self as it will satisfy the constraint.   
   (Not (Identical (Variable "y0") (Variable "y1")))                           

   (Evaluation key (Variable "y0") (Number 4))   

   ; Exclude all which don't have 4 legs                              
   (Not (Equal (Variable "n") (Number 4)))                                     
   (Absent                                                                     
        (Evaluation key (Variable "y1") (Variable "n"))))                      

  ;; Return the class                                                          
 (Variable "x")))                                                              
linas commented 5 years ago

To be clear: when I say "The BindLink is always universally quantified." I really mean if. When you say "for all baskets with green balls in them", you will get all baskets with green balls in them (even if those baskets also have ants and dragons in them). That is a different question than "baskets with only green balls in them, and no other colors or objects". Amen gave you and example of how to search for "this thing and not that thing". There are other ways to formulate "this but not that" kinds of questions.

rTreutlein commented 5 years ago

@AmeBel I also played around a bit and came up with this solution. Not sure why it doesn't return anything but I think this would still not produce the correct results as it would return any class that had 2 objects where 1 has 4 legs and the other also has 4 legs or no legs at all, but such a class could have even more objects which might not have 4 legs.

I do think to really solve this we would need a ForAll link that actually worked.

linas commented 5 years ago

Argh, I think there is a lot of confusion about what the words "for all" actually mean. Please rethink how you are trying to define and solve the problem. It's past midnight here, I am going to bed, if its still an issue tomorrow morning, I'll look at it.

Is this actually needed for anything, or is this an idle question?

vsbogd commented 5 years ago

Looks like FoldLink could be used to calculate that predicate holds true on the set of members for each class. But as far as I see there are only arithmetic fold links.

stellarspot commented 5 years ago

Is this actually needed for anything, or is this an idle question?

I am looking for a way to implement a graph message-passing algorithm in OpenCog where to send a message from node A to node B it needs to check that A has already received messages from nodes connected to it except B.

linas commented 5 years ago

@vsbogd it could be, should be possible to generalize FoldLink to "other things" but (1) no one has come up with a strong reason for doing it (2) I am nervous about trying to turn atomese into a functional programming language. It's not hard to invent/create a new programming language ("anyone can do that"); it is very hard to invent/create a good one.

linas commented 5 years ago

@stellarspot Can you tell me more? Are you passing messages between different computers, or different memory spaces on the same computer, or different objects within the same memory space? ("object-oriented programming"?) (i.e. passing messages between different objects in the same atomspace?)

linas commented 5 years ago

@stellarspot You can find the solution in two steps, shown below.

The first step finds all classes of things that contain creatures with other than 4 legs. When it finds such a class, it adds it to the set of "not-just-four-legged" classes.

(define find-not-four
 (Bind
  (VariableList (Variable "num") (Variable "cls") (Variable "inst"))
   (And
      ; The class has an instance
      (Inheritance (Variable "inst") (Variable "cls"))
      ; The instance has legs
      (Evaluation key (List (Variable "inst") (Variable "num")))
      ; The leg-count is other than four
      (NotLink (Equal (Variable "num") (Number 4)))
   )
   ; add the class to the set of non-four-legged classes
   (Member (Variable "cls") (Concept "not-just-four"))))

To find all classes where all members have only four legs, just look for anything that does not belong to the "not-just-four" set (set subtraction):

(define find-not-not-four
 (Bind
  (VariableList (Variable "cls") (Variable "inst"))
   (And
      ; The class has an instance
      (Inheritance (Variable "inst") (Variable "cls"))
      ; The class does not belong to the set of non-four-legged classes
      (Absent (Member (Variable "cls") (Concept "not-just-four")))
   )
   ; Return that class
   (Variable "cls")))

This gives you the answer you were looking for, Both Amen and Roman were trying to do this in just one shot, and that is an interesting approach, and I tried it myself, but it seems impossible to do this with just a single pass. (I think it's provably impossible -- I'm too lazy to prove this, so instead let me hand-wave and mumble about "second order" and pi-sigma hierarchies and skolemization; you are trying to do a second-order search, and BindLink is always first-order. One gets to higher orders in OpenCog by chaining together multiple rules. The rule engine and openpsi both do that; but here, both URE and openpsi are overkill.)

linas commented 5 years ago

Perhaps an issue is that my two-rule approach leaves behind some garbage in the atomspace. There are two ways to deal with the garbage: (1) explicitly delete it, (2) use temporary atomspaces. Temporary atomspaces are easier, I guess.

; Create a temporary atomspace
(cog-push-atomspace)

; Run your processing job
(cog-execute! find-not-four)
(cog-execute! find-not-not-four)

; discard temporary atomspace
(cog-pop-atomspace)

;  verify that the main atomspace contains no garbage
(cog-incoming-set (Concept "not-just-four"))
linas commented 5 years ago

And of course .. I posted the last comment without actually testing it, and it appears that the temporary atomspace is .. not actually discarded. So that is a bug. Investigating the bug now. Apparently no one uses temporary atomspaces? Or no one noticed this bug before? Hmm.

vsbogd commented 5 years ago

Regarding FoldLink and ForAllLink I mean that it would be useful if we can use one of them to describe such queries in a more compact way. If ForAllLink is not implemented may be we should implement it? I don't think it is simple though.

linas commented 5 years ago

@vsbogd So FoldLink just implements folding. I'm not sure what that has to do with this problem.

GetLink is more-or-less the same thing as ForAllLink We could just rename GetLink to ForAllLink, Is that enough? Three different people above said something strange about for-all that I don't understand, so I'm thinking that whatever you believe that for-all means is not the same as what I believe that for-all means.

Please note that the definition of for-all depends on the algebra, logic or topos that you assume. See, for example, https://en.wikipedia.org/wiki/Natural_deduction and notice multiple different kinds of for-all: for-all_F, for-all_I^au, for-all_F^u . Do you want it to come with or without a sigma-pi hierarchy? (Borel hierarchy?) (the pi's are the for-all's, the sigmas are the there-exists, when placed in skolemized form, which wikipedia does not explain very well) Or perhaps a subject-classifier for-all? https://en.wikipedia.org/wiki/Borel_hierarchy https://en.wikipedia.org/wiki/Skolem_normal_form https://en.wikipedia.org/wiki/Subobject_classifier

The TFValueOf proposal in #2004 is basically a proposal for a simple binary 0/1, T/F value, for a set-theory-style subobject classifier, while the SimpleTruthValue is a much more complicated subobject classifier. A complicated subobject classifier is going to have complicated for-all and there-exists functions/functors. This makes skolemization harder, trickier and more "interesting", which makes the sigma-pi hierarchy harder, trickier and "more intersting". In opencog, the "universal rule engine", the URE, is what is implementing the sigma-pi hierarchy (the borel hierarchy). So all these decisions have knock-on effects, like dominos...

ngeiswei commented 5 years ago

ForAllLink was invented long before GetLink/BindLink and is PLN's universal quantifier (thus supports uncertainty).

It's hasn't been implemented in the "new" version of PLN yet. The main reason for that is because most of the time ImplicationLink (or it's sugar syntax ImplicationScopeLink) is enough since most truths are conditional.

I feel it is wiser, at least for the time being, to keep the pattern matcher links GetLink/BindLink and their PLN spiritual counterparts ForAllLink/ImplicationLink distinct. Their future unification seems possible but it doesn't look like an important question to address now.

ngeiswei commented 5 years ago

@stellarspot, I think you can solve your problem with the unified rule engine (URE). If you'd like, please have a look at

https://wiki.opencog.org/w/Unified_rule_engine

as well the URE examples

https://github.com/opencog/atomspace/tree/master/examples/rule-engine

and the PLN examples

https://github.com/opencog/opencog/tree/master/examples/pln

In particular maybe the following example is close to what you want

https://github.com/opencog/opencog/tree/master/examples/pln/good-songs

Once you understand the URE, I'll be happy to help you build your query if you still need assistance.

stellarspot commented 5 years ago

Below is the code where I used Atomese in Python to write sample message passing algorithm on a graph.

First it creates new graph where each edge from the original graph is replaced by two directed edges. For each directed edge the message is calculated if there is already no a message for this edge and there are all incoming message for the source node. It uses BindLink to find all edges and calls ExecutionOutputLink to run the second BindLink to find all incoming edges.

To do the same with URE it seems it needs to have several steps. The first step should generate a list of incoming messages for the given node. The second step needs to check that there are enough messages (number of messages is the number of neighbors minus one). If it is true, new message can be generated. The intermediate list with messages needs to be removed so it will be updated next time if there are no enough messages.

from opencog.utilities import initialize_opencog
from opencog.type_constructors import *
from opencog.bindlink import execute_atom

atomspace = AtomSpace()
initialize_opencog(atomspace)

TV_FALSE = TruthValue(0, 1)
TV_TRUE = TruthValue(1, 1)

EDGE_KEY = PredicateNode('edge')
MESSAGE_KEY = PredicateNode('message')
DIRECTED_MESSAGE_EDGE_KEY = PredicateNode('directed-message-edge')

def get_node(n):
    return ConceptNode(n)

def get_edge(a, b):
    return EvaluationLink(EDGE_KEY, ListLink(a, b))

def get_directed_message_edge(a, b):
    return EvaluationLink(DIRECTED_MESSAGE_EDGE_KEY, ListLink(a, b))

def has_message(edge):
    return TV_TRUE if edge.get_value(MESSAGE_KEY) else TV_FALSE

def set_message_value(v1, v2, message):
    get_directed_message_edge(v1, v2).set_value(MESSAGE_KEY, FloatValue(message))

def get_message_value(v1, v2):
    value = get_directed_message_edge(v1, v2).get_value(MESSAGE_KEY)
    return float(value.to_list()[0])

def get_neigbours(v):
    neighbour_nodes_rule = BindLink(
        TypedVariableLink(
            VariableNode('$V'),
            TypeNode('ConceptNode')),
        AndLink(
            # Pattern clauses
            get_directed_message_edge(
                VariableNode('$V'),
                v)),
        VariableNode('$V'))

    return execute_atom(atomspace, neighbour_nodes_rule)

def get_neigbours_except(v1, v2):
    neighbour_nodes_rule = BindLink(
        TypedVariableLink(
            VariableNode('$V'),
            TypeNode('ConceptNode')),
        AndLink(
            # Preconditions
            NotLink(
                EqualLink(
                    VariableNode('$V'),
                    v2)),
            # Pattern clauses
            get_directed_message_edge(
                VariableNode('$V'),
                v1)),
        VariableNode('$V'))

    return execute_atom(atomspace, neighbour_nodes_rule)

def can_send_message(v1, v2):
    neigbor_nodes = get_neigbours_except(v1, v2)

    for v in neigbor_nodes.out:
        if has_message(get_directed_message_edge(v, v1)) == TV_FALSE:
            return TV_FALSE

    return TV_TRUE

def send_message(v1, v2):
    neigbor_nodes = get_neigbours_except(v1, v2)

    a = 0.8
    message = 10

    for v in neigbor_nodes.out:
        msg = get_message_value(v, v1)
        message += msg

    print('   send message:', v1.name, "->", v2.name, message)

    message = a * message
    set_message_value(v1, v2, message)
    return get_directed_message_edge(v1, v2)

def get_node_value(n):
    neigbours = get_neigbours(n)
    message = 0
    for v in neigbours.out:
        msg = get_message_value(v, n)
        message += msg

    return message

# Graph
# A - +
#     C --- D --- E
# B - +

get_edge(get_node("A"), get_node("C"))
get_edge(get_node("B"), get_node("C"))
get_edge(get_node("C"), get_node("D"))
get_edge(get_node("D"), get_node("E"))

nodes = [get_node("A"),
         get_node("B"),
         get_node("C"),
         get_node("D"),
         get_node("E")]

directed_message_edge_creation_rule = BindLink(
    VariableList(
        TypedVariableLink(
            VariableNode('$V1'),
            TypeNode('ConceptNode')),
        TypedVariableLink(
            VariableNode('$V2'),
            TypeNode('ConceptNode'))),
    get_edge(
        VariableNode('$V1'),
        VariableNode('$V2')),
    ListLink(
        get_directed_message_edge(
            VariableNode('$V1'),
            VariableNode('$V2')),
        get_directed_message_edge(
            VariableNode('$V2'),
            VariableNode('$V1'))))

message_sending_rule = BindLink(
    VariableList(
        TypedVariableLink(
            VariableNode('$V1'),
            TypeNode('ConceptNode')),
        TypedVariableLink(
            VariableNode('$V2'),
            TypeNode('ConceptNode'))),

    AndLink(
        # Preconditions
        NotLink(
            EvaluationLink(
                GroundedPredicateNode('py: has_message'),
                ListLink(
                    get_directed_message_edge(
                        VariableNode('$V1'),
                        VariableNode('$V2'))))),
        EvaluationLink(
            GroundedPredicateNode('py: can_send_message'),
            ListLink(
                VariableNode('$V1'),
                VariableNode('$V2')
            )),
        # Pattern clauses
        get_directed_message_edge(
            VariableNode('$V1'),
            VariableNode('$V2'))
    ),
    ExecutionOutputLink(
        GroundedSchemaNode('py: send_message'),
        ListLink(
            VariableNode('$V1'),
            VariableNode('$V2'))))

res = execute_atom(atomspace, directed_message_edge_creation_rule)
# print(res)

print("=== iter 1 ===")
res = execute_atom(atomspace, message_sending_rule)
print("=== iter 2 ===")
res = execute_atom(atomspace, message_sending_rule)
print("=== iter 3 ===")
res = execute_atom(atomspace, message_sending_rule)

for node in nodes:
    msg = get_node_value(node)
    print('node:', node.name, "value:", msg)
linas commented 5 years ago

I did not study the code in the last post very carefully, but .. still several remarks:

calls ExecutionOutputLink to run the second BindLink

If you design it properly, this is not needed. You can nest bindlink, get-links, putlinks, sequential-and, sequential-or links arbitrarily deeply, and they "just work", You can even write infinite loops, so that you just call "cog-execute" just once, ever, and then the system runs in automatic for the next half-hour or whatever. This is how we've done Sophia-the-robot demos in the past. One calls execute during boot-up, and that's it. The only reason for using GroundedPredicates was to send messages to/from ROS, to control the robot. All other program flow was accomplished with infinitely-recursive nested bind-links.

def has_message

I get the feeling that you are kind of missing the point of atomese. The point of atomese is to NOT write python code! By representing everything as a graph (in atomese), and having the flow of control move through the graph, you can avoid writing any python, at all. See for example, the wikipedia article on "behvaior tree" -- https://en.wikipedia.org/wiki/Behavior_tree_(artificial_intelligence,_robotics_and_control) and https://en.wikipedia.org/wiki/Behavior_tree and the simple behavior-tree demo here: https://github.com/opencog/atomspace/blob/master/examples/pattern-matcher/sequence.scm and here https://github.com/opencog/atomspace/blob/master/examples/pattern-matcher/condition.scm .. and if you don't like behavior trees and are a big fan of finite state machines instead, there are FSM demos in the same directory. Also, if you are a stimulus-response type person, there is an SRAI demo here: https://github.com/opencog/atomspace/blob/master/examples/pattern-matcher/recognizer.scm -- the point of all of these demos is to automate by NOT writing python code.

There is no message-passing demo, but maybe there should be... this demo https://github.com/opencog/atomspace/blob/master/examples/atomspace/stream.scm is a pre-prototype message-passing demo. It uses ValueOfLink to get messages...

So -- what's wrong with python code? Nothing, but if you want to write python, you should NOT use the atomspace! There are far less klunky, far easier-to-use, far faster and more efficient black-board systems, message-passing systems, graph-processing systems, finite-state and SRAI and behavior-tree systems, than what you could ever do in atomese/opencog. Some of them have really slick GUI's and drag-n-drop systems and visualizers that come with them.

The reason for using the atomspace is to represent the program flow as a graph, with atoms, so that:

By creating graphs in python, it is impossible to do any of this: there is no learning/reasoning system in the world (other than a human) that knows how to open a python file, edit it, change it, save it and run it. As soon as you code in python, you are placing your system into a format which no existing machine-learning algo can ever understand.

This is particularly true of Grounded-AnythingNodes: it is fundamanetally impossible for a learning/reasoning system to understand what a grounded-something node does, because learning/reasoning systems do not know how to read (or write) phython, (or scheme or haskell or c++) Basically, Grounded-anything nodes should not be used for anything ever except for a few small exceptions: moving data to/from external systems e.g. ROS, to control a robot. otherwise, they should be avoided at all costs. They're pure, unadulterated evil, from the data-mining point of view.

stellarspot commented 5 years ago

You can nest bindlink, get-links, putlinks, sequential-and, sequential-or links arbitrarily deeply, and they "just work"

I tried to solve the task 'find all baskets which has only red balls' using nested bind links. The first bind link returns all balls from the baskets, the second returns only red balls. After that I just use Equal link to checks that both results give the same balls:

(Member (Concept "ball1") (Concept "basket1"))
(Member (Concept "ball2") (Concept "basket1"))

(Member (Concept "ball3") (Concept "basket2"))
(Member (Concept "ball4") (Concept "basket2"))

(Member (Concept "ball5") (Concept "basket3"))
(Member (Concept "ball6") (Concept "basket3"))

(Inheritance (Concept "ball1") (Concept "red"))
(Inheritance (Concept "ball2") (Concept "red"))
(Inheritance (Concept "ball3") (Concept "red"))
(Inheritance (Concept "ball4") (Concept "green"))
(Inheritance (Concept "ball5") (Concept "green"))
(Inheritance (Concept "ball6") (Concept "green"))

(define baskets-with-all-red-balls
 (Bind
  (TypedVariable (Variable "$BASKET") (Type "ConceptNode"))
  (Equal
   (Bind
    (TypedVariable (Variable "$BALL") (Type "ConceptNode"))
    (Member
     (Variable "$BALL")
     (Variable "$BASKET"))
    (Variable "$BALL"))
   (Bind
    (TypedVariable (Variable "$BALL") (Type "ConceptNode"))
    (And
     (Member
      (Variable "$BALL")
      (Variable "$BASKET"))
     (Inheritance
      (Variable "$BALL")
      (Concept "red")))
    (Variable "BALL")))
  (Variable "$BASKET")))

(display
 (cog-execute! baskets-with-all-red-balls)
)

The result is just an empty set.

I also tried to rewrite the request to use the same bind link in the Equal link so it should always returns true but the result was just an empty set as before:

(define pattern
 (Bind
  (TypedVariable (Variable "$BASKET") (Type "ConceptNode"))
  (Equal
   ; The first and the second bind links are just the same
   ; they returns the same balls for the given basket
   (Bind
    (TypedVariable (Variable "$BALL") (Type "ConceptNode"))
    (Member
     (Variable "$BALL")
     (Variable "$BASKET"))
    (Variable "$BALL"))
   (Bind
    (TypedVariable (Variable "$BALL") (Type "ConceptNode"))
    (Member
     (Variable "$BALL")
     (Variable "$BASKET"))
    (Variable "$BALL")))
  (Variable "$BASKET")))

(display
 (cog-execute! pattern)
)
linas commented 5 years ago

There are several issues with what you wrote. First is that the BindLink is not nestable in that way; nesting is achieved using PutLink.

The EqualLink is really not needed for the problem that you are trying to solve; there are much simpler ways of obtaining the answer.

You will have a lot less difficulty with all of this if you go through the tutorials, and read the documentation.

The tutorials are located here: https://github.com/opencog/atomspace/blob/master/examples/atomspace/ and here: https://github.com/opencog/atomspace/blob/master/examples/pattern-matcher/

The documentation is here: https://wiki.opencog.org/w/SatisfactionLink_and_BindLink

I believe that if you go through all of the tutorials, (and not just one or two), and then think about variations on them, you will be able to find much easier and simpler solutions to the problems that you are encountering.