Creating a Mind Agent that does something in C

From OpenCog
Jump to: navigation, search

THIS PAGE IS OBSOLETE

Attention: Much of the MindAgent infrastructure in the CogServer is a temporary work-around for the lack of thread-safe API's in several parts of the OpenCog embodiment code-base. The MindAgent scheduler is simply a way of allowing multiple independent blocks of code to share one single thread, and thus safely co-exist. If your block of code does not access any of the thread-unsafe API's, then you should not use the scheduler! Instead, just create as many threads as you need, and do whatever you need to do; the OS will take care of the rest.

At this time, Atoms, TruthValues, AttentionValues and the AtomSpace are all thread-safe. The TimeServer, SpaceServer, LearningServer, OAC and PAI are probably not thread-safe. Thus, you only need to use scheduling MindAgents for accessing embodiment code; otherwise, please do not use this infrastructure.

Please note that the MindAgent dispatcher code is extremely simple, and is guaranteed to suffer from various textbook ills, such as deadlocks, priority inversion, stalls. It's not pre-emptive, it's not fair, it's just a simple loop. Thus, MindAgents should be kept very simple, should run only for very small intervals of time, and should avoid anything that would cause them to sleep or block. If any agent blocks, they all block. No agent can run until the current agent has finished running. This is why threads are encouraged: the 'run' method should be trivial. Do your work in a thread!

Description

This page describes how to build a Mind Agent that does some simple updates to the AtomSpace. The examples have no practical application, apart from showing you how to do some simple operations on the AtomSpace with the API functions that it offers.

Prerequisites

This page has the following prerequisites:

Contents

First steps

The first thing to do is add a new class to your project along the lines described in Creating a new Mind Agent in C. Let's call it AtomUpdatingAgent, because that's what we'll be doing.

Since we need to use SimpleTruthValue types, add the following line to your AtomUpdatingAgent.cc file

#include <opencog/atomspace/SimpleTruthValue.h>

Once you have done this, you should have your project in QT looking something like this:

Empty AtomUpdatingAgent.png


