diff options
author | jkinnebrew <jkinnebrew@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 2009-12-29 22:36:29 +0000 |
---|---|---|
committer | jkinnebrew <jkinnebrew@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 2009-12-29 22:36:29 +0000 |
commit | aa28b017fc6276d6b41ddbdd7e09d195761dedf7 (patch) | |
tree | 566e7525eb7a0a6dcb30ea18153be847cdee4139 | |
parent | cd9ba4b205b47f9dfb5dfb08f6ab61f284545043 (diff) | |
download | ATCD-aa28b017fc6276d6b41ddbdd7e09d195761dedf7.tar.gz |
Tue Dec 29 22:28:23 UTC 2009 John S. Kinnebrew <john.s.kinnebrew@vanderbilt.edu>
-rw-r--r-- | SA_POP/ChangeLog | 42 | ||||
-rw-r--r-- | SA_POP/Planner.cpp | 14 | ||||
-rw-r--r-- | SA_POP/SANet/SANet.cpp | 307 | ||||
-rw-r--r-- | SA_POP/SANet/SANet.h | 153 | ||||
-rw-r--r-- | SA_POP/SANet/SANet_Standalone.mpc | 8 | ||||
-rw-r--r-- | SA_POP/SANet/SANet_Types.h | 19 | ||||
-rw-r--r-- | SA_POP/SANet/SANet_UI.cpp | 524 | ||||
-rw-r--r-- | SA_POP/SANet/SANode.cpp | 172 | ||||
-rw-r--r-- | SA_POP/SANet/SANode.h | 69 | ||||
-rw-r--r-- | SA_POP/SA_POP_Types.h | 18 | ||||
-rw-r--r-- | SA_POP/Standalone/SAPOP_Demo.mpc | 15 | ||||
-rw-r--r-- | SA_POP/Standalone/SA_POP_Demo.cpp | 102 | ||||
-rw-r--r-- | SA_POP/Standalone/UserInput.cpp | 33 | ||||
-rw-r--r-- | SA_POP/Standalone/UserInput.h | 42 | ||||
-rw-r--r-- | SA_POP/UserInput/InputCL.cpp | 152 | ||||
-rw-r--r-- | SA_POP/UserInput/InputCL.h | 166 | ||||
-rw-r--r-- | SA_POP/UserInput/Question.cpp | 124 | ||||
-rw-r--r-- | SA_POP/UserInput/Question.h | 172 |
18 files changed, 1683 insertions, 449 deletions
diff --git a/SA_POP/ChangeLog b/SA_POP/ChangeLog index 8803fed21b2..97d4655fee6 100644 --- a/SA_POP/ChangeLog +++ b/SA_POP/ChangeLog @@ -1,3 +1,40 @@ +Tue Dec 29 22:28:23 UTC 2009 John S. Kinnebrew <john.s.kinnebrew@vanderbilt.edu> + + * UserInput: + * UserInput/InputCL.h: + * UserInput/InputCL.cpp: + * UserInput/Question.h: + * UserInput/Question.cpp: + + Added reusable text user interface. + + + * Standalone/SAPOP_Demo.mpc: + * Standalone/SA_POP_Demo.cpp: + + Updated SA-POP Standalone to use new UI. + + + * Standalone/UserInput.h: + * Standalone/UserInput.cpp: + + Removed these old UI files. + + + * Planner.cpp: + * SA_POP_Types.h: + * SANet/SANet.h: + * SANet/SANet.cpp: + * SANet/SANet_Standalone.mpc: + * SANet/SANet_Types.h: + * SANet/SANet_UI.cpp: + * SANet/SANode.h: + * SANet/SANode.cpp: + + Added SANet cloning (deep copy by copy constructor). + Also cleaned up some more of the SANet code. + + Fri Dec 18 20:28:36 UTC 2009 John S. Kinnebrew <john.s.kinnebrew@vanderbilt.edu> * SA_POP_Types.h: @@ -22,8 +59,8 @@ Fri Dec 18 01:00:33 UTC 2009 John S. Kinnebrew <john.s.kinnebrew@vanderbilt.ed * SA_Builder.h: * SA_Builder.cpp: - Updated initialization of SA_Builder so overridden init() - method will work correctly. + Updated initialization of SA_Builder so overriding init() + method will work correctly in derived classes. * SAPOP_Exp_EU.mwc: @@ -42,7 +79,6 @@ Fri Dec 18 01:00:33 UTC 2009 John S. Kinnebrew <john.s.kinnebrew@vanderbilt.ed Added EU performance experiment skeleton. - * experiments/EU_Test: * experiments/EU_Test/EU_Test.mpc: * experiments/EU_Test/EU_Test.cpp: diff --git a/SA_POP/Planner.cpp b/SA_POP/Planner.cpp index 1862d015a70..89c3c1709a3 100644 --- a/SA_POP/Planner.cpp +++ b/SA_POP/Planner.cpp @@ -525,9 +525,6 @@ double Planner::calculate_plan_utility(size_t sa_max_steps) this->sanet_->set_task_state(this->working_plan_->get_task_from_inst((*it).second), true); this->sanet_->set_cond_state((*it).cond.id, true); -// this->sanet_->note_causal_link(*it); - - std::cout<<(*it).cond.id<<" cond, "<<(*it).first<<" first, "<<(*it).second<<" second"<<std::endl; @@ -540,15 +537,18 @@ double Planner::calculate_plan_utility(size_t sa_max_steps) this->sanet_->set_cond_state(it->first, true); } -// sanet_->restrict_prop_to_clinks(true); sanet_->update(sa_max_steps); -// sanet_->restrict_prop_to_clinks(false); double conj_utils = 0; for(GoalMap::iterator it = goals.begin(); it != goals.end(); it++){ std::cout<<it->second<<std::endl; - std::cout<<this->sanet_->get_cond_future_val(it->first, this->sanet_->get_step())<<std::endl; - conj_utils+=(it->second * this->sanet_->get_cond_future_val(it->first, this->sanet_->get_step())); + if (it->second >= 0.0) { + std::cout<<this->sanet_->get_cond_future_val(it->first, true)<<std::endl; + conj_utils+=(it->second * this->sanet_->get_cond_future_val(it->first, true)); + } else { + std::cout<<this->sanet_->get_cond_future_val(it->first, false)<<std::endl; + conj_utils+=(it->second * this->sanet_->get_cond_future_val(it->first, false)); + } } std::cout<<"Plan utility: "<<conj_utils<<std::endl; diff --git a/SA_POP/SANet/SANet.cpp b/SA_POP/SANet/SANet.cpp index 07cabb4066f..93883aaad50 100644 --- a/SA_POP/SANet/SANet.cpp +++ b/SA_POP/SANet/SANet.cpp @@ -17,16 +17,14 @@ #include "SANet.h" #include "SANode.h" #include "SANet_Exceptions.h" -#include "SA_POP_Types.h" using namespace SANet; SANet::Network::Network (void) : step_ (0) -//, restrict_prop_to_clinks_(false) { - // Clear maps & sets. + // All map/set member variables initially empty. this->task_nodes_.clear (); this->cond_nodes_.clear (); this->precond_links_.clear (); @@ -36,14 +34,104 @@ SANet::Network::Network (void) this->disabled_tasks_.clear (); this->active_conds_.clear (); this->disabled_conds_.clear (); -// this->causal_links_by_first_.clear (); -// this->causal_links_by_cond_.clear (); -// this->causal_links_by_second_.clear (); }; -int SANet::Network::get_step(){ - return step_; -} + +// Copy constructor. Performs initialization by making a deep copy +// of the provided network (including allocation of new nodes with +// state copied from nodes in provided network and creation of +// corresponding links between them). +SANet::Network::Network (const Network &s) +: step_ (s.step_) +{ + // Member variables that include node pointers are initially empty. + this->task_nodes_.clear (); + this->cond_nodes_.clear (); + + // Member variables that include links are initially empty (will be populated during link creation). + this->precond_links_.clear (); + this->effect_links_.clear (); + + // Copy active/disabled node (ID) sets (no node pointers and no links). + this->active_tasks_ = s.active_tasks_; + this->disabled_tasks_ = s.disabled_tasks_; + this->active_conds_ = s.active_conds_; + this->disabled_conds_ = s.disabled_conds_; + + // Copy goals (no node pointers and no links). + this->goals_ = s.goals_; + + // Create new nodes corresponding to those in s, adding each to appropriate node (ID to pointer) map. + for (TaskNodeMap::const_iterator node_iter = s.task_nodes_.begin (); + node_iter != s.task_nodes_.end (); node_iter++) + { + SANet::TaskNode *new_node = new SANet::TaskNode (*(node_iter->second)); + this->task_nodes_.insert (std::make_pair (node_iter->first, new_node)); + } + for (CondNodeMap::const_iterator node_iter = s.cond_nodes_.begin (); + node_iter != s.cond_nodes_.end (); node_iter++) + { + SANet::CondNode *new_node = new SANet::CondNode (*(node_iter->second)); + this->cond_nodes_.insert (std::make_pair (node_iter->first, new_node)); + } + + // Create precondition links corresponding to all those in s + // (using pointers to new nodes instead of the original nodes in s). + for (PrecondLinkPortMap::const_iterator link_iter = s.precond_links_.begin (); + link_iter != s.precond_links_.end (); link_iter++) + { + PrecondLink link = link_iter->first; + PortID port = link_iter->second; + + // Get pointer to task node in original network. + TaskNodeMap::const_iterator orig_task_iter = s.task_nodes_.find (link.second); + if (orig_task_iter == s.task_nodes_.end ()) + throw UnknownNode (); + TaskNode *orig_task = orig_task_iter->second; + + // Get precondition link conditional probabilities. + ConditionalProb prob = orig_task->get_precond_prob (link.first); + + // Add precondition link. + this->add_precond_link (link.first, link.second, prob.true_prob, prob.false_prob, port); + } + + // Create effect links corresponding to all those in s + // (using pointers to new nodes instead of the original nodes in s). + for (EffectLinkPortMap::const_iterator link_iter = s.effect_links_.begin (); + link_iter != s.effect_links_.end (); link_iter++) + { + EffectLink link = link_iter->first; + PortID port = link_iter->second; + + // Get pointer to task node. + TaskNodeMap::const_iterator orig_task_iter = s.task_nodes_.find (link.first); + if (orig_task_iter == s.task_nodes_.end ()) + throw UnknownNode (); + TaskNode *orig_task = orig_task_iter->second; + + // Get effect link probability. + Probability prob = orig_task->get_effect_prob (link.second); + + // Add effect link. + this->add_effect_link (link.first, link.second, prob, port); + } + +// Network data members + // STRUCTURE VARIABLES. +// TaskNodeMap task_nodes_; +// CondNodeMap cond_nodes_; +// PrecondLinkPortMap precond_links_; +// EffectLinkPortMap effect_links_; + // STATE VARIABLES. +// TaskIDSet active_tasks_; +// TaskIDSet disabled_tasks_; +// CondIDSet active_conds_; +// CondIDSet disabled_conds_; +// GoalMap goals_; +// int step_; +}; + SANet::Network::~Network () { @@ -62,10 +150,6 @@ SANet::Network::~Network () } }; -//void SANet::Network::restrict_prop_to_clinks(bool val){ -// restrict_prop_to_clinks_ = val; -//}; - void SANet::Network::add_task (TaskID ID, std::string name, MultFactor atten_factor, TaskCost cost, Probability prior_prob) { @@ -104,40 +188,6 @@ void SANet::Network::reset_step(){ } -/* -void SANet::Network::note_causal_link(SA_POP::CausalLink clink){ - causal_links_by_first_.insert(std::pair<TaskID, SA_POP::CausalLink> (clink.first, clink)); - causal_links_by_cond_.insert(std::pair<CondID, SA_POP::CausalLink> (clink.cond.id, clink)); - causal_links_by_second_.insert(std::pair<TaskID, SA_POP::CausalLink> (clink.second, clink)); -} - -bool SANet::Network::is_clink_first_to_cond_by_first(TaskID task, CondID cond){ - - for(std::multimap<SANet::TaskID, SA_POP::CausalLink>::iterator it = causal_links_by_first_.lower_bound(task); - it != causal_links_by_first_.upper_bound(task); it++){ - SA_POP::CausalLink clink = it->second; - if(clink.cond.id == cond){ - return true; - } - } - - return false; -} - -bool SANet::Network::is_clink_first_to_cond_by_cond(CondID cond, TaskID task){ - for(std::multimap<SANet::CondID, SA_POP::CausalLink>::iterator it = causal_links_by_cond_.lower_bound(task); - it != causal_links_by_cond_.upper_bound(cond); it++){ - SA_POP::CausalLink clink = it->second; - - if(clink.first == task){ - return true; - } - } - - return false; -} -*/ - Probability SANet::Network::get_prior(TaskID ID) { TaskNodeMap::iterator task_iter = task_nodes_.find (ID); @@ -536,13 +586,24 @@ Probability SANet::Network::get_cond_val (CondID cond_id) return iter->second->get_init_prob (); }; -Probability SANet::Network::get_cond_future_val(CondID cond_id, int step){ +// Get a condition's future probability for a given value. +// (NOTE: Future probability is based on whatever spreading +// activation has already been executed.) + +//****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****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**** +// (WARNING: Condition node must have been active for all +// spreading activation or exception will be thrown.) +//****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****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 SANet::Network::get_cond_future_val(CondID cond_id, bool value) +{ CondNodeMap::iterator iter = this->cond_nodes_.find(cond_id); if(iter == this->cond_nodes_.end()) - throw "SANet::Network::get_cond_val (): Unknown condition node."; - return iter->second->get_prob (step).probability; + throw "SANet::Network::get_cond_future_val (): Unknown condition node."; + return (iter->second->get_prob (this->step_, value)).probability; } + // Get all goals. const GoalMap& SANet::Network::get_goals (void) { @@ -665,12 +726,21 @@ CondSet SANet::Network::get_effects (TaskID task_id) return effects; }; + + +// ****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 +// Ankit's function get_duration() needs to be removed, once we ensure any +// scheduling code relying on it has been changed. + // Get the duration of a task. TimeValue SANet::Network::get_duration (TaskID task_id) { TaskNode *temp = this->task_nodes_.find(task_id)->second; return NULL_TIME; } +// ****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 + + // Get all tasks that satisfy a condition. TaskSet SANet::Network::get_satisfying_tasks (Condition cond) @@ -739,98 +809,89 @@ LinkPorts SANet::Network::get_clink_ports (TaskID task1_id, CondID cond_id, // Set Task State. void SANet::Network::set_task_state(TaskID task_ID, bool state) { - - task_nodes_.find(task_ID)->second->set_activity(state); - - if(state) - { - //insetr into active, remove from disabled - this->active_tasks_.insert(task_ID); - - this->disabled_tasks_.erase(task_ID); - - } - else - { - //remove from active, insert into disabled - - this->active_tasks_.erase(task_ID); - - this->disabled_tasks_.insert(task_ID); - } + // Get pointer to node from ID. + SANet::TaskNodeMap::iterator task_iter = this->task_nodes_.find(task_ID); + if (task_iter == this->task_nodes_.end ()) + throw UnknownNode (); + + // Use node pointer to set activity state. + task_iter->second->set_activity(state); + + if(state) { + // Insert into active task set & remove from disabled task set. + this->active_tasks_.insert(task_ID); + this->disabled_tasks_.erase(task_ID); + } else { + // Remove from active task set & insert into disabled task set. + this->active_tasks_.erase(task_ID); + this->disabled_tasks_.insert(task_ID); + } }; // Set Cond State. void SANet::Network::set_cond_state(CondID cond_ID, bool state) { - cond_nodes_.find(cond_ID)->second->set_activity(state); - if(state) - { - //insetr into active, remove from disabled - this->active_conds_.insert(cond_ID); - - - this->disabled_conds_.erase(cond_ID); - - } - else - { - //remove from active, insert into disabled + // Get pointer to node from ID. + SANet::CondNodeMap::iterator cond_iter = this->cond_nodes_.find(cond_ID); + if (cond_iter == this->cond_nodes_.end ()) + throw UnknownNode (); + + // Use node pointer to set activity state. + cond_iter->second->set_activity(state); - this->active_conds_.erase(cond_ID); + if(state) { + // Insert into active condition set & remove from disabled condition set. + this->active_conds_.insert(cond_ID); + this->disabled_conds_.erase(cond_ID); - this->disabled_conds_.insert(cond_ID); - } + } else { + // Remove from active condition set & insert into disabled condition set. + this->active_conds_.erase(cond_ID); + this->disabled_conds_.insert(cond_ID); + } }; // Set All nodes to State. void SANet::Network::set_nodes_state(bool state) { - if(state) + if(state) { + // For all tasks, activate, insert into active set, & remove from disabled set. + for (TaskNodeMap::iterator node_iter = task_nodes_.begin (); + node_iter != task_nodes_.end (); node_iter++) { + node_iter->second->set_activity(state); + this->active_tasks_.insert(node_iter->first); + this->disabled_tasks_.erase(node_iter->first); + } - //insetr all tasks into active, remove from disabled - for (TaskNodeMap::iterator node_iter = task_nodes_.begin (); - node_iter != task_nodes_.end (); node_iter++) - { - node_iter->second->set_activity(state); - this->active_tasks_.insert(node_iter->first); - - this->disabled_tasks_.erase(node_iter->first); - } - - for (CondNodeMap::iterator node_iter = cond_nodes_.begin (); - node_iter != cond_nodes_.end (); node_iter++) - { - node_iter->second->set_activity(state); - this->active_conds_.insert(node_iter->first); - - this->disabled_conds_.erase(node_iter->first); - } + // For all conditions, activate, insert into active set, & remove from disabled set. + for (CondNodeMap::iterator node_iter = cond_nodes_.begin (); + node_iter != cond_nodes_.end (); node_iter++) + { + node_iter->second->set_activity(state); + this->active_conds_.insert(node_iter->first); + this->disabled_conds_.erase(node_iter->first); } - else + } else { + // For all tasks, deactivate, remove from active set, & insert into disabled set. + for (TaskNodeMap::iterator node_iter = task_nodes_.begin (); + node_iter != task_nodes_.end (); node_iter++) { - //remove from active, insert into disabled - - for (TaskNodeMap::iterator node_iter = task_nodes_.begin (); - node_iter != task_nodes_.end (); node_iter++) - { - node_iter->second->set_activity(state); - this->active_tasks_.erase(node_iter->first); - - this->disabled_tasks_.insert(node_iter->first); - } - - for (CondNodeMap::iterator node_iter = cond_nodes_.begin (); - node_iter != cond_nodes_.end (); node_iter++) - { - node_iter->second->set_activity(state); - this->active_conds_.erase(node_iter->first); + node_iter->second->set_activity(state); + this->active_tasks_.erase(node_iter->first); + this->disabled_tasks_.insert(node_iter->first); + } - this->disabled_conds_.insert(node_iter->first); - } + // For all conditions, deactivate, remove from active set, & insert into disabled set. + for (CondNodeMap::iterator node_iter = cond_nodes_.begin (); + node_iter != cond_nodes_.end (); node_iter++) + { + node_iter->second->set_activity(state); + this->active_conds_.erase(node_iter->first); + this->disabled_conds_.insert(node_iter->first); } + } };
\ No newline at end of file diff --git a/SA_POP/SANet/SANet.h b/SA_POP/SANet/SANet.h index ef49ed94473..b50318b17d5 100644 --- a/SA_POP/SANet/SANet.h +++ b/SA_POP/SANet/SANet.h @@ -17,12 +17,16 @@ #include <iostream> #include <map> #include <set> -#include <stdexcept> #include "SANet_Types.h" #include "SANode.h" -#include "SA_POP_Types.h" namespace SANet { + /// Set of task node IDs. + typedef std::set<TaskID> TaskIDSet; + + /// Set of condition node IDs. + typedef std::set<CondID> CondIDSet; + /// Map from task node ID to pointer. typedef std::map<TaskID, TaskNode *> TaskNodeMap; @@ -45,13 +49,22 @@ namespace SANet { /// Constructor. Network (void); + /// Copy constructor. Performs initialization by making a deep copy + /// of the provided network (including allocation of new nodes with + /// state copied from nodes in provided network and creation of + /// corresponding links between them). + /** + * @param s Network to copy. + */ + Network (const Network &s); + /// Destructor. virtual ~Network (); // ************************************************************************ - // Network creations methods. + // Network creation methods. // ************************************************************************ /// Add a new task node to the network. @@ -81,9 +94,9 @@ namespace SANet { * * @param false_prob Initial probability that value is false. * - * @param cond_kind The type of condition + * @param cond_kind The type of condition. * - * @param goal_util Initial utility (positive for goals, zero otherwise). + * @param goal_util Initial utility (positive for TRUE goals, negative for FALSE goals, and zero for non-goals). */ virtual void add_cond (CondID ID, std::string name, MultFactor atten_factor, Probability true_prob, Probability false_prob, @@ -115,35 +128,12 @@ namespace SANet { * * @param weight Link weight (probability task sets condition to * true, or negative of the probability task sets condition to false). - * - * @param port_ID ID of port (on task) associated with this condition + * * @param port_ID ID of port (on task) associated with this condition * (used for data nodes). */ virtual void add_effect_link (TaskID task_ID, CondID cond_ID, LinkWeight weight, PortID port_ID = ""); - /// Set the state of a task node. - /** - * @param task_ID Task node ID. - * - * @param state New state (false for inactive, and true for active); - */ - virtual void set_task_state(TaskID task_ID, bool state); - - /// Set the state of a condition node. - /** - * @param cond_ID Condition node ID. - * - * @param state New state (false for inactive, and true for active); - */ - virtual void set_cond_state(CondID cond_ID, bool state); - - /// Set state of all nodes. - /** - * @param state New state (false for inactive, and true for active); - */ - virtual void set_nodes_state(bool state); - @@ -163,12 +153,14 @@ namespace SANet { /// Print Graphviz network representation to stream. /** * @param strm Output stream on which to print network representation. + * * @param graphmap The color mapping being used. + * * @param defaultColor The default color if it's not in the mapping. */ - virtual void print_graphviz (std::basic_ostream<char, std::char_traits<char> >& strm, std::map<std::string, std::string>& graphmap, std::string defaultColor = "grey"); - - + virtual void print_graphviz (std::basic_ostream<char, + std::char_traits<char> >& strm, std::map<std::string, std::string>& graphmap, + std::string defaultColor = "grey"); /// Print XML network representation to stream. /** @@ -226,7 +218,7 @@ namespace SANet { * * @param prior New prior probability; */ - virtual void update_prior(TaskID task_ID, Probability prior); + virtual void update_prior (TaskID task_ID, Probability prior); /// Update a task to condition link. /** @@ -240,8 +232,30 @@ namespace SANet { * @param port_ID ID of port (on task) associated with this condition * (used for data nodes). */ - virtual void update_effect_link(TaskID task_ID, CondID cond_ID, - LinkWeight weight, PortID port_ID= ""); + virtual void update_effect_link (TaskID task_ID, CondID cond_ID, + LinkWeight weight, PortID port_ID= ""); + + /// Set the state of a task node. + /** + * @param task_ID Task node ID. + * + * @param state New state (false for inactive, and true for active); + */ + virtual void set_task_state(TaskID task_ID, bool state); + + /// Set the state of a condition node. + /** + * @param cond_ID Condition node ID. + * + * @param state New state (false for inactive, and true for active); + */ + virtual void set_cond_state(CondID cond_ID, bool state); + + /// Set state of all nodes. + /** + * @param state New state (false for inactive, and true for active); + */ + virtual void set_nodes_state(bool state); @@ -283,6 +297,20 @@ namespace SANet { */ virtual Probability get_cond_val (CondID cond_id); + /// Get a condition's future probability for a given value. + /// (NOTE: Future probability is based on whatever spreading + /// activiation has already been executed.) + /// (WARNING: Condition node must have been active for all + /// spreading activation or exception will be thrown.) + /** + * @param cond_id Condition ID. + * + * @param value Value for which to get condition future probability. + * + * @return Future task expected utility. + */ + Probability get_cond_future_val(CondID cond_id, bool value); + /// Get all goals. /** * @return Set of condition ids and associated utilities. @@ -298,6 +326,8 @@ namespace SANet { virtual Utility get_task_current_eu (TaskID task_id); /// Get a task's future expected utility. + /// (NOTE: Future probability is based on whatever spreading + /// activiation has already been executed). /** * @param task_id The task id. * @@ -363,7 +393,7 @@ namespace SANet { /// Get the prior probability for a task node in the network. /** - * @param ID Node ID. + * @param ID ID of task node. * * @returns Prior probability of the task. */ @@ -373,29 +403,27 @@ namespace SANet { /** * @param task_ID Task ID. * - * @param cond_ID Cond ID. + * @param cond_ID Condition ID. * * @returns Weight of the effect link. */ virtual LinkWeight get_link(TaskID task_ID, CondID cond_ID); + + // ****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 + // Ankit's function get_duration() needs to be removed, once we ensure any + // scheduling code relying on it has been changed. + // ****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 + /// Get the duration of a task /** - * @param task_id ID of the Task + * @param task_id Task ID. * - * @return duration of the task + * @return Duration of the task. */ virtual TimeValue get_duration (TaskID task_id); - Probability get_cond_future_val(int step, CondID cond_id); - - int get_step(); - -// void note_causal_link(SA_POP::CausalLink clink); - -// void restrict_prop_to_clinks(bool val); - protected: // ************************************************************************ @@ -420,17 +448,17 @@ namespace SANet { // State variables. // ************************************************************************ - //Set of Active Task Nodes - std::set<SANet::TaskID> active_tasks_; + /// Set of active task nodes (by ID). + TaskIDSet active_tasks_; - //Set of Disabled Task Nodes - std::set<SANet::TaskID> disabled_tasks_; + /// Set of disabled task nodes (by ID). + TaskIDSet disabled_tasks_; - //Set of Active Condition Nodes - std::set<SANet::CondID> active_conds_; + /// Set of active condition nodes (by ID). + CondIDSet active_conds_; - //Set of Active Task Nodes - std::set<SANet::CondID> disabled_conds_; + /// Set of disabled condition nodes (by ID). + CondIDSet disabled_conds_; /// Goals. GoalMap goals_; @@ -439,26 +467,11 @@ namespace SANet { int step_; - -// bool restrict_prop_to_clinks_; - - -// std::multimap<TaskID, SA_POP::CausalLink> causal_links_by_first_; -// std::multimap<CondID, SA_POP::CausalLink> causal_links_by_cond_; -// std::multimap<TaskID, SA_POP::CausalLink> causal_links_by_second_; - - - // ************************************************************************ // State helper methods. // ************************************************************************ void reset_step(); - - //bool is_clink_first_to_cond_by_first(TaskID task, CondID cond); - //bool is_clink_first_to_cond_by_cond (CondID cond, TaskID task); - //bool is_clink_cond_to_second_by_second(TaskID task, CondID cond); - //bool is_clink_cond_to_second_by_cond(CondID cond, TaskiD second); }; }; diff --git a/SA_POP/SANet/SANet_Standalone.mpc b/SA_POP/SANet/SANet_Standalone.mpc index d49da025fcc..0f6a4c4b165 100644 --- a/SA_POP/SANet/SANet_Standalone.mpc +++ b/SA_POP/SANet/SANet_Standalone.mpc @@ -1,7 +1,8 @@ project(SANet_Demo) : xerces, aceexe, sapop_xml { exename = SANet_Demo - includes += $(SAPOP_ROOT) + includes += $(SAPOP_ROOT) \ + $(SAPOP_ROOT)/UserInput macros = SANET_STANDALONE @@ -15,6 +16,9 @@ project(SANet_Demo) : xerces, aceexe, sapop_xml { SANet_XML_Typedefs.h SANetFileIn.h + + $(SAPOP_ROOT)/UserInput/InputCL.h + $(SAPOP_ROOT)/UserInput/Question.h } @@ -29,6 +33,8 @@ project(SANet_Demo) : xerces, aceexe, sapop_xml { SANet_XML_Typedefs.cpp SANetFileIn.cpp XML_SANet.cpp + + $(SAPOP_ROOT)/UserInput/InputCL.cpp } Documentation_Files { diff --git a/SA_POP/SANet/SANet_Types.h b/SA_POP/SANet/SANet_Types.h index fa52d12647d..5b4483b516f 100644 --- a/SA_POP/SANet/SANet_Types.h +++ b/SA_POP/SANet/SANet_Types.h @@ -68,6 +68,9 @@ namespace SANet { /// Type of a probability. typedef SA_POP::Probability Probability; + /// Type of a conditional probability. + typedef SA_POP::ConditionalProb ConditionalProb; + /// Type of a (precondition or effect) link weight. typedef SA_POP::LinkWeight LinkWeight; @@ -248,6 +251,22 @@ namespace SANet { /// Type of a probability. typedef EUCalc Probability; + /// Type of a conditional probability. + struct ConditionalProb { + // Probability when conditioned variable is true. + Probability true_prob; + // Probability when conditioned variable is false. + Probability false_prob; + bool operator== (const ConditionalProb &s) const { return this->true_prob == s.true_prob && this->false_prob == s.false_prob; }; + bool operator!= (const ConditionalProb &s) const { return !(*this == s); }; + bool operator< (const ConditionalProb &s) const + { + if (this->true_prob == s.true_prob) + return this->false_prob < s.false_prob; + return this->true_prob < s.true_prob; + }; + }; + /// Type of a (precondition or effect) link weight. typedef EUCalc LinkWeight; diff --git a/SA_POP/SANet/SANet_UI.cpp b/SA_POP/SANet/SANet_UI.cpp index aeddd1edb6d..ad18f08cab1 100644 --- a/SA_POP/SANet/SANet_UI.cpp +++ b/SA_POP/SANet/SANet_UI.cpp @@ -20,6 +20,19 @@ #include <string> #include "SANet.h" #include "SANetFileIn.h" +#include "InputCL.h" + + +namespace SANet { + namespace Default { + const size_t SA_MAX_STEPS = 1000; + }; /* SANet::Default namespace */ +}; /* SANet namespace */ + +// Forward declaration of testing functions. +int test_clone (std::string filename); +int test_user_interface (void); +int test_net_gen (void); using namespace SANet; @@ -33,46 +46,402 @@ using namespace SANet; */ int main (int argc, char *argv[]) { - std::cout << "Spreading Activation Network User Interface" << std::endl; + std::cout << "Spreading Activation Network User Interface" << std::endl << std::endl; + + // To run a test, uncomment appropriate test function. +// return test_clone ("simple.san.xml"); +// return test_net_gen (); +// return test_user_interface (); + + UserInterface::InputCL user_input; // Get filename from user. - std::cout << "Network file: "; std::string filename = ""; - std::cin >> filename; + UserInterface::Question file_ques ("Spreading activation network file:"); + if (user_input.ask (file_ques)) + filename = file_ques.get_answer (); + + // Get flag for whether to output network configurations to files. + bool output_to_file = false; // Build network. SANetFileIn in; SANet::Network *net = in.build_net (filename); - // Print XML representation to output1.xml. - std::ofstream out_file ("output1.xml"); - if (out_file == 0){ - std::string msg = "Unable to open output1.xml for writing"; - throw msg; + // Display initial configuration. + std::cout << "Initial network configuration:" << std::endl; + net->print (std::cout, true); + + // Print XML representation to output_init.xml. + if (output_to_file) { + std::ofstream file_init ("output_init.xml"); + if (file_init == 0){ + std::string msg = "Unable to open output_init.xml for writing"; + throw msg; + } + net->print_xml (file_init); + file_init.close (); } - net->print_xml (out_file); - out_file.close (); -/* - net->add_cond (1111, "C1", 1, 1, 0, 0); - net->add_cond (1112, "C2", 1, 1, 0, 0); + // Get max steps from user. + size_t max_steps = SANet::Default::SA_MAX_STEPS; + UserInterface::QuestionInt steps_ques("Max steps to run (10000 step limit): ", 0, 10000); + if (user_input.ask (steps_ques)) + max_steps = steps_ques.get_answer_int (); + + + // Run spreading activation. + net->update (max_steps); + + // Display final configuration. + std::cout << "Final network configuration:" << std::endl; + net->print (std::cout, true); + + // Print XML representation to output_final.xml. + if (output_to_file) { + std::ofstream file_final ("output_final.xml"); + if (file_final == 0){ + std::string msg = "Unable to open output_final.xml for writing"; + throw msg; + } + net->print_xml (file_final); + file_final.close (); + } + + // Delete network. + delete net; + + // Wait for user to end program. +// UserInterface::Question end_ques ("Enter any character to end program:"); +// user_input.ask (end_ques); + + return 0; +}; + +int test_clone (std::string filename, bool output_to_file = false) +{ + UserInterface::InputCL user_input; + + // Build network. + SANetFileIn in; + SANet::Network *net = in.build_net (filename); + + // Create initial network clone. + SANet::Network *net_dupe_init = new SANet::Network (*net); + + // Display initial configurations. + std::cout << "Initial network configuration:" << std::endl; + net->print (std::cout, true); + std::cout << "Initial clone network configuration:" << std::endl; + net_dupe_init->print (std::cout, true); + + // Print initial XML representation of networks. + if (output_to_file) { + // Print initial network XML representation. + std::ofstream file_init ("output_init.xml"); + if (file_init == 0){ + std::string msg = "Unable to open output_init.xml for writing"; + throw msg; + } + net->print_xml (file_init); + file_init.close (); + + // Print initial clone network XML representation. + std::ofstream file_dupe_init ("output_clone_init.xml"); + if (file_dupe_init == 0){ + std::string msg = "Unable to open output_clone_init.xml for writing"; + throw msg; + } + net_dupe_init->print_xml (file_dupe_init); + file_dupe_init.close (); + } + + // Get max steps from user. + size_t max_steps = SANet::Default::SA_MAX_STEPS; + UserInterface::QuestionInt steps_ques("Max steps to run (10000 step limit): ", 0, 10000); + if (user_input.ask (steps_ques)) + max_steps = steps_ques.get_answer_int (); + + // Run spreading activation on original network. + net->update (max_steps); + + // Clone updated network. + SANet::Network *net_dupe_final = new SANet::Network (*net); + + // Display final configurations. + std::cout << "Final network configuration (ORIGINAL net) after spreading activation:" << std::endl; + net->print (std::cout, true); + std::cout << "Network configuration (CLONE of INITIAL net with no spreading activation performed):" << std::endl; + net_dupe_init->print (std::cout, true); + std::cout << "Network configuration (CLONE of FINAL net after spreading activation):" << std::endl; + net_dupe_final->print (std::cout, true); + + // Print final XML representation of networks. + if (output_to_file) { + // Print network XML representation. + std::ofstream file_final ("output_final.xml"); + if (file_final == 0){ + std::string msg = "Unable to open output_final.xml for writing"; + throw msg; + } + net->print_xml (file_final); + file_final.close (); + + // Print clone network XML representation. + std::ofstream file_dupe_final ("output_clone_final.xml"); + if (file_dupe_final == 0){ + std::string msg = "Unable to open output_clone_final.xml for writing"; + throw msg; + } + net_dupe_init->print_xml (file_dupe_final); + file_dupe_final.close (); + + // Print second (after SA) clone network XML representation. + std::ofstream file_dupe2_final ("output_clone2_final.xml"); + if (file_dupe2_final == 0){ + std::string msg = "Unable to open output_clone2_final.xml for writing"; + throw msg; + } + net_dupe_final->print_xml (file_dupe2_final); + file_dupe2_final.close (); + } + + + // Run spreading activation on clones. + net_dupe_init->update (max_steps); + net_dupe_final->update (max_steps); + + // Display final configurations. + std::cout << "Final network configuration (CLONE of INITIAL net) after spreading activation:" << std::endl; + net_dupe_init->print (std::cout, true); + std::cout << "Final network configuration (CLONE of FINAL net) after additional spreading activation:" << std::endl; + net_dupe_final->print (std::cout, true); + + + // Delete networks. + delete net; + delete net_dupe_init; + delete net_dupe_final; + + // Wait for user to end program. + UserInterface::Question end_ques ("Enter any character to end program:"); + user_input.ask (end_ques); + + return 0; +}; + + + +namespace UserInterface { + namespace Testing { + /// Type of an example enumerated type for user input. + enum RunKind {CONTINUE, STOP, EXIT, INVALID}; + }; /* UserInterface::Testing namespace */ +}; /* UserInterface namespace */ + + +int test_user_interface (void) +{ + std::string answer = "999999"; + int answer_int = 999999; + UserInterface::Testing::RunKind answer_val = UserInterface::Testing::INVALID; + std::string answer_val_str = "InVsTr"; + bool answer_bool = false; + + UserInterface::InputCL user_input; + + UserInterface::Question ques ("Testing display info."); + + user_input.info (ques); + + ques.set_prompt ("Testing prompt (enter anything):"); + user_input.ask (ques); + std::cout << "Your answer was \"" << ques.get_answer () << "\"" << std::endl; + + answer = "999999"; + answer_int = 999999; + UserInterface::QuestionInt ques_int ("Enter an integer between -100 and 5000:", -100, 5000); + + user_input.ask (ques_int); + answer = ques_int.get_answer (); + answer_int = ques_int.get_answer_int (); + std::cout << "Your answer was \"" << answer << "\" which equals " << answer_int << "." << std::endl; + + + + + std::cout << "QuestionChoice<int> case insensitive" << std::endl; + UserInterface::QuestionChoice<int> ques_choice_int ("Enter (O)ne, (T)wo, or (F)our:", -1); + ques_choice_int.add_mapping ("O", 1); + ques_choice_int.add_mapping ("One", 1); + ques_choice_int.add_mapping ("T", 2); + ques_choice_int.add_mapping ("Two", 2); + ques_choice_int.add_mapping ("F", 4); + ques_choice_int.add_mapping ("Four", 4); + + answer = "InV"; + answer_val_str = "InVsTr"; + answer_int = -2; + + user_input.ask (ques_choice_int); + answer = ques_choice_int.get_answer (); + answer_int = ques_choice_int.get_answer_val (); + switch (answer_int) + { + case 1: + answer_val_str = "1 value"; + break; + case 2: + answer_val_str = "2 value"; + break; + case 4: + answer_val_str = "4 value"; + break; + case -1: + answer_val_str = "INVALID value"; + break; + default: + answer_val_str = "Unknown answer value"; + break; + } + std::cout << "Your answer was \"" << answer << "\" which equals " << answer_val_str << "." << std::endl; + + + + + std::cout << "QuestionChoice case insensitive" << std::endl; + UserInterface::QuestionChoice<UserInterface::Testing::RunKind> ques_choice ("Enter (C)ontinue, (S)top, or (E)xit:", UserInterface::Testing::INVALID); + ques_choice.add_mapping ("C", UserInterface::Testing::CONTINUE); + ques_choice.add_mapping ("Continue", UserInterface::Testing::CONTINUE); + ques_choice.add_mapping ("S", UserInterface::Testing::STOP); + ques_choice.add_mapping ("Stop", UserInterface::Testing::STOP); + ques_choice.add_mapping ("E", UserInterface::Testing::EXIT); + ques_choice.add_mapping ("Exit", UserInterface::Testing::EXIT); + + answer = "InV"; + answer_val_str = "InVsTr"; + answer_val = UserInterface::Testing::INVALID; + + user_input.ask (ques_choice); + answer = ques_choice.get_answer (); + answer_val = ques_choice.get_answer_val (); + switch (answer_val) + { + case UserInterface::Testing::CONTINUE: + answer_val_str = "CONTINUE value"; + break; + case UserInterface::Testing::STOP: + answer_val_str = "STOP value"; + break; + case UserInterface::Testing::EXIT: + answer_val_str = "EXIT value"; + break; + case UserInterface::Testing::INVALID: + answer_val_str = "INVALID value"; + break; + default: + answer_val_str = "Unknown answer value"; + break; + } + std::cout << "Your answer was \"" << answer << "\" which equals " << answer_val_str << "." << std::endl; + + + std::cout << "QuestionChoice case sensitive" << std::endl; + UserInterface::QuestionChoice<UserInterface::Testing::RunKind> ques_choice_case ("Enter (C)ontinue, (S)top, or (E)xit:", UserInterface::Testing::INVALID, true); + ques_choice_case.add_mapping ("C", UserInterface::Testing::CONTINUE); + ques_choice_case.add_mapping ("Continue", UserInterface::Testing::CONTINUE); + ques_choice_case.add_mapping ("S", UserInterface::Testing::STOP); + ques_choice_case.add_mapping ("Stop", UserInterface::Testing::STOP); + ques_choice_case.add_mapping ("E", UserInterface::Testing::EXIT); + ques_choice_case.add_mapping ("Exit", UserInterface::Testing::EXIT); + + answer = "InV"; + answer_val_str = "InVsTr"; + answer_val = UserInterface::Testing::INVALID; + + user_input.ask (ques_choice_case); + answer = ques_choice_case.get_answer (); + answer_val = ques_choice_case.get_answer_val (); + switch (answer_val) + { + case UserInterface::Testing::CONTINUE: + answer_val_str = "CONTINUE value"; + break; + case UserInterface::Testing::STOP: + answer_val_str = "STOP value"; + break; + case UserInterface::Testing::EXIT: + answer_val_str = "EXIT value"; + break; + case UserInterface::Testing::INVALID: + answer_val_str = "INVALID value"; + break; + default: + answer_val_str = "Unknown answer value"; + break; + } + std::cout << "Your answer was \"" << answer << "\" which equals " << answer_val_str << "." << std::endl; + + + std::cout << "QuestionBool" << std::endl; + UserInterface::QuestionBool ques_bool ("Enter (Y)es or (N)o:", false); + + answer = "InV"; + answer_val_str = "InVsTr"; + answer_bool = true; + + user_input.ask (ques_bool); + answer = ques_bool.get_answer (); + answer_bool = ques_bool.get_answer_val (); + switch (answer_bool) + { + case true: + answer_val_str = "TRUE value"; + break; + case false: + answer_val_str = "FALSE value"; + break; + default: + answer_val_str = "Unknown answer value"; + break; + } + std::cout << "Your answer was \"" << answer << "\" which equals " << answer_val_str << "." << std::endl; + + + // Wait for user to end program. + UserInterface::Question end_ques ("Enter any character to end program:"); + user_input.ask (end_ques); + + return 0; +}; + + + +int test_net_gen (void) +{ + UserInterface::InputCL user_input; + + // Build network. + SANet::Network *net = new SANet::Network (); + + net->add_cond (1111, "C1", 1, 1, 0, 0, ENVIRON); + net->add_cond (1112, "C2", 1, 1, 0, 0, ENVIRON); net->add_task (2221, "A1", 1, 0, 0.375); - net->add_cond (1113, "C3", 1, 0, 1, 10); - net->add_cond (1114, "C4", 1, 0, 1, 10); + net->add_cond (1113, "C3", 1, 0, 1, 10, ENVIRON); + net->add_cond (1114, "C4", 1, 0, 1, 10, ENVIRON); net->add_precond_link (1111, 2221, 0.75, 0); net->add_precond_link (1112, 2221, 0.5, 0.25); net->add_effect_link (2221, 1113, 1); net->add_effect_link (2221, 1114, 0.9); -*/ /* - net->add_cond (1110, "C0", 1, 1, 0, 0); + net->add_cond (1110, "C0", 1, 1, 0, 0, ENVIRON); net->add_task (2221, "A1", 1, 0, 0.5); net->add_task (2222, "A2", 1, 0, 0.5); - net->add_cond (1111, "C1", 1, 0, 1, 0); - net->add_cond (1112, "C2", 1, 0, 1, 0); + net->add_cond (1111, "C1", 1, 0, 1, 0, ENVIRON); + net->add_cond (1112, "C2", 1, 0, 1, 0, ENVIRON); net->add_task (2223, "A3", 1, 1, 0.25); - net->add_cond (1113, "C3", 1, 0, 1, 10); + net->add_cond (1113, "C3", 1, 0, 1, 10, ENVIRON); net->add_precond_link (1110, 2221, 1, 0); net->add_precond_link (1110, 2222, 1, 0); net->add_effect_link (2221, 1111, 1); @@ -83,115 +452,58 @@ int main (int argc, char *argv[]) */ /* - net->add_cond (1111, "C1", 1, 1, 0, 0); - net->add_cond (1112, "C2", 1, 1, 0, 0); + net->add_cond (1111, "C1", 1, 1, 0, 0, ENVIRON); + net->add_cond (1112, "C2", 1, 1, 0, 0, ENVIRON); net->add_task (2221, "A1", 1, 1, 0.5); net->add_task (2222, "A2", 1, 3, 0.5); - net->add_cond (1113, "C3", 1, 0, 1, 10); + net->add_cond (1113, "C3", 1, 0, 1, 10, ENVIRON); net->add_precond_link (1111, 2221, 1, 0); net->add_precond_link (1112, 2222, 1, 0); net->add_effect_link (2221, 1113, 1); net->add_effect_link (2222, 1113, -1); */ -/* - net->print (); - - net->update (10); - std::cout << std::endl; + // Display initial configuration. + std::cout << "Initial network configuration:" << std::endl; net->print (std::cout, true); -*/ - -/* - std::string filename = ""; - Parser::XML_Parser parser; - Parser::XML_Object *obj; - Parser::SA_Net_Builder builder; - Network *net; - - // Get network file from user. - std::cout << "Network file: "; - std::cin >> filename; - - try { - obj = parser.parse_file (filename); - } catch (Parser::Invalid_File e) { - std::cerr << "Invalid File exception occurred while opening network file." << std::endl; - std::cerr << e.err_msg (); - return -1; - } catch (Parser::Duplicate_Param e) { - std::cerr << "Duplicate Parameter exception occurred while parsing network file." << std::endl; - std::cerr << e.err_msg (); - return -1; - } catch (Parser::Invalid_Character e) { - std::cerr << "Invalid Character exception occurred while parsing network file." << std::endl; - std::cerr << e.err_msg (); - return -1; - } catch (Parser::Invalid_Param_Name e) { - std::cerr << "Invalid Parameter Name exception occurred while parsing network file." << std::endl; - std::cerr << e.err_msg (); - return -1; - } catch (Parser::Invalid_Param_Type e) { - std::cerr << "Invalid Parameter Type exception occurred while parsing network file." << std::endl; - std::cerr << e.err_msg (); - return -1; - } catch (Parser::Invalid_Tag_Name e) { - std::cerr << "Invalid Tag Name exception occurred while parsing network file." << std::endl; - std::cerr << e.err_msg (); - return -1; - } catch (char *e) { - std::cerr << "Exception occurred while parsing network file." << std::endl; - std::cerr << e; - return -1; - } catch (...) { - std::cerr << "Unknown exception occurred while parsing network file."; - std::cerr << std::endl; - return -1; - } - try { - net = builder.build_net (obj); - } catch (char *e) { - std::cerr << "Exception occurred while building network." << std::endl; - std::cerr << e; - return -1; - } catch (...) { - std::cerr << "Unknown exception occurred while building network."; - std::cerr << std::endl; - return -1; + // Print XML representation to output_init.xml. + std::ofstream file_init ("output_init.xml"); + if (file_init == 0){ + std::string msg = "Unable to open output_init.xml for writing"; + throw msg; } -*/ - std::cout << "Initial network configuration:" << std::endl; - net->print (); + net->print_xml (file_init); + file_init.close (); // Get max steps from user. - std::cout << "Max steps to run: "; - std::string max_steps_str = ""; - std::cin >> max_steps_str; - + size_t max_steps = SANet::Default::SA_MAX_STEPS; + UserInterface::QuestionInt steps_ques("Max steps to run (10000 step limit): ", 0, 10000); + if (user_input.ask (steps_ques)) + max_steps = steps_ques.get_answer_int (); + // Run spreading activation. - net->update (atoi (max_steps_str.c_str ())); + net->update (max_steps); + // Display final configuration. std::cout << "Final network configuration:" << std::endl; net->print (std::cout, true); - std::ofstream out2_file ("output2.xml"); - if (out2_file == 0){ - std::string msg = "Unable to open output2.xml for writing"; + // Print XML representation to output_final.xml. + std::ofstream file_final ("output_final.xml"); + if (file_final == 0){ + std::string msg = "Unable to open output_final.xml for writing"; throw msg; } - net->print_xml (out2_file); - out2_file.close (); + net->print_xml (file_final); + file_final.close (); -// delete obj; delete net; -//****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****TEMP****TEMP****TEMP****TEMP****TEMP - std::cout << "Enter any character to end program: "; - char temp_; - std::cin>>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****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP + // Wait for user to end program. + UserInterface::Question end_ques ("Enter any character to end program:"); + user_input.ask (end_ques); return 0; -} +}; diff --git a/SA_POP/SANet/SANode.cpp b/SA_POP/SANet/SANode.cpp index 2a8838043a8..0eacee63dec 100644 --- a/SA_POP/SANet/SANode.cpp +++ b/SA_POP/SANet/SANode.cpp @@ -25,7 +25,7 @@ Node::Node (NodeID ID, std::string name, MultFactor atten_factor) step_ (0), prob_changed_ (false), util_changed_ (false) , - active(true) + active_ (true) { // Initialize probability and utility info. pos_util_.utility = 0; @@ -44,6 +44,50 @@ Node::Node (NodeID ID, std::string name, MultFactor atten_factor) post_links_.clear (); }; +// Copy constructor. Performs initialization by making a deep copy +// of the provided node (with the exception of network structural +// information about other nodes). +// (WARNING: Links, including their probability values and node +// pointers, to & from this node are EMPTY in the newly created copy.) +Node::Node (const Node &s) +: ID_ (s.ID_), + active_ (s.active_), + name_ (s.name_), + atten_factor_ (s.atten_factor_), + step_ (s.step_), + prob_changed_ (s.prob_changed_), + util_changed_ (s.util_changed_) +{ + // Initialize probability and utility info. + this->pos_util_ = s.pos_util_; + this->neg_util_ = s.neg_util_; + this->true_prob_ = s.true_prob_; + this->false_prob_ = s.false_prob_; + + // Initialize (EMPTY) pre- and post-node maps & links. + this->pre_nodes_.clear (); + this->pre_links_.clear (); + this->post_nodes_.clear (); + this->post_links_.clear (); + +// Node data members. +// NodeID ID_; +// bool active_; +// std::string name_; +// MultFactor atten_factor_; +// int step_; +// NodeMap pre_nodes_; +// NodeMap post_nodes_; +// LinkMap pre_links_; +// LinkMap post_links_; +// bool prob_changed_; +// bool util_changed_; +// Utility_Info pos_util_; +// Utility_Info neg_util_; +// Probability_Info true_prob_; +// Probability_Info false_prob_; +}; + Node::~Node () { // Nothing to do. @@ -93,7 +137,7 @@ std::string Node::get_name (void) /// Set activity flag void Node::set_activity (bool state) { - active = state; + this->active_ = state; } NodeID Node::get_ID (void) @@ -120,10 +164,52 @@ const LinkMap& Node::get_post (void) 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) + prior_prob_ (prior_prob), + cost_ (cost) { - // Nothing to do. + // Initialize (empty) pre-node maps (true/false conditional probabilities for preconditions). + this->pre_true_probs_.clear (); + this->pre_false_probs_.clear (); +}; + +// Copy constructor. Performs initialization by making a deep copy +// of the provided node (with the exception of network structural +// information about other nodes). +// (WARNING: Links, including their probability values and node +// pointers, to & from this node are EMPTY in the newly created copy.) +TaskNode::TaskNode (const TaskNode &s) +: Node (s), + prior_prob_ (s.prior_prob_), + cost_ (s.cost_) +{ + // Initialize (EMPTY) pre-node maps (true/false conditional probabilities for preconditions). + this->pre_true_probs_.clear (); + this->pre_false_probs_.clear (); + + // All other data members initialized to copy values by base class. + +// Node data members. +// NodeID ID_; +// bool active_; +// std::string name_; +// MultFactor atten_factor_; +// int step_; +// NodeMap pre_nodes_; +// NodeMap post_nodes_; +// LinkMap pre_links_; +// LinkMap post_links_; +// bool prob_changed_; +// bool util_changed_; +// Utility_Info pos_util_; +// Utility_Info neg_util_; +// Probability_Info true_prob_; +// Probability_Info false_prob_; + +// TaskNode additional data members. +// Probability prior_prob_; +// TaskCost cost_; +// LinkMap pre_true_probs_; +// LinkMap pre_false_probs_; }; TaskNode::~TaskNode (void) @@ -145,7 +231,7 @@ bool TaskNode::update (void) { //Check to see if node is active before updating - if(!active) + if(!(this->active_)) { //the node should return as not changing the network step_++; @@ -734,6 +820,27 @@ void TaskNode::add_precond (CondID ID, CondNode *node, Probability true_prob, node->add_post_link (ID_, this, weight); }; +// Get conditional probability of success for a particular precondition. +ConditionalProb TaskNode::get_precond_prob (CondID cond_ID) +{ + // Find conditional probability of success when precondition is true. + SANet::LinkMap::iterator link_true_iter = this->pre_true_probs_.find (cond_ID); + if (link_true_iter == this->pre_true_probs_.end ()) + throw UnknownNode (); + + // Find conditional probability of success when precondition is false. + SANet::LinkMap::iterator link_false_iter = this->pre_false_probs_.find (cond_ID); + if (link_false_iter == this->pre_false_probs_.end ()) + throw UnknownNode (); + + // Create conditional probability structure with true and false conditional probabilities. + ConditionalProb precond_prob; + precond_prob.true_prob = link_true_iter->second; + precond_prob.false_prob = link_false_iter->second; + + return precond_prob; +}; + void TaskNode::add_effect (CondID ID, CondNode *node, LinkWeight weight) { // Add node to post-nodes. @@ -769,6 +876,17 @@ void TaskNode::update_effect (CondID ID, CondNode *node, LinkWeight weight) node->update_pre_link (ID_, this, weight); }; +// Get probability of effect (link weight) for a particular effect condition. +Probability TaskNode::get_effect_prob (CondID cond_ID) +{ + // Find probability of effect. + SANet::LinkMap::iterator link_iter = this->post_links_.find (cond_ID); + if (link_iter == this->post_links_.end ()) + throw UnknownNode (); + + return link_iter->second; +}; + Probability TaskNode::get_prior (void) { return prior_prob_; @@ -807,6 +925,46 @@ CondNode::CondNode (CondID ID, std::string name, MultFactor atten_factor, } }; +// Copy constructor. Performs initialization by making a deep copy +// of the provided node (with the exception of network structural +// information about other nodes). +// (WARNING: Links, including their probability values and node +// pointers, to & from this node are EMPTY in the newly created copy.) +CondNode::CondNode (const CondNode &s) +: Node (s), + goal_util_ (s.goal_util_), + init_true_prob_ (s.init_true_prob_), + true_prob_from_ (s.true_prob_from_), + false_prob_from_ (s.false_prob_from_), + cond_kind_ (s.cond_kind_) +{ + // All other data members initialized to copy values by base class. + +// Node data members. +// NodeID ID_; +// bool active_; +// std::string name_; +// MultFactor atten_factor_; +// int step_; +// NodeMap pre_nodes_; +// NodeMap post_nodes_; +// LinkMap pre_links_; +// LinkMap post_links_; +// bool prob_changed_; +// bool util_changed_; +// Utility_Info pos_util_; +// Utility_Info neg_util_; +// Probability_Info true_prob_; +// Probability_Info false_prob_; + +// CondNode additional data members. +// Utility goal_util_; +// Probability init_true_prob_; +// TaskID true_prob_from_; +// TaskID false_prob_from_; +// CondKind cond_kind_; +}; + CondNode::~CondNode (void) { // Nothing to do. @@ -1001,7 +1159,7 @@ bool CondNode::update (void) { //Check to see if node is active before updating - if(!active) + if(!(this->active_)) { step_++; //the node should return as not changing the network diff --git a/SA_POP/SANet/SANode.h b/SA_POP/SANet/SANode.h index 4a205e86183..2a344adf09b 100644 --- a/SA_POP/SANet/SANode.h +++ b/SA_POP/SANet/SANode.h @@ -77,6 +77,16 @@ namespace SANet { */ Node (NodeID ID, std::string name, MultFactor atten_factor); + /// Copy constructor. Performs initialization by making a deep copy + /// of the provided node (with the exception of network structural + /// information about other nodes). + /// (WARNING: Links, including their probability values and node + /// pointers, to & from this node are EMPTY in the newly created copy.) + /** + * @param s Node to copy. + */ + Node (const Node &s); + /// Destructor. virtual ~Node (); @@ -165,7 +175,7 @@ namespace SANet { void reset_step(); bool is_active(){ - return active; + return active_; } protected: @@ -173,7 +183,7 @@ namespace SANet { NodeID ID_; /// Flag indicating whether the node is active. - bool active; + bool active_; /// Name of node (descriptive only). std::string name_; @@ -240,6 +250,16 @@ namespace SANet { TaskNode (TaskID ID, std::string name, MultFactor atten_factor, TaskCost cost, Probability prior_prob); + /// Copy constructor. Performs initialization by making a deep copy + /// of the provided node (with the exception of network structural + /// information about other nodes). + /// (WARNING: Links, including their probability values and node + /// pointers, to & from this node are EMPTY in the newly created copy.) + /** + * @param s Task node to copy. + */ + TaskNode (const TaskNode &s); + /// Destructor. virtual ~TaskNode (void); @@ -296,20 +316,15 @@ namespace SANet { */ virtual Utility get_utility (int step); - /// Get Prior of the TaskNode. + /// Get prior probability of the task. /** - * - * - * @return Expected utility. + * @return Prior probability of the task. */ virtual Probability get_prior (void); - /// Update Prior of the TaskNode. + /// Update prior probability of the task. /** - * - * @param prior the new prior for the task - * - * + * @param prior The new prior probability of the task. */ virtual void update_prior (Probability prior); @@ -329,11 +344,19 @@ namespace SANet { virtual void add_precond (CondID ID, CondNode *node, Probability true_prob, Probability false_prob); + /// Get conditional probability of success for a particular precondition. + /** + * @param cond_ID Precondition node. + * + * @return Conditional probability of the link. + */ + virtual ConditionalProb get_precond_prob (CondID cond_ID); + /// Add effect link. /** - * @param ID Node ID. + * @param ID ID of effect condition node ID. * - * @param node Node pointer. + * @param node Pointer to effect condition node. * * @param weight Link weight (probability task sets condition to * true, or negative of the probability task sets condition to false). @@ -342,7 +365,7 @@ namespace SANet { /// Update effect link. /** - * @param ID Node ID. + * @param ID ID of effect condition node ID. * * @param node Node pointer. * @@ -351,6 +374,14 @@ namespace SANet { */ virtual void update_effect (CondID ID, CondNode *node, LinkWeight weight); + /// Get probability of effect (link weight) for a particular effect condition. + /** + * @param cond_ID Effect condition node ID. + * + * @return Conditional probability of the link. + */ + virtual Probability get_effect_prob (CondID cond_ID); + void set_pos_util(double util); Utility_Info get_pos_util(); @@ -397,6 +428,16 @@ namespace SANet { CondNode (CondID ID, std::string name, MultFactor atten_factor, Probability true_prob, Probability false_prob, Utility goal_util, CondKind cond_kind); + /// Copy constructor. Performs initialization by making a deep copy + /// of the provided node (with the exception of network structural + /// information about other nodes). + /// (WARNING: Links, including their probability values and node + /// pointers, to & from this node are EMPTY in the newly created copy.) + /** + * @param s Condition node to copy. + */ + CondNode (const CondNode &s); + /// Destructor. virtual ~CondNode (void); diff --git a/SA_POP/SA_POP_Types.h b/SA_POP/SA_POP_Types.h index 5cf91c6b04d..ba17bf3feea 100644 --- a/SA_POP/SA_POP_Types.h +++ b/SA_POP/SA_POP_Types.h @@ -36,7 +36,7 @@ #define SA_POP_DEBUG_VERBOSE 30 // SET current SA-POP Debug output level. -#define SA_POP_DEBUG_LEVEL SA_POP_DEBUG_QUIET +#define SA_POP_DEBUG_LEVEL SA_POP_DEBUG_VERBOSE #define _CRTDBG_MAP_ALLOC #if defined (SA_POP_HAS_ACE) @@ -124,6 +124,22 @@ namespace SA_POP { /// Type of a probability. typedef EUCalc Probability; + /// Type of a conditional probability. + struct ConditionalProb { + // Probability when conditioned variable is true. + Probability true_prob; + // Probability when conditioned variable is false. + Probability false_prob; + bool operator== (const ConditionalProb &s) const { return this->true_prob == s.true_prob && this->false_prob == s.false_prob; }; + bool operator!= (const ConditionalProb &s) const { return !(*this == s); }; + bool operator< (const ConditionalProb &s) const + { + if (this->true_prob == s.true_prob) + return this->false_prob < s.false_prob; + return this->true_prob < s.true_prob; + }; + }; + /// Type of a (precondition or effect) link weight. typedef EUCalc LinkWeight; diff --git a/SA_POP/Standalone/SAPOP_Demo.mpc b/SA_POP/Standalone/SAPOP_Demo.mpc index ec49404f256..53194eeec62 100644 --- a/SA_POP/Standalone/SAPOP_Demo.mpc +++ b/SA_POP/Standalone/SAPOP_Demo.mpc @@ -1,16 +1,17 @@ project(SA_POP_Demo) : xerces, aceexe, sapop_core_standalone { exename = SA_POP_Demo - Source_Files { - SA_POP_Demo.cpp - UserInput.cpp - } + includes += $(SAPOP_ROOT)/UserInput - Inline_Files { + Header_Files { + $(SAPOP_ROOT)/UserInput/InputCL.h + $(SAPOP_ROOT)/UserInput/Question.h } - Header_Files { - UserInput.h + Source_Files { + SA_POP_Demo.cpp + + $(SAPOP_ROOT)/UserInput/InputCL.cpp } Documentation_Files { diff --git a/SA_POP/Standalone/SA_POP_Demo.cpp b/SA_POP/Standalone/SA_POP_Demo.cpp index b0f3e2d5f3e..64c916bef4f 100644 --- a/SA_POP/Standalone/SA_POP_Demo.cpp +++ b/SA_POP/Standalone/SA_POP_Demo.cpp @@ -14,49 +14,57 @@ #include <iostream> #include "SA_POP_Types.h" #include "SA_Builder.h" -#include "UserInput.h" #include "TaskMapFileIn.h" #include "SANet/SANetFileIn.h" #include "LogScreenOut.h" +#include "InputCL.h" + + +// SA-POP DEFAULTS. +namespace SA_POP { + namespace Default { + const SA_POP::CondID CondIDMin = 1; + const SA_POP::CondID CondIDMax = 999999; + const SA_POP::Utility GoalUtilMin = -1000; + const SA_POP::Utility GoalUtilMax = 1000; + }; /* SA_POP::Default namespace */ +}; /* SA_POP namespace */ + +// SPREADING ACTIVATION DEFAULTS. +namespace SANet { + namespace Default { + const size_t SA_MAX_STEPS = 1000; + }; /* SANet::Default namespace */ +}; /* SANet namespace */ + + int main (int argc, char* argv[]) { SA_POP::SA_Builder builder; SANet::SANetFileIn sanet_in; SA_POP::TaskMapFileIn tm_in; + SA_POP::Planner *planner = 0; + UserInterface::InputCL user_input; + std::string sanet_filename = ""; std::string tm_filename = ""; + SA_POP::CondID goal_id = 0; + SA_POP::Utility goal_util = 0; + size_t max_steps = SANet::Default::SA_MAX_STEPS; - // Get filenames from user. - std::cout << "Task Network file: "; -// sanet_filename = "../examples/output1.xml"; -// sanet_filename = "../examples/SPACE.san.xml"; -// sanet_filename = "../examples/test_graph1.san.xml"; - std::cin >> sanet_filename; - - std::cout << "Task Map file: "; -// tm_filename = "../examples/SPACE.tm.xml"; -// tm_filename = "../examples/test_graph.tm.xml"; - std::cin >> tm_filename; - SA_POP::Goal goal; - goal.goal_id = "UserSpecifiedGoal ID"; - goal.name = "User specified goal"; - goal.abs_times.clear (); - goal.rel_times.clear (); - goal.goal_conds.clear (); - goal.start_window = std::make_pair (0, 0); + // Get filenames from user. + UserInterface::Question sanet_file_ques ("Task Network file:"); + if (user_input.ask (sanet_file_ques)) + sanet_filename = sanet_file_ques.get_answer (); + UserInterface::Question tm_file_ques ("Task Map file:"); + if (user_input.ask (tm_file_ques)) + tm_filename = tm_file_ques.get_answer (); - // Get goal. - SA_POP::CondID goal_id; - SA_POP::Utility goal_util; - std::cout << "Goal condition ID: "; - std::cin >> goal_id; - std::cout << "Goal utility: "; - std::cin >> goal_util; - goal.goal_conds.insert (std::make_pair (goal_id, goal_util)); + // Build task network and task map. try { sanet_in.build_net (sanet_filename, &builder); tm_in.build_task_map (tm_filename, &builder); @@ -65,19 +73,45 @@ int main (int argc, char* argv[]) std::cerr << std::endl; std::cerr << e; } catch (...) { - std::cerr << "UNKNOWN ERROR while planning." << std::endl; + std::cerr << "UNKNOWN ERROR while building task network and task map from files." << std::endl; } - SA_POP::Planner *planner = 0; + // Create goal. + SA_POP::Goal goal; + goal.goal_id = "UserSpecifiedGoal ID"; + goal.name = "User specified goal"; + goal.abs_times.clear (); + goal.rel_times.clear (); + goal.goal_conds.clear (); + goal.start_window = std::make_pair (0, 0); + + // Get goal condition and utility from user. + UserInterface::QuestionInt goal_id_ques ("Goal condition ID:", SA_POP::Default::CondIDMin, SA_POP::Default::CondIDMax); + if (user_input.ask (goal_id_ques)) + goal_id = goal_id_ques.get_answer_int (); + UserInterface::QuestionInt goal_util_ques ("Goal utility:", SA_POP::Default::GoalUtilMin, SA_POP::Default::GoalUtilMax); + if (user_input.ask (goal_util_ques)) + goal_util = goal_util_ques.get_answer_int (); + + goal.goal_conds.insert (std::make_pair (goal_id, goal_util)); + + + // Get maximum steps of spreading activation from user. + UserInterface::QuestionInt steps_ques("Max steps to run (10000 step limit): ", 0, 10000); + if (user_input.ask (steps_ques)) + max_steps = steps_ques.get_answer_int (); + + + // Run SA-POP. try { planner = builder.get_planner (); SA_POP::LogScreenOut screen_out (std::cout); planner->add_out_adapter (&screen_out); - planner->plan (100, goal); + planner->plan (max_steps, goal); } catch (std::string e) { std::cerr << "ERROR while planning:" << std::endl; std::cerr << e; @@ -89,11 +123,9 @@ int main (int argc, char* argv[]) delete planner; -//****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****TEMP****TEMP****TEMP****TEMP****TEMP - std::cout << "Enter any character to end program: "; - char temp_; - std::cin>>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****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP + // Wait for user to end program. +// UserInterface::Question end_ques ("Enter any character to end program:"); +// user_input.ask (end_ques); return 0; } diff --git a/SA_POP/Standalone/UserInput.cpp b/SA_POP/Standalone/UserInput.cpp deleted file mode 100644 index a216b91cbff..00000000000 --- a/SA_POP/Standalone/UserInput.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// -*- C++ -*- -// $Id$ - -//============================================================================= -/** - * @file UserInput.cpp - * - * This file contains the UserInput class implementation for the input adapter - * that provides a user interface for testing SA-POP. - * - * @author John S. Kinnebrew <john.s.kinnebrew@vanderbilt.edu> - */ -//============================================================================= - -#include "SA_POP_Types.h" -#include "UserInput.h" -#include "Builder.h" -#include "Planner.h" - - -using namespace SA_POP; - -// Constructor. -UserInput::UserInput (void) -{ - //****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****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP -}; - -// Destructor. -UserInput::~UserInput (void) -{ - //****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****TEMP****TEMP****TEMP****TEMP****TEMP****TEMP -}; diff --git a/SA_POP/Standalone/UserInput.h b/SA_POP/Standalone/UserInput.h deleted file mode 100644 index b1b2b52111c..00000000000 --- a/SA_POP/Standalone/UserInput.h +++ /dev/null @@ -1,42 +0,0 @@ -// -*- C++ -*- -// $Id$ - -//============================================================================= -/** - * @file UserInput.h - * - * This file contains the UserInput class definition for the input adapter - * that provides a user interface for testing SA-POP. - * - * @author John S. Kinnebrew <john.s.kinnebrew@vanderbilt.edu> - */ -//============================================================================= - -#ifndef SA_POP_USER_INPUT_H_ -#define SA_POP_USER_INPUT_H_ - -#include "SA_POP_Types.h" -#include "UserInput.h" -#include "Builder.h" -#include "Planner.h" - - -namespace SA_POP { - - /** - * @class UserInput - * - * @brief Input adapter that provides a user interface for testing SA-POP. - */ - class UserInput { - public: - /// Constructor. - UserInput (void); - - /// Destructor. - virtual ~UserInput (void); - }; - -}; /* SA_POP namespace */ - -#endif /* SA_POP_USER_INPUT_H_ */ diff --git a/SA_POP/UserInput/InputCL.cpp b/SA_POP/UserInput/InputCL.cpp new file mode 100644 index 00000000000..b097a6d96b7 --- /dev/null +++ b/SA_POP/UserInput/InputCL.cpp @@ -0,0 +1,152 @@ +// -*- C++ -*- +// $Id$ + +//============================================================================= +/** + * @file InputCL.cpp + * + * This file contains the InputCL class implementation for the command line + * input adapter (helper class for command line interfaces). + * + * @author John S. Kinnebrew <john.s.kinnebrew@vanderbilt.edu> + */ +//============================================================================= + +#include <iostream> +#include <string> + +#include "InputCL.h" +#include "Question.h" + +using namespace UserInterface; + +// Constructor. +InputCL::InputCL (std::basic_ostream<char, std::char_traits<char> >& ostrm, + std::basic_istream<char, std::char_traits<char> >& istrm) +: ostrm_ (ostrm), + istrm_ (istrm) +{ + // Nothing to initialize. +}; + +// Destructor. +InputCL::~InputCL (void) +{ + // Nothing to do. +}; + +// Provide info to user. +void InputCL::info (UserInterface::Question info) +{ + this->ostrm_ << info.get_prompt (); + this->ostrm_ << std::endl; +}; + +// Ask the user a question (continues asking until they provide a valid answer). +bool InputCL::ask (UserInterface::Question& question, size_t max_repeat) +{ + // Display question and get answer until receiving a valid response or maximum + // number of repeats has been reached. + std::string answer = ""; + for (size_t reps = 0; reps < max_repeat; reps++) { + // Display question. + this->ostrm_ << question.get_prompt (); + this->ostrm_ << " "; + + // Get answer. + this->istrm_ >> answer; + + // Break out of question asking loop if user provided a valid answer. + if (question.is_valid_answer (answer)) + break; + + // User provided an invalid answer, so display response. + this->ostrm_ << question.get_invalid_response (); + this->ostrm_ << std::endl; + } + + // Set answer in question object and return flag indicating its validity. + return question.answer (answer); +}; + + + + + + + +// Constructor. +QuestionInt::QuestionInt (std::string prompt, int min, int max, std::string invalid_response) +: Question (prompt, invalid_response), + min_ (min), + max_ (max) +{ + // Nothing to do. +}; + +// Destructor. +QuestionInt::~QuestionInt (void) +{ + // Nothing to do. +}; + +// Is an answer valid for this question? +bool QuestionInt::is_valid_answer (std::string answer) +{ + int i; + std::istringstream answer_ss (answer); + + if (answer_ss >> i) + { + if (i >= this->min_ && i <= this->max_) + return true; + } + + return false; +}; + +// Get answer. +int QuestionInt::get_answer_int () +{ + int i = 0; + std::istringstream answer_ss (this->answer_); + + if (answer_ss >> i) + return i; + + return this->min_; +}; + + + + + +// Constructor +QuestionBool::QuestionBool (std::string prompt, bool def_val, std::string invalid_response) +: QuestionChoice (prompt, def_val, false, invalid_response) +{ + this->init_map (); +}; + +// Destructor. +QuestionBool::~QuestionBool (void) +{ + // Nothing to do. +}; + +// Get answer. +bool QuestionBool::get_answer_bool (void) +{ + return this->get_answer_val (); +}; + +// Initialize mapping with yes/no answers. +void QuestionBool::init_map (void) +{ + this->answer_map_.clear (); + this->add_mapping ("Y", true); + this->add_mapping ("Yes", true); + this->add_mapping ("N", false); + this->add_mapping ("No", false); +}; + diff --git a/SA_POP/UserInput/InputCL.h b/SA_POP/UserInput/InputCL.h new file mode 100644 index 00000000000..2656c967b6d --- /dev/null +++ b/SA_POP/UserInput/InputCL.h @@ -0,0 +1,166 @@ +// -*- C++ -*- +// $Id$ + +//============================================================================= +/** + * @file InputCL.h + * + * This file contains the class definition of InputCL and related classes for + * the command line input adapter (helper class for command line interfaces). + * + * @author John S. Kinnebrew <john.s.kinnebrew@vanderbilt.edu> + */ +//============================================================================= + +#ifndef USER_INTERFACE_INPUT_CL_H_ +#define USER_INTERFACE_INPUT_CL_H_ + +#include <iostream> +#include <string> + +#include "Question.h" + +namespace UserInterface { + + namespace Default { + const size_t MAX_QUESTION_REPEAT = 5; + }; /* Default namespace */ + + + /** + * @class InputCL + * + * @brief Command line input adapter (helper class for command line interfaces). + */ + class InputCL { + public: + /// Constructor. + /** + * @param ostrm Output stream to display questions/prompts and info to user. + * + * @param istrm Input stream to get user input. + */ + InputCL (std::basic_ostream<char, std::char_traits<char> >& ostrm + = std::cout, std::basic_istream<char, std::char_traits<char> >& istrm + = std::cin); + + /// Destructor. + virtual ~InputCL (void); + + /// Provide info to user. + /** + * @param info Question class with info for user. + */ + void info (UserInterface::Question info); + + /// Ask the user a question. + /** + * @param question Question for user (question object will be updated with last user answer upon return). + * + * @param max_repeat Maximum number of times to repeat question when user provides invalid answer(s). + * + * @return True if user provided a valid answer to question, false otherwise. + */ + bool ask (UserInterface::Question& question, size_t max_repeat = UserInterface::Default::MAX_QUESTION_REPEAT); + + protected: + /// Output stream to display questions/prompts and info to user. + std::basic_ostream<char, std::char_traits<char> >& ostrm_; + + /// Input stream to get user input. + std::basic_istream<char, std::char_traits<char> >& istrm_; + }; + + + + + + + + + + + + + + /** + * @class QuestionInt + * + * @brief Class for a user question with an integer answer. + */ + class QuestionInt : public Question { + public: + /// Constructor. + /** + * @param prompt Prompt/question for user. + * + * @param min Minimum (inclusive) valid answer. + * + * @param max Maximum (inclusive) valid answer. + * + * @param invalid_response Response string for when user provides an invalid answer. + */ + QuestionInt (std::string prompt, int min, int max, std::string invalid_response = UserInterface::Default::INVALID_RESPONSE_STR); + + /// Destructor. + virtual ~QuestionInt (void); + + /// Is an answer valid for this question? + /** + * @param answer Answer to check validity. + * + * @return True for a valid answer or false for an invalid answer. + */ + virtual bool is_valid_answer (std::string answer); + + /// Get answer. + /** + * @return Answer from user (if no valid answer provided, returns minimum valid answer). + */ + int get_answer_int (void); + + protected: + /// Minimum (inclusive) valid answer. + int min_; + + /// Maximum (inclusive) valid answer. + int max_; + + }; + + /** + * @class QuestionBool + * + * @brief Class for a user question with a boolean (yes/no) answer. + * Valid answer strings (case insensitive) corresponding to true are "y" and "yes". + * Valid answer strings (case insensitive) corresponding to false are "n" and "no". + */ + class QuestionBool : public QuestionChoice<bool> { + public: + /// Constructor. + /** + * @param prompt Prompt/question (or info) for user. + * + * @param def_val Default value returned if no valid answer provided. + * + * @param invalid_response Response string for when user provides an invalid answer. + */ + QuestionBool (std::string prompt, bool def_val, std::string invalid_response = UserInterface::Default::INVALID_RESPONSE_STR); + + /// Destructor. + virtual ~QuestionBool (void); + + /// Get answer. + /** + * @return Answer from user (if no valid answer provided, returns default value). + */ + bool get_answer_bool (void); + + protected: + /// Initialize mapping with yes/no answers. + void init_map (void); + }; + +}; /* UserInterface namespace */ + +#endif /* USER_INTERFACE_INPUT_CL_H_ */ diff --git a/SA_POP/UserInput/Question.cpp b/SA_POP/UserInput/Question.cpp new file mode 100644 index 00000000000..14ffb39905d --- /dev/null +++ b/SA_POP/UserInput/Question.cpp @@ -0,0 +1,124 @@ +// -*- C++ -*- +// $Id$ + +//============================================================================= +/** + * @file Question.cpp + * + * This file contains the implementation of Question classes for use with + * the command line input adapter (InputCL). + * + * @author John S. Kinnebrew <john.s.kinnebrew@vanderbilt.edu> + */ +//============================================================================= + +#ifndef USER_INTERFACE_QUESTION_CPP_ +#define USER_INTERFACE_QUESTION_CPP_ + +#include <string> +#include <sstream> +#include <map> +#include <algorithm> + +#include "Question.h" + +using namespace UserInterface; + + + +// Constructor. +template <typename T> +QuestionChoice<T>::QuestionChoice (std::string prompt, T invalid_val, bool match_case, std::string invalid_response) +: Question (prompt, invalid_response), + invalid_val_ (invalid_val), + match_case_ (match_case) +{ + // Clear map from answers to values. + this->answer_map_.clear (); +}; + +// Destructor. +template <typename T> +QuestionChoice<T>::~QuestionChoice (void) +{ + // Nothing to do. +}; + +// Is an answer valid for this question? +template <typename T> bool +QuestionChoice<T>::is_valid_answer (std::string answer) +{ + std::string ans = answer; + + // If case insensitive, convert answer to upper case before checking answer map. + if (!this->match_case_) + std::transform(ans.begin(), ans.end(), ans.begin(), ::toupper); + + // If answer is not in answer map, it is not valid. + if (this->answer_map_.find (ans) == this->answer_map_.end ()) + return false; + + return true; +}; + +// Get answer. +template <typename T> T +QuestionChoice<T>::get_answer_val (void) +{ + std::string ans = this->answer_; + + // If case insensitive, convert answer to upper case before checking answer map. + if (!this->match_case_) + std::transform(ans.begin(), ans.end(), ans.begin(), ::toupper); + + // Find answer in answer map. + std::map<std::string, T>::iterator answer_iter = this->answer_map_.find (ans); + + // If answer is not in answer map, return invalid value. + if (answer_iter == this->answer_map_.end ()) + return this->invalid_val_; + + return answer_iter->second; +}; + +// Set complete mapping from answers to values. +// (WARNING: Map will completely replace all existing mappings.) +template <typename T> void +QuestionChoice<T>::set_map (const std::map<std::string, T> &answer_map) +{ + // Overwrite current mapping with new mapping (converting answers + // to upper case, if not case sensitive). + if (this->match_case_) { + this->answer_map_ = answer_map; + } else { + // Clear current map. + this->answer_map_.clear (); + + // Convert each answer to upper case and insert with value into answer map. + std::string ans = ""; + for (std::map<std::string, T>::const_iterator ans_iter = answer_map.begin (); ans_iter != answer_map; ans_iter++) { + ans = ans_iter->first; + std::transform(ans.begin(), ans.end(), ans.begin(), ::toupper); + this->answer_map_.insert (std::make_pair (ans, ans_iter->second)); + } + } +}; + +// Add a mapping from an answer to a value (or replace with provided +// value if a mapping already exists for the answer). +template <typename T> void +QuestionChoice<T>::add_mapping (std::string answer, T value) +{ + std::string ans = answer; + + // If case insensitive, convert answer to upper case before inserting in answer map. + if (!this->match_case_) + std::transform(ans.begin(), ans.end(), ans.begin(), ::toupper); + + this->answer_map_.insert (std::make_pair (ans, value)); +}; + + + + +#endif /* USER_INTERFACE_QUESTION_CPP_ */ diff --git a/SA_POP/UserInput/Question.h b/SA_POP/UserInput/Question.h new file mode 100644 index 00000000000..05e841cb83c --- /dev/null +++ b/SA_POP/UserInput/Question.h @@ -0,0 +1,172 @@ +// -*- C++ -*- +// $Id$ + +//============================================================================= +/** + * @file Question.h + * + * This file contains the declarations of Question classes for use with + * the command line input adapter (InputCL). + * + * @author John S. Kinnebrew <john.s.kinnebrew@vanderbilt.edu> + */ +//============================================================================= + +#ifndef USER_INTERFACE_QUESTION_H_ +#define USER_INTERFACE_QUESTION_H_ + +#include <string> +#include <sstream> +#include <map> + +namespace UserInterface { + + namespace Default { + const std::string INVALID_RESPONSE_STR = "Sorry, that is not a valid answer."; + }; /* Default namespace */ + + /** + * @class Question + * + * @brief Base class for a user question (or info for user). + */ + class Question { + public: + /// Constructor. + /** + * @param prompt Prompt/question (or info) for user. + * + * @param invalid_response Response string for when user provides an invalid answer. + */ + Question (std::string prompt, std::string invalid_response = UserInterface::Default::INVALID_RESPONSE_STR) + : prompt_ (prompt), invalid_response_ (invalid_response), answer_ ("") { }; + + /// Destructor. + virtual ~Question (void) { }; + + /// Set prompt. + /** + * @param prompt Prompt/question (or info) for user. + */ + void set_prompt (std::string prompt) { this->prompt_ = prompt; }; + + /// Get prompt. + /** + * @return Prompt/question (or info) for user. + */ + std::string get_prompt () { return this->prompt_; }; + + /// Get response string for when user provides an invalid answer. + /** + * @return Response string for when user provides an invalid answer. + */ + std::string get_invalid_response () { return this->invalid_response_; }; + + /// Is an answer valid for this question? + /** + * @param answer Answer to check validity. + * + * @return True for a valid answer or false for an invalid answer. + */ + virtual bool is_valid_answer (std::string answer) { return true; }; + + /// Provide user answer. + /** + * @param answer User answer. + * + * @return True for a valid answer or false for an invalid answer. + */ + virtual bool answer (std::string answer) { if (this->is_valid_answer (answer)) {this->answer_ = answer; return true;} return false; }; + + /// Get answer. + /** + * @return Answer from user (if no valid answer provided, returns empty string). + */ + std::string get_answer () { return this->answer_; }; + + protected: + /// Prompt/question (or info) for user. + std::string prompt_; + + /// Response to user when they provide an invalid answer to the question. + std::string invalid_response_; + + /// Answer. + std::string answer_; + }; + + + /** + * @class QuestionChoice + * + * @brief Class for a user question with a mapping from answers to values. + */ + template <typename T> + class QuestionChoice : public Question { + public: + /// Class trait of its answer value type. + typedef T TYPE; + + /// Constructor. + /** + * @param prompt Prompt/question for user. + * + * @param invalid_val Value to return if no valid answer provided. + * + * @param match_case Match case of answer strings? (i.e., case sensitive?) + * + * @param invalid_response Response string for when user provides an invalid answer. + */ + QuestionChoice (std::string prompt, T invalid_val, bool match_case = false, std::string invalid_response = UserInterface::Default::INVALID_RESPONSE_STR); + + /// Destructor. + virtual ~QuestionChoice (void); + + /// Is an answer valid for this question? + /** + * @param answer Answer to check validity. + * + * @return True for a valid answer or false for an invalid answer. + */ + virtual bool is_valid_answer (std::string answer); + + /// Get answer. + /** + * @return Value corresponding to answer from user (if no valid answer provided, returns invalid_val parameter from constructor). + */ + T get_answer_val (void); + + /// Set complete mapping from answers to values. + /// (WARNING: Map will completely replace all existing mappings.) + /** + * @param answer_map Map from valid answer strings to corresponding values. + */ + void set_map (const std::map<std::string, T> &answer_map); + + /// Add a mapping from an answer to a value (or replace with provided + /// value if a mapping already exists for the answer). + /** + * @param answer Valid answer string. + * + * @param value Value corresponding to answer string. + */ + void add_mapping (std::string answer, T value); + + protected: + /// Match case of strings? (i.e., case sensitive?) + bool match_case_; + + /// Value to indicate invalid answer. + T invalid_val_; + + /// Map from answers to values. + std::map<std::string, T> answer_map_; + }; + + + +}; /* UserInterface namespace */ + +#include "Question.cpp" + +#endif /* USER_INTERFACE_QUESTION_H_ */ |