Manipulating Atoms in Python

From OpenCog

Lesson: Manipulating Atoms in Python3

  • Repeat a bunch of the Scheme shell examples in python
  • See the opencog atomspace examples on Python

The links above provide detailed descriptions of all topics in this chapter. What follows is a severely restricted selection from these pages. One should go back and explore those links to gain a deeper understanding of the topics introduced here.

In this lesson, we will see the same stuff, this time repeated in python. The last two sections will show how to execute custom functions involving atoms in python. This can be done in scheme or c++ as well. But before we do any of that, you must make sure that python can import the opencog modules.

Export the location of the opencog modules to PYTHONPATH environment variable. This has to be done everytime you open a new shell. You may want to put it in your ~/.bashrc file, like so:

export PYTHONPATH=/usr/local/lib/python3.5/dist-packages/:$PYTHONPATH

You may need to adjust the above to match your actual python version.

Making some Atoms (python3)

Here I will mostly use the ipython shell to give examples. But you can of course put all the commands in a script if you like. Import AtomSpace and types to start making atoms.

In [1]: from opencog.atomspace import AtomSpace, types

There are two ways to create Atoms in python. You can use the c++ like syntax or you can use the scheme like syntax.

c++ like syntax

#Create the atomspace
In [2]: atsp = AtomSpace()

#Create some atoms with add_node function
In [3]: cat = atsp.add_node(types.ConceptNode, "Cat")

In [4]: man = atsp.add_node(types.ConceptNode, "Man")

In [5]: animal = atsp.add_node(types.ConceptNode, "Animal")

#Try to print the atomspace
In [6]: atsp
Out[6]: <opencog.atomspace.AtomSpace at 0x7f3beeaf4810>

#Try to print a Node 
In [7]: man
Out[7]: (ConceptNode "Man") ; [3][1]

So printing the AtomSpace didn't quite work out as we might have expected from c++. We can print its contents as follows:

In [10]: for atom in atsp:
   ....:     print (atom)
(ConceptNode "Animal") ; [4][1]

(ConceptNode "Man") ; [3][1]

(ConceptNode "Cat") ; [2][1]

Now lets add some links into the AtomSpace. This is again, just like c++.

In [11]: atsp.add_link(types.InheritanceLink, [man, animal])
  (ConceptNode "Man") ; [3][1]
  (ConceptNode "Animal") ; [4][1]
) ; [5][1]

scheme like syntax

To use scheme like concise syntax you have to do a few extra steps. Import the type_constructors that enable you to add atoms to the AtomSpace by calling functions named after their types. Import initialize_opencog a function that binds a AtomSpace instance to the type_constructors.

In [13]: from opencog.utilities import initialize_opencog

In [14]: from opencog.type_constructors import *

#Setup that ensures that any atoms you create are added to the AtomSpace atsp.
In [15]: initialize_opencog(atsp)

Now you can add atoms just like in scheme. This becomes very useful when you start building complex patterns for the pattern matcher.

In [15]: initialize_opencog(atsp)

In [16]: color = ConceptNode("Color")

In [17]: c1 = ConceptNode("Blue")

In [18]: link = InheritanceLink(c1, color)

In [19]: for atom in atsp:
   ....:     print (atom)
(ConceptNode "Color") ; [6][1]

(ConceptNode "Blue") ; [7][1]

(ConceptNode "Animal") ; [4][1]

(ConceptNode "Man") ; [3][1]

(ConceptNode "Cat") ; [2][1]

  (ConceptNode "Blue") ; [7][1]
  (ConceptNode "Color") ; [6][1]
) ; [8][1]

  (ConceptNode "Man") ; [3][1]
  (ConceptNode "Animal") ; [4][1]
) ; [5][1]

One last thing before we wrap this up. The Atoms are classes with a lot of useful methods. If you are in the ipython shell you can look at a list by writing <variable_pointing_to_an_atom>.<Tab>. For example we have a variable color that points to the ConceptNode object of name "Color". Then I can see a list of all the method I can call on it by:

In [21]: color.<Press_Tab>
color.arity              color.incoming           color.long_string        color.truth_value        color.vlti
color.atomspace          color.incoming_by_type   color.lti                       color.xincoming
color.av                 color.increment_vlti               color.type               color.xincoming_by_type
color.decrement_vlti     color.is_a               color.out                color.type_name          
color.get_out            color.is_link            color.sti                color.uuid               
color.handle_uuid        color.is_node            color.t                  color.value

Pattern Matching

Now lets look at how we can run the PM through python. The PM functions are defined in c++ and made available in python through wrappers that are defined in /opencog/cython/opencog/bindlink.pyx and you can see the imports in atomspace/opencog/cython/opencog/bindlink.pxd

Here we will again run the equivalent of bindlink and cog-staisfying-set functions in scheme.

#Delete existing atoms
In [22]: atsp.clear()

#Create some atoms
In [27]: InheritanceLink(ConceptNode("Red"), color)
In [28]: InheritanceLink(ConceptNode("Green"), color)
In [29]: InheritanceLink(ConceptNode("Blue"), color)

#Create a pattern to look for color nodes
In [30]: varlink = TypedVariableLink(VariableNode("$xcol"), TypeNode("ConceptNode"))
In [31]: pattern = InheritanceLink(VariableNode("$xcol"), color)
In [32]: colornodes = GetLink(varlink, pattern)

#Now run the function to find all color nodes
In [33]:  execute_atom(atsp, colornodes)
  (ConceptNode "Red") ; [10][1]
  (ConceptNode "Blue") ; [12][1]
  (ConceptNode "Green") ; [14][1]
) ; [22][1]

In a similar manner you can import bindlink from opencog.bindlink and use it to execute rewrite queries (with the help of BindLink in place of SatisfactionLink).