Next, edit the opencog.conf file to load an example Scheme file, as described in Understanding the opencog.conf file. Make sure that in the SCM_PRELOAD section the NLP files are commented out and the Scheme file of your choice has been added, similar to the one shown below (we'll be using the LionTigerAS.scm file mentioned in Scheme example files for noobs)

SCM_PRELOAD           = scm/type_constructors.scm, 
                        scm/persistence.scm,
                        scm/utilities.scm,
                        scm/apply.scm,
                        scm/file-utils.scm, 
                        scm/debug.scm, 
     			../tests/reasoning/pln/scm/new/LionTigerAS.scm,
#                        nlp/scm/type-definitions.scm, 
#                        nlp/scm/config.scm, 
#                        nlp/scm/file-utils.scm,
#                        nlp/scm/nlp-utils.scm,
#                        nlp/scm/disjunct-list.scm,
#                        nlp/scm/processing-utils.scm,
                        reasoning/pln/scm/pln-rules.scm,
                        embodiment/scm/type_constructors.scm

Example implementations for the Run() function

Below are some simple sets of commands you can paste into the Run() function of your Mind Agent to make it do various changes to the atomspace.

STI Updating Agent

To update the STI of all the Atoms, you could use the code below. It loops through all the Atoms and sets the STI to 20.

XXX Per note above: the correct design here would be to fork a thread, and do all of the processing in a thread, and then exist that thread when done. The run() method itself should just fork the thread, and return immediately. This example needs to be fixed! XXX

void AtomUpdatingAgent::run()
{
    logger().info("[AtomUpdatingAgent] run");

    //AtomSpace* as;
    AtomSpace* as = &_cogserver.getAtomSpace();
    HandleSeq nodes;

    as->getHandleSet(back_inserter(nodes), NODE, true);

    static const AttentionValue::sti_t DEFAULTATOMSTI = 20;

    foreach (Handle handle, nodes) {
       // Set all nodes to default STI and default LTI
       as->setSTI(handle, DEFAULTATOMSTI);
       as->setLTI(handle, DEFAULTATOMSTI);

       logger().info("[AtomUpdatingAgent] Updated STI for Atom with Name " + as->getName(handle));
    }
}

Build the examples as described in the prerequisite tutorial of this page and follow the instructions to load your module in the OpenCog shell. Your log file should show lines such as:

[2012-11-06 03:50:41:044] [INFO] [AtomUpdatingAgent] Updated STI for Atom with Hash 5532494666180499357

You may use the Atomspace Viewer to see the results of your STI updates in real time. Alternatively, you can see this through the AtomSpace API by logging it, or by using the scheme shell inside the OpenCog shell. Since this has many commands, we'll just list them here.

After connecting to the OpenCog shell

rlwrap telnet localhost 17001

Start the scheme shell

scm

And type the defined name of a concept. In our example, which uses the LionTigerAS.scm file, this should work:

lion

The output would then be

(ConceptNode "Lion" (stv 0.5 0.99900001) (av 20 20 0))

Which shows that both the STI and LTI have been updated to 20, as we specified in the code. The 0 after that indicates the VLTI, which we did not update in our code snippet.

STV Updating Agent

To update the TruthValues of Atoms, you could use the code below. It loops through atoms that have a TruthValue where the Strength is greater than 0 and manipulates their composite values, storing the new values in the AtomSpace again.

XXX Per note above: the correct design here would be to fork a thread, and do all of the processing in a thread, and then exist that thread when done. The run() method itself should just fork the thread, and return immediately. This example needs to be fixed! XXX

void AtomUpdatingAgent::run()
{
    logger().info("[AtomUpdatingAgent] run");

    AtomSpace* as = &_cogserver.getAtomSpace();
    HandleSeq nodes;

    as->getHandleSet(back_inserter(nodes), NODE, true);

    foreach (Handle handle, nodes) {
        // Get the original TruthValue information
        TruthValuePtr tvpOldTruthValue = as->getTV(handle);

        // Split the TruthValue it into its composite values, which are custom types that are defined as floats (at the moment)
        float fOldStrength = tvpOldTruthValue->getMean();
        float fOldConfidence = tvpOldTruthValue->getConfidence();
        float fOldCount = tvpOldTruthValue->getCount();

        // Ignore Atoms with a Strength of 0.0
        if (fOldStrength > 0.0f)
        {
            // Prepare a string to log the old values
            std::string strOldTruthValueData = "Initial TruthValue for Atom '" + as->getName(handle) + "', ";

            strOldTruthValueData = strOldTruthValueData + "Old Strength: " + boost::lexical_cast<std::string>(fOldStrength) + ", ";
            strOldTruthValueData = strOldTruthValueData + "Old Confidence: " + boost::lexical_cast<std::string>(fOldConfidence) + ", ";
            strOldTruthValueData = strOldTruthValueData + "Old Count: " + boost::lexical_cast<std::string>(fOldCount);

            logger().info("[AtomUpdatingAgent] " + strOldTruthValueData);

            // Calculate a new Strength and Count (Confidence is derived from these values by the system)
            float fNewStrength = fOldStrength * 0.95f;
            float fNewCount = fOldCount / 2.0f;

            // Prepare a new SimpleTruthValue
            SimpleTruthValue newTruthValue(fNewStrength, fNewCount);

            // Update the TruthValue of the Atom to some new values
            as->setTV(handle, newTruthValue);

            // Retrieve the new Confidence value
            float fNewConfidence = as->getConfidence(handle);

            // Prepare a string to log the new values
            std::string strNewTruthValueData;

            strNewTruthValueData += "New Strength: " + boost::lexical_cast<std::string>(fNewStrength) + ", ";
            strNewTruthValueData += "New Confidence: " + boost::lexical_cast<std::string>(fNewConfidence) + ", ";
            strNewTruthValueData += "New Count: " + boost::lexical_cast<std::string>(fNewCount);

            logger().info("[AtomUpdatingAgent] Updated TruthValue for Atom with Hash '" + as->getName(handle) + "', " + strNewTruthValueData);
        }
    }
}

If all has gone well, your cogserver.log file should contain some lines as shown below.

[2013-09-24 07:45:37:451] [INFO] [AtomUpdatingAgent] Updated TruthValue for Atom with Hash '# New Parsed Sentence', New Strength: 0.857374966, New Confidence: 0.999999046, New Count: 838860672

Next Steps

None yet.

Q&A

Any questions?

Please add them here

In the STI Updating Agent section, the code provided did not compile without the following changes.

1) The as->getAtomHash method is not defined.

logger().info("[AtomUpdatingAgent] Updated STI for Atom with Hash " + boost::lexical_cast<std::string>(as->getAtomHash(handle)));

change to

logger().info("[AtomUpdatingAgent] Updated STI for Atom with Name " + as->getName(handle));

2) sti_t is not found.

static const sti_t DEFAULTATOMSTI = 20;

change to

static const AttentionValue::sti_t DEFAULTATOMSTI = 20;

3) Is this tutorial a joke? Does anything work?

Yes. And No.