Creating a Mind Agent that does something in C
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:
- It's recommended that you have read Creating a new Mind Agent in C so you can prepare the initial classes for this tutorial yourself.
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:
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.