summaryrefslogtreecommitdiff
path: root/SA_POP/SANet/SANode.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'SA_POP/SANet/SANode.cpp')
-rw-r--r--SA_POP/SANet/SANode.cpp1020
1 files changed, 1020 insertions, 0 deletions
diff --git a/SA_POP/SANet/SANode.cpp b/SA_POP/SANet/SANode.cpp
new file mode 100644
index 00000000000..4ce882526d0
--- /dev/null
+++ b/SA_POP/SANet/SANode.cpp
@@ -0,0 +1,1020 @@
+// -*- C++ -*-
+
+//=============================================================================
+/**
+ * @file SANode.cpp
+ *
+ * This file contains the Node, CondNode, & TaskNode class
+ * implementations for spreading activation network nodes.
+ *
+ * @author John S. Kinnebrew <john.s.kinnebrew@vanderbilt.edu>
+ */
+//=============================================================================
+
+#include "SANode.h"
+#include "SANet_Exceptions.h"
+#include <utility>
+#include <iostream>
+
+using namespace SANet;
+
+Node::Node (NodeID ID, std::string name, MultFactor atten_factor)
+: ID_ (ID),
+ name_ (name),
+ atten_factor_ (atten_factor),
+ step_ (0),
+ prob_changed_ (false),
+ util_changed_ (false)
+{
+ // Initialize probability and utility info.
+ pos_util_.utility = 0;
+ pos_util_.common.clear ();
+ neg_util_.utility = 0;
+ neg_util_.common.clear ();
+ true_prob_.probability = 0;
+ true_prob_.common.clear ();
+ false_prob_.probability = 0;
+ false_prob_.common.clear ();
+
+ // Initialize (empty) pre and post node maps and links.
+ pre_nodes_.clear ();
+ pre_links_.clear ();
+ post_nodes_.clear ();
+ post_links_.clear ();
+};
+
+Node::~Node ()
+{
+ // Nothing to do.
+};
+
+Utility_Info Node::get_reward (int step)
+{
+ // Check to ensure step is the current step, or else throw exception
+ if (step != step_) {
+ throw Invalid_Step ();
+ }
+
+ // Return positive utility info.
+ return pos_util_;
+};
+
+Probability_Info Node::get_prob (int step, bool value)
+{
+ // Check to ensure step is the current step, or else throw exception
+ if (step != step_) {
+ throw Invalid_Step ();
+ }
+
+ // Return probability for true if value is true.
+ if (value) {
+ return true_prob_;
+ }
+ // Otherwise return probability for false.
+ return false_prob_;
+};
+
+bool Node::prob_changed (void)
+{
+ return prob_changed_;
+};
+
+bool Node::util_changed (void)
+{
+ return util_changed_;
+};
+
+std::string Node::get_name (void)
+{
+ return name_;
+};
+
+NodeID Node::get_ID (void)
+{
+ return ID_;
+};
+
+// Get pre-links (nodes with links to this node).
+const LinkMap& Node::get_pre (void)
+{
+ return this->pre_links_;
+};
+
+// Get post-links (nodes with links from this node).
+const LinkMap& Node::get_post (void)
+{
+ return this->post_links_;
+};
+
+TaskNode::TaskNode (NodeID ID, std::string name, MultFactor atten_factor,
+ TaskCost cost, Probability prior_prob)
+: Node (ID, name, atten_factor),
+ cost_ (cost),
+ prior_prob_ (prior_prob)
+{
+ // Nothing to do.
+};
+
+TaskNode::~TaskNode (void)
+{
+ // Nothing to do.
+};
+
+bool TaskNode::update (void)
+{
+ // Reset change flags.
+ prob_changed_ = false;
+ util_changed_ = false;
+
+ //****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP
+ // Probability flag is not being set correctly, so run to max steps...
+ prob_changed_ = true;
+ util_changed_ = true;
+ //****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP
+
+ // Flag for detection of loops.
+ bool is_loop = false;
+
+ // Variables for current node and link in updates.
+ CondNode *cur_node;
+ CondID cur_ID;
+ LinkMap::iterator link_iter;
+ LinkWeight cur_weight;
+ MultFactor cur_mult;
+
+ // Variables for current probability value.
+ Probability_Info cur_prob;
+ ProbabilityMap::iterator true_prob_iter;
+ ProbabilityMap::iterator false_prob_iter;
+ ProbabilityMap::iterator prev_prob_iter;
+
+ // Reset probability info.
+ true_prob_.probability = prior_prob_;
+ //****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP
+ // clearing common probabilities set removes self (if "loop" found where
+ // this node is receiving utility from same goal on multiple paths). so
+ // will never realize that nothing has changed.
+ // and (possible) common probabilities are never removed from the set once
+ // detected so this does not need to be cleared as long as any
+ // changed probabilities are appropriately changed in common set... right???
+ true_prob_.common.clear ();
+
+ // Update probability.
+ for (NodeMap::iterator node_iter = pre_nodes_.begin ();
+ node_iter != pre_nodes_.end (); node_iter++)
+ {
+ // Get current node info.
+ cur_ID = node_iter->first;
+ cur_node = (CondNode *) node_iter->second;
+
+ // Get current link info.
+ link_iter = pre_links_.find(cur_ID);
+ if (link_iter == pre_links_.end ()) {
+ throw Update_Error ();
+ }
+ cur_weight = link_iter->second;
+
+ // Get current probability info.
+ try {
+ if (cur_weight >= 0) {
+ cur_prob = cur_node->get_prob (step_, true);
+ } else {
+ cur_prob = cur_node->get_prob (step_, false);
+ }
+ } catch (Invalid_Step e) {
+ std::cerr << "Error in task node update: Invalid step value.";
+ std::cerr << std::endl;
+ return false;
+ } catch (...) {
+ std::cerr << "Unexpected exception thrown in task node update.";
+ std::cerr << std::endl;
+ return false;
+ }
+
+ // Get conditional probability of success for true precondition.
+ true_prob_iter = pre_true_probs_.find (cur_ID);
+ if (true_prob_iter == pre_true_probs_.end ()) {
+ throw Update_Error ();
+ }
+
+ // Get conditional probability of success for false precondition.
+ false_prob_iter = pre_false_probs_.find (cur_ID);
+ if (false_prob_iter == pre_false_probs_.end ()) {
+ throw Update_Error ();
+ }
+
+ // Update true probability depending on sign of link weight.
+ if (cur_weight >= 0) {
+ // Update conditional probability of success given this node.
+ cur_prob.probability = ((cur_prob.probability * true_prob_iter->second) +
+ ((1 - cur_prob.probability) * false_prob_iter->second));
+
+ // Update probability.
+ true_prob_.probability = true_prob_.probability * cur_prob.probability /
+ prior_prob_;
+ } else {
+ // Update conditional probability of success given this node.
+ cur_prob.probability = ((cur_prob.probability * false_prob_iter->second)
+ + ((1 - cur_prob.probability) * true_prob_iter->second));
+
+ // Update probability.
+ true_prob_.probability = true_prob_.probability * cur_prob.probability /
+ prior_prob_;
+ }
+
+ // Update prob_changed_ flag if necessary.
+ if (cur_node->prob_changed ()) {
+ prob_changed_ = true;
+ }
+
+ // Update common probabilities and handle duplicates.
+ for (ProbabilityMap::iterator prob_iter = cur_prob.common.begin ();
+ prob_iter != cur_prob.common.end (); prob_iter++)
+ {
+ prev_prob_iter = true_prob_.common.find (prob_iter->first);
+
+ // If a common probability is already in the probability map,
+ // divide from probability, otherwise add it to the probability map.
+ if (prev_prob_iter != true_prob_.common.end ())
+ {
+#if defined (SANET_DEBUG)
+ std::cout << std::endl << "DEBUG in TaskNode::update()... (" << ID_ << ") Duplicate common probability found:" << std::endl;
+ std::cout << "Probability from " << prev_prob_iter->first << " = " << prev_prob_iter->second << std::endl << std::endl;
+#endif /* SANET_DEBUG */
+ true_prob_.probability = true_prob_.probability /
+ prev_prob_iter->second;
+ } else {
+ true_prob_.common.insert (std::make_pair (prob_iter->first,
+ prob_iter->second));
+ }
+ }
+ }
+
+ // Variables for current utility updates.
+ Utility_Info cur_util;
+ UtilityMap::iterator prev_util_iter;
+
+ // Reset utility info.
+ pos_util_.utility = 0;
+ pos_util_.common.clear ();
+ neg_util_.utility = 0;
+ neg_util_.common.clear ();
+
+ // Update utility.
+ for (NodeMap::iterator node_iter = post_nodes_.begin ();
+ node_iter != post_nodes_.end (); node_iter++)
+ {
+ // Get current node info.
+ cur_ID = node_iter->first;
+ cur_node = (CondNode *) node_iter->second;
+
+ // Update util_changed_ flag if necessary.
+ if (cur_node->util_changed ()) {
+ util_changed_ = true;
+ }
+
+ // Get current link info.
+ link_iter = post_links_.find(cur_ID);
+ if (link_iter == post_links_.end ()) {
+ throw Update_Error ();
+ }
+ cur_weight = link_iter->second;
+
+ // Set multiplier as attenuation factor times link weight, probability
+ // that task will succeed, and probability that effect node has the
+ // opposite value from what task would change it to.
+ if (cur_weight >= 0) {
+ cur_mult = atten_factor_ * cur_weight * true_prob_.probability *
+ cur_node->get_prob (step_, false).probability;
+ } else {
+ cur_mult = atten_factor_ * cur_weight * true_prob_.probability *
+ cur_node->get_prob (step_, true).probability;
+ }
+
+ // Get current utility info.
+ try {
+ cur_util = cur_node->get_reward (step_);
+ } catch (Invalid_Step e) {
+ std::cerr << "Error in task node update: Invalid step value.";
+ std::cerr << std::endl;
+ return false;
+ } catch (...) {
+ std::cerr << "Unexpected exception thrown in task node update.";
+ std::cerr << std::endl;
+ return false;
+ }
+
+ // Updated utility based on current multiplier.
+ cur_util.utility = cur_mult * cur_util.utility;
+
+ // Update positive or negative utilities depending on sign of link weight.
+ if (cur_weight >= 0) {
+ // Add utility to expected utility value.
+ pos_util_.utility += cur_util.utility;
+
+ // Update all component utilities based on link weight, and handle
+ // utilities from common goals.
+ for (UtilityMap::iterator util_iter = cur_util.common.begin ();
+ util_iter != cur_util.common.end (); util_iter++)
+ {
+ util_iter->second = cur_mult * util_iter->second;
+ prev_util_iter = pos_util_.common.find (util_iter->first);
+
+ // If a utility from this goal is already in the utility map,
+ // delete smaller utility value, otherwise add the utility from this
+ // goal to the utility map.
+ if (prev_util_iter != pos_util_.common.end ())
+ {
+#if defined (SANET_DEBUG)
+ std::cout << std::endl << "DEBUG in TaskNode::update()... (" << ID_ << ") Duplicate utility from goal found:" << std::endl;
+ std::cout << "Utility from " << prev_util_iter->first << " = " << prev_util_iter->second << std::endl << std::endl;
+#endif /* SANET_DEBUG */
+ if (prev_util_iter->second < util_iter->second) {
+ pos_util_.utility -= prev_util_iter->second;
+ } else {
+ pos_util_.utility -= util_iter->second;
+ }
+ // Set loop flag.
+ is_loop = true;
+ } else {
+ pos_util_.common.insert (std::make_pair (util_iter->first,
+ util_iter->second));
+ }
+ }
+ } else {
+ // Add utility to expected utility value.
+ neg_util_.utility += cur_util.utility;
+
+ // Update all component utilities based on link weight, and handle
+ // utilities from common goals.
+ for (UtilityMap::iterator util_iter = cur_util.common.begin ();
+ util_iter != cur_util.common.end (); util_iter++)
+ {
+ util_iter->second = cur_mult * util_iter->second;
+ prev_util_iter = neg_util_.common.find (util_iter->first);
+
+ // If a utility from this goal is already in the utility map,
+ // delete larger (less negative) utility value, otherwise add the
+ // utility from this goal to the utility map.
+ if (prev_util_iter != neg_util_.common.end ())
+ {
+ if (prev_util_iter->second > util_iter->second) {
+ neg_util_.utility -= prev_util_iter->second;
+ } else {
+ neg_util_.utility -= util_iter->second;
+ }
+ // Set loop flag.
+ is_loop = true;
+ } else {
+ neg_util_.common.insert (std::make_pair (util_iter->first,
+ util_iter->second));
+ }
+ }
+ }
+ }
+
+//*****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****
+ // Include cost in current expected utility.
+// pos_util_.utility -= cost_;
+//*****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****DEBUG****
+
+ // If a loop was detected, add current probability to common probabilities.
+ if (is_loop) {
+#if defined (SANET_DEBUG)
+ if (DEBUG) {
+ std::cout << std::endl << "DEBUG in TaskNode::update()... (" << ID_ << ") Loop detected, adding this node to common probabilities" << std::endl << std::endl;
+#endif /* SANET_DEBUG */
+ // Update common probabilities for true probability.
+ ProbabilityMap::iterator prob_iter = true_prob_.common.find (ID_);
+ if (prob_iter != true_prob_.common.end ()) {
+ if (prob_iter->second != true_prob_.probability) {
+ prob_iter->second = true_prob_.probability;
+ prob_changed_ = true;
+ }
+ } else {
+ true_prob_.common.insert (std::make_pair (ID_,
+ true_prob_.probability));
+ // Update prob_changed_ flag.
+ prob_changed_ = true;
+ }
+ }
+
+ // Set false probability (i.e. probability of task failure) to 1 minus
+ // probability of success.
+ false_prob_.probability = 1 - true_prob_.probability;
+
+ // Update step (at end of step for task node).
+ step_++;
+
+ // Return boolean changed value based on change flags.
+ return (prob_changed_ || util_changed_);
+
+};
+
+Utility TaskNode::get_utility (int step)
+{
+ // Check to ensure step is the current step, or else throw exception
+ if (step != step_) {
+ throw Invalid_Step ();
+ }
+
+ // Variable for summing expected utility.
+ Utility utility = 0;
+
+ // Add positive expected utility, negative expected utility values, and
+ // subtract cost.
+ utility += pos_util_.utility + neg_util_.utility - cost_;
+
+ return utility;
+};
+
+void TaskNode::print (std::basic_ostream<char, std::char_traits<char> >&
+ strm, bool verbose)
+{
+ // Print node name and ID.
+ strm << "Task Node \"" << name_ << "\":" << std::endl;
+ strm << " ID: " << ID_ << std::endl;
+
+ // Print cost and expected utility.
+ strm << " Cost: " << cost_ << std::endl;
+ strm << " Expected Utility: " << get_utility (step_) << std::endl;
+
+ // If verbose, print positive and negative component utilities from goals.
+ if (verbose) {
+ // Print positive utility and its component utilities.
+ strm << " Positive utility received: " << pos_util_.utility << std::endl;
+ for (UtilityMap::iterator iter = pos_util_.common.begin ();
+ iter != pos_util_.common.end (); iter++)
+ {
+ strm << " Component expected utility from goal " << iter->first;
+ strm << " = " << iter->second;
+ strm << std::endl;
+ }
+
+ // Print negative utility and its component utilities.
+ strm << " Negative utility received: " << neg_util_.utility << std::endl;
+ for (UtilityMap::iterator iter = neg_util_.common.begin ();
+ iter != neg_util_.common.end (); iter++)
+ {
+ strm << " Component expected utility from goal " << iter->first;
+ strm << " = " << iter->second;
+ strm << std::endl;
+ }
+ }
+
+ // Print probability of task success.
+ strm << " Probability (success): " << true_prob_.probability << std::endl;
+
+ // If verbose, print common utility
+ if (verbose) {
+ for (ProbabilityMap::iterator iter = true_prob_.common.begin ();
+ iter != true_prob_.common.end (); iter++)
+ {
+ strm << " Component probability (possible loops only) from ";
+ strm << iter->first << " = " << iter->second;
+ strm << std::endl;
+ }
+ }
+
+ // If verbose, print probability of task failure.
+ if (verbose) {
+ strm << " Probability (failure): " << false_prob_.probability;
+ strm << std::endl;
+ }
+
+ // Current link map iterator input and output link printing loops.
+ LinkMap::iterator cur_link_iter;
+
+ // Print node input links.
+ strm << " In Links (preconditions):" << std::endl;
+ for (NodeMap::iterator node_iter = pre_nodes_.begin ();
+ node_iter != pre_nodes_.end (); node_iter++)
+ {
+ // Print input node name and ID.
+ strm << " " << node_iter->first << " ";
+ strm << "(" << node_iter->second->get_name () << "); ";
+
+ // Find link for this node.
+ cur_link_iter = pre_links_.find (node_iter->first);
+
+ // If this node couldn't be found in pre_links_ print error,
+ // otherwise print link weight.
+ if (cur_link_iter == pre_links_.end ()) {
+ strm << "ERROR: weight not found";
+ } else {
+ strm << "weight = " << cur_link_iter->second;
+ }
+ strm << std::endl;
+
+ // If verbose, print conditional probabilities of success for precondition.
+ if (verbose) {
+ strm << " Conditional probability if true: ";
+ strm << pre_true_probs_.find (node_iter->first)->second << std::endl;
+ strm << " Conditional probability if false: ";
+ strm << pre_false_probs_.find (node_iter->first)->second << std::endl;
+ }
+ }
+
+ // Print node output links.
+ strm << " Out Links (effects):" << std::endl;
+ for (NodeMap::iterator node_iter = post_nodes_.begin ();
+ node_iter != post_nodes_.end (); node_iter++)
+ {
+ // Print output node name and ID.
+ strm << " " << node_iter->first << " ";
+ strm << "(" << node_iter->second->get_name () << "); ";
+
+ // Find link for this node.
+ cur_link_iter = post_links_.find (node_iter->first);
+
+ // If this node couldn't be found in post_links_ print error,
+ // otherwise print link weight.
+ if (cur_link_iter == post_links_.end ()) {
+ strm << "ERROR: weight not found";
+ } else {
+ strm << "weight = " << cur_link_iter->second;
+ }
+ strm << std::endl;
+ }
+};
+
+void TaskNode::add_precond (CondID ID, CondNode *node, Probability true_prob,
+ Probability false_prob)
+{
+ // Add node to pre-nodes.
+ pre_nodes_.insert (std::make_pair (ID, node));
+
+ // Add probabilities.
+ pre_true_probs_.insert (std::make_pair (ID, true_prob));
+ pre_false_probs_.insert (std::make_pair (ID, false_prob));
+
+ // Add link weight.
+ LinkWeight weight = (true_prob - false_prob)/(true_prob + false_prob);
+ pre_links_.insert (std::make_pair (ID, weight));
+
+ // Add link for precondition node.
+ node->add_post_link (ID_, this, weight);
+};
+
+void TaskNode::add_effect (CondID ID, CondNode *node, LinkWeight weight)
+{
+ // Add node to post-nodes.
+ post_nodes_.insert (std::make_pair (ID, node));
+
+ // Add link weight.
+ post_links_.insert (std::make_pair (ID, weight));
+
+ // Add link for precondition node.
+ node->add_pre_link (ID_, this, weight);
+};
+
+CondNode::CondNode (CondID ID, std::string name, MultFactor atten_factor,
+ Probability true_prob, Probability false_prob, Utility goal_util, CondKind condkind)
+: Node (ID, name, atten_factor),
+ goal_util_ (goal_util),
+ init_true_prob_ (true_prob),
+ true_prob_from_ (ID),
+ false_prob_from_ (ID),
+ cond_kind_ (condkind)
+{
+ // Set initial probabilities.
+ true_prob_.probability = true_prob;
+ false_prob_.probability = false_prob;
+
+ // Set prob_changed_ flag.
+ prob_changed_ = true;
+
+ // If this node is a goal, set util_changed_ flag and add goal utility
+ // to positive utilities.
+ if (goal_util > 0) {
+ util_changed_ = true;
+ pos_util_.utility = goal_util;
+ pos_util_.common.insert (std::make_pair (ID, goal_util));
+ }
+};
+
+CondNode::~CondNode (void)
+{
+ // Nothing to do.
+};
+
+// Get initial/current probability.
+Probability CondNode::get_init_prob (bool value)
+{
+ if (value)
+ return this->init_true_prob_;
+
+ return (1.0 - this->init_true_prob_);
+};
+
+// Update initial/current probability.
+void CondNode::set_init_prob (Probability init_true_prob)
+{
+ this->init_true_prob_ = init_true_prob;
+ this->prob_changed_ = true;
+};
+
+void CondNode::print (std::basic_ostream<char, std::char_traits<char> >&
+ strm, bool verbose)
+{
+ // Print node name and ID.
+ strm << "Condition Node \"" << name_ << "\":" << std::endl;
+ strm << " ID: " << ID_ << std::endl;
+
+ // Print goal utility.
+ strm << " Goal utility: " << goal_util_ << std::endl;
+
+ // Print positive utility.
+ strm << " Expected utility for true value: " << pos_util_.utility;
+ strm << std::endl;
+
+ // If verbose, print component utilities from all goals.
+ if (verbose) {
+ for (UtilityMap::iterator iter = pos_util_.common.begin ();
+ iter != pos_util_.common.end (); iter++)
+ {
+ strm << " Component expected utility from goal " << iter->first;
+ strm << " = " << iter->second;
+ strm << std::endl;
+ }
+ }
+
+ // Print negative utility.
+ strm << " Expected utility for false value: " << neg_util_.utility;
+ strm << std::endl;
+
+ // If verbose, print component utilities from all goals.
+ if (verbose) {
+ for (UtilityMap::iterator iter = neg_util_.common.begin ();
+ iter != neg_util_.common.end (); iter++)
+ {
+ strm << " Component expected utility from goal " << iter->first;
+ strm << " = " << iter->second;
+ strm << std::endl;
+ }
+ }
+
+ // Print probability (maximum) that condition is true.
+ strm << " Probability (true): " << true_prob_.probability << std::endl;
+
+ // If verbose, print component probabilities for loops.
+ if (verbose) {
+ for (ProbabilityMap::iterator iter = true_prob_.common.begin ();
+ iter != true_prob_.common.end (); iter++)
+ {
+ strm << " Component probability (possible loops only) from ";
+ strm << iter->first << " = " << iter->second;
+ strm << std::endl;
+ }
+ }
+
+ // Print probability (maximum) that condition is false.
+ strm << " Probability (false): " << false_prob_.probability << std::endl;
+
+ // If verbose, print component probabilities for loops.
+ if (verbose) {
+ for (ProbabilityMap::iterator iter = false_prob_.common.begin ();
+ iter != false_prob_.common.end (); iter++)
+ {
+ strm << " Component probability (possible loops only) from ";
+ strm << iter->first << " = " << iter->second;
+ strm << std::endl;
+ }
+ }
+
+ // Current link map iterator input and output link printing loops.
+ LinkMap::iterator cur_link_iter;
+
+ // Print node input links.
+ strm << " In Links (tasks that change this condition):" << std::endl;
+ for (NodeMap::iterator node_iter = pre_nodes_.begin ();
+ node_iter != pre_nodes_.end (); node_iter++)
+ {
+ // Print input node name and ID.
+ strm << " " << node_iter->first << " ";
+ strm << "(" << node_iter->second->get_name () << "); ";
+
+ // Find link for this node.
+ cur_link_iter = pre_links_.find (node_iter->first);
+
+ // If this node couldn't be found in pre_links_ print error,
+ // otherwise print link weight.
+ if (cur_link_iter == pre_links_.end ()) {
+ strm << "ERROR: weight not found";
+ } else {
+ strm << "weight = " << cur_link_iter->second;
+ }
+ strm << std::endl;
+ }
+
+ // Print node output links.
+ strm << " Out Links (tasks that have this precondition):" << std::endl;
+ for (NodeMap::iterator node_iter = post_nodes_.begin ();
+ node_iter != post_nodes_.end (); node_iter++)
+ {
+ // Print output node name and ID.
+ strm << " " << node_iter->first << " ";
+ strm << "(" << node_iter->second->get_name () << "); ";
+
+ // Find link for this node.
+ cur_link_iter = post_links_.find (node_iter->first);
+
+ // If this node couldn't be found in post_links_ print error,
+ // otherwise print link weight.
+ if (cur_link_iter == post_links_.end ()) {
+ strm << "ERROR: weight not found";
+ } else {
+ strm << "weight = " << cur_link_iter->second;
+ }
+ strm << std::endl;
+ }
+};
+
+bool CondNode::update (void)
+{
+ // Reset change flags.
+ prob_changed_ = false;
+ util_changed_ = false;
+
+ // Update step (at beginning of step for condition node).
+ step_++;
+
+ // Flag for detection of loops.
+ bool is_loop = false;
+
+ // Variables for current node and link in updates.
+ TaskNode *cur_node;
+ TaskID cur_ID;
+ LinkMap::iterator link_iter;
+ LinkWeight cur_weight;
+ MultFactor cur_mult;
+
+ // Reset utility info.
+ pos_util_.utility = 0;
+ pos_util_.common.clear ();
+ neg_util_.utility = 0;
+ neg_util_.common.clear ();
+ // If this node is a goal, set add goal utility to positive utilities.
+ if (goal_util_ > 0) {
+ pos_util_.utility = goal_util_;
+ pos_util_.common.insert (std::make_pair (ID_, goal_util_));
+ };
+
+ // Variables for current utility updates.
+ Utility_Info cur_util;
+ UtilityMap::iterator prev_util_iter;
+
+ // Update utility.
+ for (NodeMap::iterator node_iter = post_nodes_.begin ();
+ node_iter != post_nodes_.end (); node_iter++)
+ {
+ // Get current node info.
+ cur_ID = node_iter->first;
+ cur_node = (TaskNode *) node_iter->second;
+
+ // Update util_changed_ flag if necessary.
+ if (cur_node->util_changed ()) {
+ util_changed_ = true;
+ }
+
+ // Get current link info.
+ link_iter = post_links_.find(cur_ID);
+ if (link_iter == post_links_.end ()) {
+ throw Update_Error ();
+ }
+ cur_weight = link_iter->second;
+
+ // Set multiplier as attenuation factor times link weight.
+ cur_mult = atten_factor_ * cur_weight;
+
+ // Get current utility info.
+ try {
+ cur_util = cur_node->get_reward (step_);
+ } catch (Invalid_Step e) {
+ std::cerr << "Error in condition node update: Invalid step value.";
+ std::cerr << std::endl;
+ return false;
+ } catch (...) {
+ std::cerr << "Unexpected exception thrown in condition node update.";
+ std::cerr << std::endl;
+ return false;
+ }
+
+ // Updated utility based on current multiplier.
+ cur_util.utility = cur_mult * cur_util.utility;
+
+ // Update positive or negative utilities depending on sign of link weight.
+ if (cur_weight >= 0) {
+ // Add utility to expected utility value.
+ pos_util_.utility += cur_util.utility;
+
+ // Update all component utilities based on link weight, and handle
+ // utilities from common goals.
+ for (UtilityMap::iterator util_iter = cur_util.common.begin ();
+ util_iter != cur_util.common.end (); util_iter++)
+ {
+ util_iter->second = cur_mult * util_iter->second;
+ prev_util_iter = pos_util_.common.find (util_iter->first);
+
+ // If a utility from this goal is already in the utility map,
+ // delete smaller utility value, otherwise add the utility from this
+ // goal to the utility map.
+ if (prev_util_iter != pos_util_.common.end ())
+ {
+#if defined (SANET_DEBUG)
+ std::cout << std::endl << "DEBUG in CondNode::update()... (" << ID_ << ") Duplicate utility from goal found:" << std::endl;
+ std::cout << "Utility from " << prev_util_iter->first << " = " << prev_util_iter->second << std::endl << std::endl;
+#endif /* SANET_DEBUG */
+ if (prev_util_iter->second < util_iter->second) {
+ pos_util_.utility -= prev_util_iter->second;
+ } else {
+ pos_util_.utility -= util_iter->second;
+ }
+ // Set loop flag.
+ is_loop = true;
+ } else {
+ pos_util_.common.insert (std::make_pair (util_iter->first,
+ util_iter->second));
+ }
+ }
+ } else {
+ // Add utility to expected utility value.
+ neg_util_.utility += cur_util.utility;
+
+ // Update all component utilities based on link weight, and handle
+ // utilities from common goals.
+ for (UtilityMap::iterator util_iter = cur_util.common.begin ();
+ util_iter != cur_util.common.end (); util_iter++)
+ {
+ util_iter->second = cur_mult * util_iter->second;
+ prev_util_iter = neg_util_.common.find (util_iter->first);
+
+ // If a utility from this goal is already in the utility map,
+ // delete larger (less negative) utility value, otherwise add the
+ // utility from this goal to the utility map.
+ if (prev_util_iter != neg_util_.common.end ())
+ {
+ if (prev_util_iter->second > util_iter->second) {
+ neg_util_.utility -= prev_util_iter->second;
+ } else {
+ neg_util_.utility -= util_iter->second;
+ }
+ // Set loop flag.
+ is_loop = true;
+ } else {
+ neg_util_.common.insert (std::make_pair (util_iter->first,
+ util_iter->second));
+ }
+ }
+ }
+ }
+
+ // Variables for current probability value.
+ Probability_Info cur_prob;
+ ProbabilityMap::iterator prob_iter;
+
+ // Update probability.
+ for (NodeMap::iterator node_iter = pre_nodes_.begin ();
+ node_iter != pre_nodes_.end (); node_iter++)
+ {
+ // Get current node info.
+ cur_ID = node_iter->first;
+ cur_node = (TaskNode *) node_iter->second;
+
+ // Get current link info.
+ link_iter = pre_links_.find(cur_ID);
+ if (link_iter == pre_links_.end ()) {
+ throw Update_Error ();
+ }
+ cur_weight = link_iter->second;
+
+ // Set multiplier as absolute value of link weight.
+ if (cur_weight >= 0) {
+ cur_mult = cur_weight;
+ } else {
+ cur_mult = -1 * cur_weight;
+ }
+
+ // Get current probability info.
+ try {
+ cur_prob = cur_node->get_prob (step_);
+ } catch (Invalid_Step e) {
+ std::cerr << "Error in condition node update: Invalid step value.";
+ std::cerr << std::endl;
+ return false;
+ } catch (...) {
+ std::cerr << "Unexpected exception thrown in condition node update.";
+ std::cerr << std::endl;
+ return false;
+ }
+
+ // Update probability based on current multiplier.
+ cur_prob.probability = cur_mult * cur_prob.probability;
+
+ // Update true or false probability depending on sign of link weight.
+ if (cur_weight >= 0) {
+ // Change true probability if this probability is higher than previous.
+ if (cur_prob.probability > true_prob_.probability) {
+ true_prob_ = cur_prob;
+ true_prob_from_ = cur_ID;
+
+ // Update prob_changed_ flag.
+ prob_changed_ = true;
+ }
+ // Otherwise check for newly detected common probabilities if current
+ // probability is from this node.
+ else if (true_prob_from_ == cur_ID) {
+ for (prob_iter = cur_prob.common.begin ();
+ prob_iter != cur_prob.common.end (); prob_iter++)
+ {
+ // If this common probability is not in current common probability
+ // map, add it.
+ if (true_prob_.common.find (prob_iter->first) ==
+ true_prob_.common.end ())
+ {
+ // Add common probability.
+ true_prob_.common.insert (std::make_pair (prob_iter->first,
+ prob_iter->second));
+
+ // Update prob_changed_ flag.
+ prob_changed_ = true;
+ }
+ }
+ }
+ } else {
+ // Change false probability if this probability is higher than previous.
+ if (cur_prob.probability > false_prob_.probability) {
+ false_prob_ = cur_prob;
+ false_prob_from_ = cur_ID;
+
+ // Update prob_changed_ flag.
+ prob_changed_ = true;
+ }
+ // Otherwise check for newly detected common probabilities if current
+ // probability is from this node.
+ else if (false_prob_from_ == cur_ID) {
+ for (prob_iter = cur_prob.common.begin ();
+ prob_iter != cur_prob.common.end (); prob_iter++)
+ {
+ // If this common probability is not in current common probability
+ // map, add it.
+ if (false_prob_.common.find (prob_iter->first) ==
+ false_prob_.common.end ())
+ {
+ // Add common probability.
+ false_prob_.common.insert (std::make_pair (prob_iter->first,
+ prob_iter->second));
+
+ // Update prob_changed_ flag.
+ prob_changed_ = true;
+ }
+ }
+ }
+ }
+ }
+
+ // If a loop was detected, add current probability to common probabilities.
+ if (is_loop) {
+#if defined (SANET_DEBUG)
+ std::cout << std::endl << "DEBUG in CondNode::update()... (" << ID_ << ") Loop detected, adding this node to common probabilities" << std::endl << std::endl;
+#endif /* SANET_DEBUG */
+ // Update common probabilities for true probability.
+ prob_iter = true_prob_.common.find (ID_);
+ if (prob_iter != true_prob_.common.end ()) {
+ prob_iter->second = true_prob_.probability;
+ } else {
+ true_prob_.common.insert (std::make_pair (ID_,
+ true_prob_.probability));
+ // Update prob_changed_ flag.
+ prob_changed_ = true;
+ }
+ }
+
+ // Return boolean changed value based on change flags.
+ return (prob_changed_ || util_changed_);
+};
+
+void CondNode::add_pre_link (TaskID ID, TaskNode *node, LinkWeight weight)
+{
+ // Add node to pre-nodes.
+ pre_nodes_.insert (std::make_pair (ID, node));
+
+ // Add link weight.
+ pre_links_.insert (std::make_pair (ID, weight));
+};
+
+void CondNode::add_post_link (TaskID ID, TaskNode *node, LinkWeight weight)
+{
+ // Add node to post-nodes.
+ post_nodes_.insert (std::make_pair (ID, node));
+
+ // Add link weight.
+ post_links_.insert (std::make_pair (ID, weight));
+};
+
+/// Get the kind
+CondKind CondNode::get_cond_kind()
+{
+ return this->cond_kind_;
+}
+