Soar Kernel  9.3.2 08-06-12
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
Macros | Functions
episodic_memory.cpp File Reference
#include <portability.h>
#include <cmath>
#include <algorithm>
#include <iterator>
#include <iostream>
#include <fstream>
#include <set>
#include <climits>
#include "episodic_memory.h"
#include "semantic_memory.h"
#include "agent.h"
#include "prefmem.h"
#include "symtab.h"
#include "wmem.h"
#include "print.h"
#include "xml.h"
#include "instantiations.h"
#include "decide.h"

Go to the source code of this file.

Macros

#define QUERY_DEBUG   0

Functions

void _epmem_install_id_wme (agent *my_agent, Symbol *parent, Symbol *attr, std::map< epmem_node_id, std::pair< Symbol *, bool > > *ids, epmem_node_id q1, bool val_is_short_term, char val_letter, uint64_t val_num, epmem_id_mapping *id_record, soar_module::symbol_triple_list &retrieval_wmes)
std::string _epmem_print_sti (epmem_node_id id)
void _epmem_process_buffered_wme_list (agent *my_agent, Symbol *state, soar_module::wme_set &cue_wmes, soar_module::symbol_triple_list &my_list, epmem_wme_stack *epmem_wmes)
void _epmem_promote_id (agent *my_agent, Symbol *id, epmem_time_id t)
void _epmem_respond_to_cmd_parse (agent *my_agent, epmem_wme_list *cmds, bool &good_cue, int &path, epmem_time_id &retrieve, Symbol *&next, Symbol *&previous, Symbol *&query, Symbol *&neg_query, epmem_time_list &prohibit, epmem_time_id &before, epmem_time_id &after, epmem_symbol_set &currents, soar_module::wme_set &cue_wmes)
void _epmem_store_level (agent *my_agent, std::queue< Symbol * > &parent_syms, std::queue< epmem_node_id > &parent_ids, tc_number tc, epmem_wme_list::iterator w_b, epmem_wme_list::iterator w_e, epmem_node_id parent_id, epmem_time_id time_counter, std::map< wme *, epmem_id_reservation * > &id_reservations, std::set< Symbol * > &new_identifiers, std::queue< epmem_node_id > &epmem_node, std::queue< epmem_node_id > &epmem_edge)
bool epmem_backup_db (agent *my_agent, const char *file_name, std::string *err)
void epmem_buffer_add_wme (soar_module::symbol_triple_list &my_list, Symbol *id, Symbol *attr, Symbol *value)
epmem_literalepmem_build_dnf (wme *cue_wme, epmem_wme_literal_map &literal_cache, epmem_literal_set &leaf_literals, epmem_symbol_int_map &symbol_num_incoming, epmem_literal_deque &gm_ordering, epmem_symbol_set &currents, int query_type, std::set< Symbol * > &visiting, soar_module::wme_set &cue_wmes, agent *my_agent)
void epmem_clear_result (agent *my_agent, Symbol *state)
void epmem_close (agent *my_agent)
bool epmem_consider_new_episode (agent *my_agent)
bool epmem_enabled (agent *my_agent)
epmem_wme_listepmem_get_augs_of_id (Symbol *id, tc_number tc)
bool epmem_get_variable (agent *my_agent, epmem_variable_key variable_id, int64_t *variable_value)
bool epmem_gm_mcv_comparator (const epmem_literal *a, const epmem_literal *b)
void epmem_go (agent *my_agent, bool allow_store)
bool epmem_graph_match (epmem_literal_deque::iterator &dnf_iter, epmem_literal_deque::iterator &iter_end, epmem_literal_node_pair_map &bindings, epmem_node_symbol_map bound_nodes[], agent *my_agent, int depth=0)
void epmem_init_db (agent *my_agent, bool readonly=false)
void epmem_install_memory (agent *my_agent, Symbol *state, epmem_time_id memory_id, soar_module::symbol_triple_list &meta_wmes, soar_module::symbol_triple_list &retrieval_wmes, epmem_id_mapping *id_record=NULL)
void epmem_new_episode (agent *my_agent)
epmem_time_id epmem_next_episode (agent *my_agent, epmem_time_id memory_id)
epmem_time_id epmem_previous_episode (agent *my_agent, epmem_time_id memory_id)
void epmem_print_episode (agent *my_agent, epmem_time_id memory_id, std::string *buf)
void epmem_print_retrieval_state (epmem_wme_literal_map &literals, epmem_triple_pedge_map pedge_caches[], epmem_triple_uedge_map uedge_caches[])
void epmem_process_buffered_wmes (agent *my_agent, Symbol *state, soar_module::wme_set &cue_wmes, soar_module::symbol_triple_list &meta_wmes, soar_module::symbol_triple_list &retrieval_wmes)
void epmem_process_query (agent *my_agent, Symbol *state, Symbol *pos_query, Symbol *neg_query, epmem_time_list &prohibits, epmem_time_id before, epmem_time_id after, epmem_symbol_set &currents, soar_module::wme_set &cue_wmes, soar_module::symbol_triple_list &meta_wmes, soar_module::symbol_triple_list &retrieval_wmes, int level=3)
bool epmem_register_pedges (epmem_node_id parent, epmem_literal *literal, epmem_pedge_pq &pedge_pq, epmem_time_id after, epmem_triple_pedge_map pedge_caches[], epmem_triple_uedge_map uedge_caches[], agent *my_agent)
void epmem_reset (agent *my_agent, Symbol *state)
void epmem_respond_to_cmd (agent *my_agent)
void epmem_rit_add_left (agent *my_agent, epmem_time_id min, epmem_time_id max)
void epmem_rit_add_right (agent *my_agent, epmem_time_id id)
void epmem_rit_clear_left_right (agent *my_agent)
int64_t epmem_rit_fork_node (int64_t lower, int64_t upper, bool, int64_t *step_return, epmem_rit_state *rit_state)
void epmem_rit_insert_interval (agent *my_agent, int64_t lower, int64_t upper, epmem_node_id id, epmem_rit_state *rit_state)
void epmem_rit_prep_left_right (agent *my_agent, int64_t lower, int64_t upper, epmem_rit_state *rit_state)
bool epmem_satisfy_literal (epmem_literal *literal, epmem_node_id parent, epmem_node_id child, double &current_score, long int &current_cardinality, epmem_symbol_node_pair_int_map &symbol_node_count, epmem_triple_uedge_map uedge_caches[], epmem_symbol_int_map &symbol_num_incoming)
void epmem_schedule_promotion (agent *my_agent, Symbol *id)
void epmem_set_variable (agent *my_agent, epmem_variable_key variable_id, int64_t variable_value)
epmem_hash_id epmem_temporal_hash (agent *my_agent, Symbol *sym, bool add_on_fail=true)
bool epmem_unsatisfy_literal (epmem_literal *literal, epmem_node_id parent, epmem_node_id child, double &current_score, long int &current_cardinality, epmem_symbol_node_pair_int_map &symbol_node_count)
bool epmem_valid_episode (agent *my_agent, epmem_time_id memory_id)
void epmem_visualize_episode (agent *my_agent, epmem_time_id memory_id, std::string *buf)

Macro Definition Documentation

#define QUERY_DEBUG   0

Function Documentation

void _epmem_install_id_wme ( agent my_agent,
Symbol parent,
Symbol attr,
std::map< epmem_node_id, std::pair< Symbol *, bool > > *  ids,
epmem_node_id  q1,
bool  val_is_short_term,
char  val_letter,
uint64_t  val_num,
epmem_id_mapping id_record,
soar_module::symbol_triple_list retrieval_wmes 
)
inline

Definition at line 2761 of file episodic_memory.cpp.

References epmem_buffer_add_wme(), symbol_union::id, identifier_struct::impasse_wmes, identifier_struct::input_wmes, identifier_struct::level, make_new_identifier(), sym_constant_struct::name, symbol_union::sc, identifier_struct::slots, smem_lti_get_id(), smem_lti_soar_make(), SYM_CONSTANT_SYMBOL_TYPE, and symbol_remove_ref().

Referenced by epmem_install_memory().

{
std::map< epmem_node_id, std::pair< Symbol*, bool > >::iterator id_p = ids->find( q1 );
bool existing_identifier = ( id_p != ids->end() );
if ( val_is_short_term )
{
if ( !existing_identifier )
{
id_p = ids->insert( std::make_pair< epmem_node_id, std::pair< Symbol*, bool > >( q1, std::make_pair< Symbol*, bool >( make_new_identifier( my_agent, ( ( attr->common.symbol_type == SYM_CONSTANT_SYMBOL_TYPE )?( attr->sc.name[0] ):('E') ), parent->id.level ), true ) ) ).first;
if ( id_record )
{
epmem_id_mapping::iterator rec_p = id_record->find( q1 );
if ( rec_p != id_record->end() )
{
rec_p->second = id_p->second.first;
}
}
}
epmem_buffer_add_wme( retrieval_wmes, parent, attr, id_p->second.first );
if ( !existing_identifier )
{
symbol_remove_ref( my_agent, id_p->second.first );
}
}
else
{
if ( existing_identifier )
{
epmem_buffer_add_wme( retrieval_wmes, parent, attr, id_p->second.first );
}
else
{
Symbol* value = smem_lti_soar_make( my_agent, smem_lti_get_id( my_agent, val_letter, val_num ), val_letter, val_num, parent->id.level );
if ( id_record )
{
epmem_id_mapping::iterator rec_p = id_record->find( q1 );
if ( rec_p != id_record->end() )
{
rec_p->second = value;
}
}
epmem_buffer_add_wme( retrieval_wmes, parent, attr, value );
symbol_remove_ref( my_agent, value );
ids->insert( std::make_pair< epmem_node_id, std::pair< Symbol*, bool > >( q1, std::make_pair< Symbol*, bool >( value, !( ( value->id.impasse_wmes ) || ( value->id.input_wmes ) || ( value->id.slots ) ) ) ) );
}
}
}
std::string _epmem_print_sti ( epmem_node_id  id)
inline

Definition at line 4475 of file episodic_memory.cpp.

Referenced by epmem_print_episode().

{
std::string t1, t2;
t1.assign( "<id" );
to_string( id, t2 );
t1.append( t2 );
t1.append( ">" );
return t1;
}
void _epmem_process_buffered_wme_list ( agent my_agent,
Symbol state,
soar_module::wme_set cue_wmes,
soar_module::symbol_triple_list my_list,
epmem_wme_stack epmem_wmes 
)
inline

Definition at line 908 of file episodic_memory.cpp.

References add_preference_to_tm(), chunk_instantiation(), symbol_union::id, insert_at_head_of_dll, preference_struct::inst_next, soar_module::make_fake_instantiation(), instantiation_struct::next, NIL, preference_add_ref(), preference_remove_ref(), identifier_struct::preferences_from_goal, instantiation_struct::preferences_generated, wma_activate_wmes_in_pref(), and wma_enabled().

Referenced by epmem_process_buffered_wmes().

{
if ( my_list.empty() )
{
return;
}
instantiation* inst = soar_module::make_fake_instantiation( my_agent, state, &cue_wmes, &my_list );
for ( preference* pref=inst->preferences_generated; pref; pref=pref->inst_next )
{
// add the preference to temporary memory
if ( add_preference_to_tm( my_agent, pref ) )
{
// add to the list of preferences to be removed
// when the goal is removed
insert_at_head_of_dll( state->id.preferences_from_goal, pref, all_of_goal_next, all_of_goal_prev );
pref->on_goal_list = true;
if ( epmem_wmes )
{
// if this is a meta wme, then it is completely local
// to the state and thus we will manually remove it
// (via preference removal) when the time comes
epmem_wmes->push_back( pref );
}
}
else
{
preference_remove_ref( my_agent, pref );
}
}
if ( !epmem_wmes )
{
// otherwise, we submit the fake instantiation to backtracing
// such as to potentially produce justifications that can follow
// it to future adventures (potentially on new states)
instantiation *my_justification_list = NIL;
chunk_instantiation( my_agent, inst, false, &my_justification_list );
// if any justifications are created, assert their preferences manually
// (copied mainly from assert_new_preferences with respect to our circumstances)
if ( my_justification_list != NIL )
{
preference *just_pref = NIL;
instantiation *next_justification = NIL;
for ( instantiation *my_justification=my_justification_list;
my_justification!=NIL;
my_justification=next_justification )
{
next_justification = my_justification->next;
if ( my_justification->in_ms )
{
insert_at_head_of_dll( my_justification->prod->instantiations, my_justification, next, prev );
}
for ( just_pref=my_justification->preferences_generated; just_pref!=NIL; just_pref=just_pref->inst_next )
{
if ( add_preference_to_tm( my_agent, just_pref ) )
{
if ( wma_enabled( my_agent ) )
{
wma_activate_wmes_in_pref( my_agent, just_pref );
}
}
else
{
preference_add_ref( just_pref );
preference_remove_ref( my_agent, just_pref );
}
}
}
}
}
}
void _epmem_promote_id ( agent my_agent,
Symbol id,
epmem_time_id  t 
)
inline
void _epmem_respond_to_cmd_parse ( agent my_agent,
epmem_wme_list cmds,
bool &  good_cue,
int path,
epmem_time_id retrieve,
Symbol *&  next,
Symbol *&  previous,
Symbol *&  query,
Symbol *&  neg_query,
epmem_time_list prohibit,
epmem_time_id before,
epmem_time_id after,
epmem_symbol_set currents,
soar_module::wme_set cue_wmes 
)
inline

Definition at line 5041 of file episodic_memory.cpp.

References EPMEM_MEMID_NONE, agent_struct::epmem_sym_after, agent_struct::epmem_sym_before, agent_struct::epmem_sym_current, agent_struct::epmem_sym_negquery, agent_struct::epmem_sym_next, agent_struct::epmem_sym_prev, agent_struct::epmem_sym_prohibit, agent_struct::epmem_sym_query, agent_struct::epmem_sym_retrieve, IDENTIFIER_SYMBOL_TYPE, and INT_CONSTANT_SYMBOL_TYPE.

Referenced by epmem_respond_to_cmd().

{
cue_wmes.clear();
retrieve = EPMEM_MEMID_NONE;
next = NULL;
previous = NULL;
query = NULL;
neg_query = NULL;
prohibit.clear();
before = EPMEM_MEMID_NONE;
good_cue = true;
path = 0;
for ( epmem_wme_list::iterator w_p=cmds->begin(); w_p!=cmds->end(); w_p++ )
{
cue_wmes.insert( (*w_p) );
if ( good_cue )
{
// collect information about known commands
if ( (*w_p)->attr == my_agent->epmem_sym_retrieve )
{
if ( ( (*w_p)->value->ic.common_symbol_info.symbol_type == INT_CONSTANT_SYMBOL_TYPE ) &&
( path == 0 ) &&
( (*w_p)->value->ic.value > 0 ) )
{
retrieve = (*w_p)->value->ic.value;
path = 1;
}
else
{
good_cue = false;
}
}
else if ( (*w_p)->attr == my_agent->epmem_sym_next )
{
if ( ( (*w_p)->value->id.common_symbol_info.symbol_type == IDENTIFIER_SYMBOL_TYPE ) &&
( path == 0 ) )
{
next = (*w_p)->value;
path = 2;
}
else
{
good_cue = false;
}
}
else if ( (*w_p)->attr == my_agent->epmem_sym_prev )
{
if ( ( (*w_p)->value->id.common_symbol_info.symbol_type == IDENTIFIER_SYMBOL_TYPE ) &&
( path == 0 ) )
{
previous = (*w_p)->value;
path = 2;
}
else
{
good_cue = false;
}
}
else if ( (*w_p)->attr == my_agent->epmem_sym_query )
{
if ( ( (*w_p)->value->id.common_symbol_info.symbol_type == IDENTIFIER_SYMBOL_TYPE ) &&
( ( path == 0 ) || ( path == 3 ) ) &&
( query == NULL ) )
{
query = (*w_p)->value;
path = 3;
}
else
{
good_cue = false;
}
}
else if ( (*w_p)->attr == my_agent->epmem_sym_negquery )
{
if ( ( (*w_p)->value->id.common_symbol_info.symbol_type == IDENTIFIER_SYMBOL_TYPE ) &&
( ( path == 0 ) || ( path == 3 ) ) &&
( neg_query == NULL ) )
{
neg_query = (*w_p)->value;
path = 3;
}
else
{
good_cue = false;
}
}
else if ( (*w_p)->attr == my_agent->epmem_sym_before )
{
if ( ( (*w_p)->value->ic.common_symbol_info.symbol_type == INT_CONSTANT_SYMBOL_TYPE ) &&
( ( path == 0 ) || ( path == 3 ) ) )
{
if ( ( before == EPMEM_MEMID_NONE ) || ( (*w_p)->value->ic.value < before ) )
{
before = (*w_p)->value->ic.value;
}
path = 3;
}
else
{
good_cue = false;
}
}
else if ( (*w_p)->attr == my_agent->epmem_sym_after )
{
if ( ( (*w_p)->value->ic.common_symbol_info.symbol_type == INT_CONSTANT_SYMBOL_TYPE ) &&
( ( path == 0 ) || ( path == 3 ) ) )
{
if ( after < (*w_p)->value->ic.value )
{
after = (*w_p)->value->ic.value;
}
path = 3;
}
else
{
good_cue = false;
}
}
else if ( (*w_p)->attr == my_agent->epmem_sym_prohibit )
{
if ( ( (*w_p)->value->ic.common_symbol_info.symbol_type == INT_CONSTANT_SYMBOL_TYPE ) &&
( ( path == 0 ) || ( path == 3 ) ) )
{
prohibit.push_back( (*w_p)->value->ic.value );
path = 3;
}
else
{
good_cue = false;
}
}
else if ( (*w_p)->attr == my_agent->epmem_sym_current )
{
if ( ( (*w_p)->value->ic.common_symbol_info.symbol_type == IDENTIFIER_SYMBOL_TYPE ) &&
( ( path == 0 ) || ( path == 3 ) ) )
{
currents.insert( (*w_p)->value );
path = 3;
}
else
{
good_cue = false;
}
}
else
{
good_cue = false;
}
}
}
// if on path 3 must have query
if ( ( path == 3 ) && ( query == NULL ) )
{
good_cue = false;
}
// must be on a path
if ( path == 0 )
{
good_cue = false;
}
}
void _epmem_store_level ( agent my_agent,
std::queue< Symbol * > &  parent_syms,
std::queue< epmem_node_id > &  parent_ids,
tc_number  tc,
epmem_wme_list::iterator  w_b,
epmem_wme_list::iterator  w_e,
epmem_node_id  parent_id,
epmem_time_id  time_counter,
std::map< wme *, epmem_id_reservation * > &  id_reservations,
std::set< Symbol * > &  new_identifiers,
std::queue< epmem_node_id > &  epmem_node,
std::queue< epmem_node_id > &  epmem_edge 
)
inline

Definition at line 2041 of file episodic_memory.cpp.

References _epmem_promote_id(), epmem_graph_statement_container::add_edge_unique, epmem_graph_statement_container::add_node_unique, soar_module::sqlite_statement::bind_int(), soar_module::sqlite_statement::column_int(), agent_struct::epmem_db, agent_struct::epmem_edge_maxes, agent_struct::epmem_edge_mins, agent_struct::epmem_edge_removals, EPMEM_HASH_ACCEPTABLE, agent_struct::epmem_id_ref_counts, agent_struct::epmem_id_replacement, agent_struct::epmem_id_repository, agent_struct::epmem_node_maxes, agent_struct::epmem_node_mins, agent_struct::epmem_node_removals, EPMEM_NODEID_BAD, agent_struct::epmem_params, epmem_set_variable(), agent_struct::epmem_stats, agent_struct::epmem_stmts_graph, epmem_temporal_hash(), agent_struct::epmem_validation, epmem_param_container::exclusions, soar_module::statement::execute(), epmem_graph_statement_container::find_edge_unique_shared, epmem_graph_statement_container::find_lti, epmem_graph_statement_container::find_node_unique, soar_module::primitive_stat< T >::get_value(), IDENTIFIER_SYMBOL_TYPE, soar_module::sym_set_param::in_set(), soar_module::sqlite_database::last_insert_rowid(), epmem_id_reservation_struct::my_hash, epmem_id_reservation_struct::my_id, epmem_id_reservation_struct::my_pool, epmem_stat_container::next_id, NIL, soar_module::op_reinit, soar_module::statement::reinitialize(), soar_module::row, soar_module::primitive_stat< T >::set_value(), USE_MEM_POOL_ALLOCATORS, and var_next_id.

Referenced by epmem_new_episode().

{
epmem_wme_list::iterator w_p;
bool value_known_apriori = false;
// temporal hash
epmem_hash_id my_hash; // attribute
epmem_hash_id my_hash2; // value
// id repository
epmem_id_pool **my_id_repo;
epmem_id_pool *my_id_repo2;
epmem_id_pool::iterator pool_p;
std::map<wme *, epmem_id_reservation *>::iterator r_p;
epmem_id_reservation *new_id_reservation;
// identifier recursion
epmem_wme_list* wmes = NULL;
epmem_wme_list::iterator w_p2;
bool good_recurse = false;
// find WME ID for WMEs whose value is an identifier and has a known epmem id (prevents ordering issues with unknown children)
for ( w_p=w_b; w_p!=w_e; w_p++ )
{
// skip over WMEs already in the system
if ( ( (*w_p)->epmem_id != EPMEM_NODEID_BAD ) && ( (*w_p)->epmem_valid == my_agent->epmem_validation ) )
{
continue;
}
if ( ( (*w_p)->value->common.symbol_type == IDENTIFIER_SYMBOL_TYPE ) &&
( ( (*w_p)->value->id.epmem_id != EPMEM_NODEID_BAD ) && ( (*w_p)->value->id.epmem_valid == my_agent->epmem_validation ) ) &&
( !(*w_p)->value->id.smem_lti ) )
{
// prevent exclusions from being recorded
if ( my_agent->epmem_params->exclusions->in_set( (*w_p)->attr ) )
{
continue;
}
// if still here, create reservation (case 1)
new_id_reservation = new epmem_id_reservation;
new_id_reservation->my_id = EPMEM_NODEID_BAD;
new_id_reservation->my_pool = NULL;
if ( (*w_p)->acceptable )
{
new_id_reservation->my_hash = EPMEM_HASH_ACCEPTABLE;
}
else
{
new_id_reservation->my_hash = epmem_temporal_hash( my_agent, (*w_p)->attr );
}
// try to find appropriate reservation
my_id_repo =& (*(*my_agent->epmem_id_repository)[ parent_id ])[ new_id_reservation->my_hash ];
if ( (*my_id_repo) )
{
for ( pool_p = (*my_id_repo)->begin(); pool_p != (*my_id_repo)->end(); pool_p++ )
{
if ( pool_p->first == (*w_p)->value->id.epmem_id )
{
new_id_reservation->my_id = pool_p->second;
(*my_id_repo)->erase( pool_p );
break;
}
}
}
else
{
// add repository
(*my_id_repo) = new epmem_id_pool;
}
new_id_reservation->my_pool = (*my_id_repo);
id_reservations[ (*w_p) ] = new_id_reservation;
new_id_reservation = NULL;
}
}
for ( w_p=w_b; w_p!=w_e; w_p++ )
{
// skip over WMEs already in the system
if ( ( (*w_p)->epmem_id != EPMEM_NODEID_BAD ) && ( (*w_p)->epmem_valid == my_agent->epmem_validation ) )
{
continue;
}
// prevent exclusions from being recorded
if ( my_agent->epmem_params->exclusions->in_set( (*w_p)->attr ) )
{
continue;
}
if ( (*w_p)->value->common.symbol_type == IDENTIFIER_SYMBOL_TYPE )
{
(*w_p)->epmem_valid = my_agent->epmem_validation;
(*w_p)->epmem_id = EPMEM_NODEID_BAD;
my_hash = NIL;
my_id_repo2 = NIL;
// if the value already has an epmem_id, the WME ID would have already been assigned above (ie. the epmem_id of the VALUE is KNOWN APRIORI [sic])
// however, it's also possible that the value is known but no WME ID is given (eg. (<s> ^foo <a> ^bar <a>)); this is case 2
value_known_apriori = ( ( (*w_p)->value->id.epmem_id != EPMEM_NODEID_BAD ) && ( (*w_p)->value->id.epmem_valid == my_agent->epmem_validation ) );
// if long-term identifier as value, special processing (we may need to promote, we don't add to/take from any pools)
if ( (*w_p)->value->id.smem_lti )
{
// find the lti or add new one
if ( !value_known_apriori )
{
(*w_p)->value->id.epmem_id = EPMEM_NODEID_BAD;
(*w_p)->value->id.epmem_valid = my_agent->epmem_validation;
// try to find
{
my_agent->epmem_stmts_graph->find_lti->bind_int( 1, static_cast<uint64_t>( (*w_p)->value->id.name_letter ) );
my_agent->epmem_stmts_graph->find_lti->bind_int( 2, static_cast<uint64_t>( (*w_p)->value->id.name_number ) );
{
(*w_p)->value->id.epmem_id = static_cast<epmem_node_id>( my_agent->epmem_stmts_graph->find_lti->column_int( 0 ) );
}
}
// add if necessary
if ( (*w_p)->value->id.epmem_id == EPMEM_NODEID_BAD )
{
(*w_p)->value->id.epmem_id = my_agent->epmem_stats->next_id->get_value();
my_agent->epmem_stats->next_id->set_value( (*w_p)->value->id.epmem_id + 1 );
epmem_set_variable( my_agent, var_next_id, (*w_p)->value->id.epmem_id + 1 );
// add repository
(*my_agent->epmem_id_repository)[ (*w_p)->value->id.epmem_id ] = new epmem_hashed_id_pool;
_epmem_promote_id( my_agent, (*w_p)->value, time_counter );
}
}
// now perform deliberate edge search
// ltis don't use the pools, so we make a direct search in the edge_unique table
// if failure, drop below and use standard channels
{
// get temporal hash
if ( (*w_p)->acceptable )
{
}
else
{
my_hash = epmem_temporal_hash( my_agent, (*w_p)->attr );
}
// q0, w, q1
my_agent->epmem_stmts_graph->find_edge_unique_shared->bind_int( 1, parent_id );
my_agent->epmem_stmts_graph->find_edge_unique_shared->bind_int( 3, (*w_p)->value->id.epmem_id );
{
(*w_p)->epmem_id = my_agent->epmem_stmts_graph->find_edge_unique_shared->column_int( 0 );
}
}
}
else
{
// in the case of a known value, we already have a reservation (case 1)
if ( value_known_apriori )
{
r_p = id_reservations.find( (*w_p) );
if ( r_p != id_reservations.end() )
{
// restore reservation info
my_hash = r_p->second->my_hash;
my_id_repo2 = r_p->second->my_pool;
if ( r_p->second->my_id != EPMEM_NODEID_BAD )
{
(*w_p)->epmem_id = r_p->second->my_id;
(*my_agent->epmem_id_replacement)[ (*w_p)->epmem_id ] = my_id_repo2;
}
// delete reservation and map entry
delete r_p->second;
id_reservations.erase( r_p );
}
// OR a shared identifier at the same level, in which case we need an exact match (case 2)
else
{
// get temporal hash
if ( (*w_p)->acceptable )
{
}
else
{
my_hash = epmem_temporal_hash( my_agent, (*w_p)->attr );
}
// try to get an id that matches new information
my_id_repo =& (*(*my_agent->epmem_id_repository)[ parent_id ])[ my_hash ];
if ( (*my_id_repo) )
{
if ( !(*my_id_repo)->empty() )
{
for ( pool_p = (*my_id_repo)->begin(); pool_p != (*my_id_repo)->end(); pool_p++ )
{
if ( pool_p->first == (*w_p)->value->id.epmem_id )
{
(*w_p)->epmem_id = pool_p->second;
(*my_id_repo)->erase( pool_p );
(*my_agent->epmem_id_replacement)[ (*w_p)->epmem_id ] = (*my_id_repo);
break;
}
}
}
}
else
{
// add repository
(*my_id_repo) = new epmem_id_pool;
}
// keep the address for later (used if w->epmem_id was not assigned)
my_id_repo2 = (*my_id_repo);
}
}
// case 3
else
{
// UNKNOWN identifier
new_identifiers.insert( (*w_p)->value );
// get temporal hash
if ( (*w_p)->acceptable )
{
}
else
{
my_hash = epmem_temporal_hash( my_agent, (*w_p)->attr );
}
// try to find node
my_id_repo =& (*(*my_agent->epmem_id_repository)[ parent_id ])[ my_hash ];
if ( (*my_id_repo) )
{
// if something leftover, try to use it
if ( !(*my_id_repo)->empty() )
{
for (pool_p = (*my_id_repo)->begin(); pool_p != (*my_id_repo)->end(); pool_p++)
{
if ( (*my_agent->epmem_id_ref_counts)[ pool_p->first ]->empty() )
{
(*w_p)->epmem_id = pool_p->second;
(*w_p)->value->id.epmem_id = pool_p->first;
(*w_p)->value->id.epmem_valid = my_agent->epmem_validation;
(*my_id_repo)->erase( pool_p );
(*my_agent->epmem_id_replacement)[ (*w_p)->epmem_id ] = (*my_id_repo);
break;
}
}
}
}
else
{
// add repository
(*my_id_repo) = new epmem_id_pool;
}
// keep the address for later (used if w->epmem_id was not assgined)
my_id_repo2 = (*my_id_repo);
}
}
// add wme if no success above
if ( (*w_p)->epmem_id == EPMEM_NODEID_BAD )
{
// can't use value_known_apriori, since value may have been assigned (lti, id repository via case 3)
if ( ( (*w_p)->value->id.epmem_id == EPMEM_NODEID_BAD ) || ( (*w_p)->value->id.epmem_valid != my_agent->epmem_validation ) )
{
// update next id
(*w_p)->value->id.epmem_id = my_agent->epmem_stats->next_id->get_value();
(*w_p)->value->id.epmem_valid = my_agent->epmem_validation;
my_agent->epmem_stats->next_id->set_value( (*w_p)->value->id.epmem_id + 1 );
epmem_set_variable( my_agent, var_next_id, (*w_p)->value->id.epmem_id + 1 );
// add repository for possible future children
(*my_agent->epmem_id_repository)[ (*w_p)->value->id.epmem_id ] = new epmem_hashed_id_pool;
// add ref set
(*my_agent->epmem_id_ref_counts)[ (*w_p)->value->id.epmem_id ] = new epmem_wme_set( std::less< wme* >(), soar_module::soar_memory_pool_allocator< wme* >( my_agent ) );
#else
(*my_agent->epmem_id_ref_counts)[ (*w_p)->value->id.epmem_id ] = new epmem_wme_set();
#endif
}
// insert (q0,w,q1)
my_agent->epmem_stmts_graph->add_edge_unique->bind_int( 1, parent_id );
my_agent->epmem_stmts_graph->add_edge_unique->bind_int( 2, my_hash );
my_agent->epmem_stmts_graph->add_edge_unique->bind_int( 3, (*w_p)->value->id.epmem_id );
my_agent->epmem_stmts_graph->add_edge_unique->bind_int( 4, LLONG_MAX );
(*w_p)->epmem_id = static_cast<epmem_node_id>( my_agent->epmem_db->last_insert_rowid() );
if ( !(*w_p)->value->id.smem_lti )
{
// replace the epmem_id and wme id in the right place
(*my_agent->epmem_id_replacement)[ (*w_p)->epmem_id ] = my_id_repo2;
}
// new nodes definitely start
epmem_edge.push( (*w_p)->epmem_id );
my_agent->epmem_edge_mins->push_back( time_counter );
my_agent->epmem_edge_maxes->push_back( false );
}
else
{
// definitely don't remove
(*my_agent->epmem_edge_removals)[ (*w_p)->epmem_id ] = false;
// we add ONLY if the last thing we did was remove
if ( (*my_agent->epmem_edge_maxes)[ (*w_p)->epmem_id - 1 ] )
{
epmem_edge.push( (*w_p)->epmem_id );
(*my_agent->epmem_edge_maxes)[ (*w_p)->epmem_id - 1 ] = false;
}
}
// at this point we have successfully added a new wme
// whose value is an identifier. IF the value was
// unknown at the beginning of this episode, then we need
// to update its ref count for each WME added (thereby catching
// up with ref counts that would have been accumulated via wme adds)
if ( new_identifiers.find( (*w_p)->value ) != new_identifiers.end() )
{
(*my_agent->epmem_id_ref_counts)[ (*w_p)->value->id.epmem_id ]->insert( (*w_p) );
}
// if the value has not been iterated over, continue to augmentations
if ( (*w_p)->value->id.tc_num != tc )
{
parent_syms.push( (*w_p)->value );
parent_ids.push( (*w_p)->value->id.epmem_id );
}
}
else
{
// have we seen this node in this database?
if ( ( (*w_p)->epmem_id == EPMEM_NODEID_BAD ) || ( (*w_p)->epmem_valid != my_agent->epmem_validation ) )
{
(*w_p)->epmem_id = EPMEM_NODEID_BAD;
(*w_p)->epmem_valid = my_agent->epmem_validation;
my_hash = epmem_temporal_hash( my_agent, (*w_p)->attr );
my_hash2 = epmem_temporal_hash( my_agent, (*w_p)->value );
// try to get node id
{
// parent_id=? AND attr=? AND value=?
my_agent->epmem_stmts_graph->find_node_unique->bind_int( 1, parent_id );
my_agent->epmem_stmts_graph->find_node_unique->bind_int( 2, my_hash );
my_agent->epmem_stmts_graph->find_node_unique->bind_int( 3, my_hash2 );
{
(*w_p)->epmem_id = my_agent->epmem_stmts_graph->find_node_unique->column_int( 0 );
}
}
// act depending on new/existing feature
if ( (*w_p)->epmem_id == EPMEM_NODEID_BAD )
{
// insert (parent_id,attr,value)
my_agent->epmem_stmts_graph->add_node_unique->bind_int( 1, parent_id );
my_agent->epmem_stmts_graph->add_node_unique->bind_int( 2, my_hash );
my_agent->epmem_stmts_graph->add_node_unique->bind_int( 3, my_hash2 );
(*w_p)->epmem_id = (epmem_node_id) my_agent->epmem_db->last_insert_rowid();
// new nodes definitely start
epmem_node.push( (*w_p)->epmem_id );
my_agent->epmem_node_mins->push_back( time_counter );
my_agent->epmem_node_maxes->push_back( false );
}
else
{
// definitely don't remove
(*my_agent->epmem_node_removals)[ (*w_p)->epmem_id ] = false;
// add ONLY if the last thing we did was add
if ( (*my_agent->epmem_node_maxes)[ (*w_p)->epmem_id - 1 ] )
{
epmem_node.push( (*w_p)->epmem_id );
(*my_agent->epmem_node_maxes)[ (*w_p)->epmem_id - 1 ] = false;
}
}
}
}
}
}
bool epmem_backup_db ( agent my_agent,
const char *  file_name,
std::string *  err 
)
void epmem_buffer_add_wme ( soar_module::symbol_triple_list my_list,
Symbol id,
Symbol attr,
Symbol value 
)
inline

Definition at line 994 of file episodic_memory.cpp.

References symbol_add_ref().

Referenced by _epmem_install_id_wme(), epmem_install_memory(), epmem_process_query(), and epmem_respond_to_cmd().

{
my_list.push_back( new soar_module::symbol_triple( id, attr, value ) );
symbol_add_ref( attr );
symbol_add_ref( value );
}
epmem_literal* epmem_build_dnf ( wme cue_wme,
epmem_wme_literal_map literal_cache,
epmem_literal_set leaf_literals,
epmem_symbol_int_map symbol_num_incoming,
epmem_literal_deque gm_ordering,
epmem_symbol_set currents,
int  query_type,
std::set< Symbol * > &  visiting,
soar_module::wme_set cue_wmes,
agent my_agent 
)

Definition at line 3413 of file episodic_memory.cpp.

References wme_struct::attr, epmem_param_container::balance, soar_module::sqlite_statement::bind_int(), epmem_literal_struct::children, soar_module::sqlite_statement::column_int(), epmem_get_augs_of_id(), agent_struct::epmem_literal_pool, EPMEM_NODEID_BAD, agent_struct::epmem_params, EPMEM_RIT_STATE_EDGE, EPMEM_RIT_STATE_NODE, agent_struct::epmem_stmts_graph, epmem_temporal_hash(), soar_module::statement::execute(), epmem_graph_statement_container::find_lti, get_new_tc_number(), soar_module::primitive_param< T >::get_value(), wme_struct::id, symbol_union::id, epmem_literal_struct::id_sym, IDENTIFIER_SYMBOL_TYPE, epmem_literal_struct::is_current, epmem_literal_struct::is_leaf, epmem_literal_struct::is_neg_q, epmem_literal_struct::matches, identifier_struct::name_letter, identifier_struct::name_number, epmem_literal_struct::parents, epmem_literal_struct::q1, soar_module::statement::reinitialize(), soar_module::row, identifier_struct::smem_lti, wme_struct::value, epmem_literal_struct::value_is_id, epmem_literal_struct::value_sym, epmem_literal_struct::values, epmem_literal_struct::w, epmem_literal_struct::weight, and wma_get_wme_activation().

Referenced by epmem_process_query().

{
// if the value is being visited, this is part of a loop; return NULL
// remove this check (and in fact, the entire visiting parameter) if cyclic cues are allowed
if (visiting.count(cue_wme->value)) {
return NULL;
}
// if the value is an identifier and we've been here before, we can return the previous literal
if (literal_cache.count(cue_wme)) {
return literal_cache[cue_wme];
}
cue_wmes.insert(cue_wme);
Symbol* value = cue_wme->value;
epmem_literal* literal;
allocate_with_pool(my_agent, &(my_agent->epmem_literal_pool), &literal);
new(&(literal->parents)) epmem_literal_set();
new(&(literal->children)) epmem_literal_set();
if (value->common.symbol_type != IDENTIFIER_SYMBOL_TYPE) { // WME is a value
literal->is_leaf = true;
literal->q1 = epmem_temporal_hash(my_agent, value);
leaf_literals.insert(literal);
} else if (value->id.smem_lti) { // WME is an LTI
// if we can find the LTI node id, cache it; otherwise, return failure
my_agent->epmem_stmts_graph->find_lti->bind_int(1, static_cast<uint64_t>(value->id.name_letter));
my_agent->epmem_stmts_graph->find_lti->bind_int(2, static_cast<uint64_t>(value->id.name_number));
literal->is_leaf = true;
literal->q1 = my_agent->epmem_stmts_graph->find_lti->column_int(0);
leaf_literals.insert(literal);
} else {
literal->parents.~epmem_literal_set();
literal->children.~epmem_literal_set();
free_with_pool(&(my_agent->epmem_literal_pool), literal);
return NULL;
}
} else { // WME is a normal identifier
// we determine whether it is a leaf by checking for children
epmem_wme_list* children = epmem_get_augs_of_id(value, get_new_tc_number(my_agent));
literal->q1 = EPMEM_NODEID_BAD;
// if the WME has no children, then it's a leaf
// otherwise, we recurse for all children
if (children->empty()) {
literal->is_leaf = true;
leaf_literals.insert(literal);
delete children;
} else {
bool cycle = false;
visiting.insert(cue_wme->value);
for (epmem_wme_list::iterator wme_iter = children->begin(); wme_iter != children->end(); wme_iter++) {
// check to see if this child forms a cycle
// if it does, we skip over it
epmem_literal* child = epmem_build_dnf(*wme_iter, literal_cache, leaf_literals, symbol_num_incoming, gm_ordering, currents, query_type, visiting, cue_wmes, my_agent);
if (child) {
child->parents.insert(literal);
literal->children.insert(child);
} else {
cycle = true;
}
}
delete children;
visiting.erase(cue_wme->value);
// if all children of this WME lead to cycles, then we don't need to walk this path
// in essence, this forces the DNF graph to be acyclic
// this results in savings in not walking edges and intervals
if (cycle && literal->children.empty()) {
literal->parents.~epmem_literal_set();
literal->children.~epmem_literal_set();
free_with_pool(&(my_agent->epmem_literal_pool), literal);
return NULL;
}
literal->is_leaf = false;
epmem_symbol_int_map::iterator rem_iter = symbol_num_incoming.find(value);
if (rem_iter == symbol_num_incoming.end()) {
symbol_num_incoming[value] = 1;
} else {
(*rem_iter).second++;
}
}
}
if (!query_type) {
gm_ordering.push_front(literal);
}
literal->id_sym = cue_wme->id;
literal->value_sym = cue_wme->value;
literal->is_current = (currents.count(value) > 0);
literal->w = epmem_temporal_hash(my_agent, cue_wme->attr);
literal->is_neg_q = query_type;
literal->weight = (literal->is_neg_q ? -1 : 1) * (my_agent->epmem_params->balance->get_value() >= 1.0 - 1.0e-8 ? 1.0 : wma_get_wme_activation(my_agent, cue_wme, true));
#ifdef USE_MEM_POOL_ALLOCATORS
new(&(literal->matches)) epmem_node_pair_set(std::less<epmem_node_pair>(), soar_module::soar_memory_pool_allocator<epmem_node_pair>(my_agent));
#else
new(&(literal->matches)) epmem_node_pair_set();
#endif
new(&(literal->values)) epmem_node_int_map();
literal_cache[cue_wme] = literal;
return literal;
}
void epmem_clear_result ( agent my_agent,
Symbol state 
)

Definition at line 1445 of file episodic_memory.cpp.

References identifier_struct::epmem_info, epmem_data_struct::epmem_wmes, symbol_union::id, preference_struct::in_tm, and remove_preference_from_tm().

Referenced by epmem_respond_to_cmd().

{
preference *pref;
while ( !state->id.epmem_info->epmem_wmes->empty() )
{
pref = state->id.epmem_info->epmem_wmes->back();
state->id.epmem_info->epmem_wmes->pop_back();
if ( pref->in_tm )
{
remove_preference_from_tm( my_agent, pref );
}
}
}
void epmem_close ( agent my_agent)

Definition at line 1340 of file episodic_memory.cpp.

References epmem_common_statement_container::commit, soar_module::connected, soar_module::sqlite_database::disconnect(), agent_struct::epmem_db, agent_struct::epmem_id_ref_counts, agent_struct::epmem_id_replacement, agent_struct::epmem_id_repository, agent_struct::epmem_params, agent_struct::epmem_promotions, EPMEM_RANGE_END, EPMEM_RANGE_EP, EPMEM_RANGE_POINT, EPMEM_RANGE_START, EPMEM_RIT_STATE_EDGE, EPMEM_RIT_STATE_NODE, agent_struct::epmem_stmts_common, agent_struct::epmem_stmts_graph, agent_struct::epmem_wme_adds, soar_module::statement::execute(), soar_module::status_object< T >::get_status(), soar_module::constant_param< T >::get_value(), epmem_param_container::lazy_commit, soar_module::on, soar_module::op_reinit, epmem_graph_statement_container::pool_dummy, epmem_graph_statement_container::pool_find_edge_queries, epmem_graph_statement_container::pool_find_interval_queries, epmem_graph_statement_container::pool_find_lti_queries, and symbol_remove_ref().

Referenced by destroy_soar_agent().

{
{
// if lazy, commit
{
}
// de-allocate statement pools
{
int j, k, m;
{
for ( k=0; k<=1; k++ )
{
delete my_agent->epmem_stmts_graph->pool_find_edge_queries[ j ][ k ];
}
}
{
{
{
delete my_agent->epmem_stmts_graph->pool_find_interval_queries[ j ][ k ][ m ];
}
}
}
{
{
delete my_agent->epmem_stmts_graph->pool_find_lti_queries[ k ][ m ];
}
}
delete my_agent->epmem_stmts_graph->pool_dummy;
}
// de-allocate statements
delete my_agent->epmem_stmts_common;
delete my_agent->epmem_stmts_graph;
// de-allocate local data structures
{
epmem_parent_id_pool::iterator p;
epmem_hashed_id_pool::iterator p_p;
for ( p=my_agent->epmem_id_repository->begin(); p!=my_agent->epmem_id_repository->end(); p++ )
{
for ( p_p=p->second->begin(); p_p!=p->second->end(); p_p++ )
{
delete p_p->second;
}
delete p->second;
}
my_agent->epmem_id_repository->clear();
my_agent->epmem_id_replacement->clear();
for ( epmem_id_ref_counter::iterator rf_it=my_agent->epmem_id_ref_counts->begin(); rf_it!=my_agent->epmem_id_ref_counts->end(); rf_it++ )
{
delete rf_it->second;
}
my_agent->epmem_id_ref_counts->clear();
my_agent->epmem_wme_adds->clear();
for ( epmem_symbol_set::iterator p_it=my_agent->epmem_promotions->begin(); p_it!=my_agent->epmem_promotions->end(); p_it++ )
{
symbol_remove_ref( my_agent, (*p_it) );
}
my_agent->epmem_promotions->clear();
}
// close the database
my_agent->epmem_db->disconnect();
}
#ifdef EPMEM_EXPERIMENT
if ( epmem_exp_output )
{
epmem_exp_output->close();
delete epmem_exp_output;
epmem_exp_output = NULL;
if ( epmem_exp_timer )
{
delete epmem_exp_timer;
}
}
#endif
}
bool epmem_consider_new_episode ( agent my_agent)

Definition at line 4980 of file episodic_memory.cpp.

References epmem_param_container::dc, identifier_struct::epmem_info, epmem_new_episode(), agent_struct::epmem_params, agent_struct::epmem_timers, epmem_param_container::force, epmem_param_container::force_off, soar_module::constant_param< T >::get_value(), symbol_union::id, agent_struct::io_header_output, epmem_data_struct::last_ol_time, wme_struct::next, slot_struct::next, NIL, epmem_param_container::none, epmem_param_container::output, epmem_param_container::remember, soar_module::constant_param< T >::set_value(), identifier_struct::slots, soar_module::timer::start(), soar_module::timer::stop(), wme_struct::timetag, agent_struct::top_goal, epmem_param_container::trigger, epmem_timer_container::trigger, and slot_struct::wmes.

Referenced by epmem_go().

{
my_agent->epmem_timers->trigger->start();
const int64_t force = my_agent->epmem_params->force->get_value();
bool new_memory = false;
{
const int64_t trigger = my_agent->epmem_params->trigger->get_value();
{
slot *s;
wme *w;
Symbol *ol = my_agent->io_header_output;
// examine all commands on the output-link for any
// that appeared since last memory was recorded
for ( s = ol->id.slots; s != NIL; s = s->next )
{
for ( w = s->wmes; w != NIL; w = w->next )
{
if ( w->timetag > my_agent->top_goal->id.epmem_info->last_ol_time )
{
new_memory = true;
}
}
}
}
else if ( trigger == epmem_param_container::dc )
{
new_memory = true;
}
else if ( trigger == epmem_param_container::none )
{
new_memory = false;
}
}
else
{
new_memory = ( force == epmem_param_container::remember );
}
my_agent->epmem_timers->trigger->stop();
if ( new_memory )
{
epmem_new_episode( my_agent );
}
return new_memory;
}
bool epmem_enabled ( agent my_agent)
epmem_wme_list* epmem_get_augs_of_id ( Symbol id,
tc_number  tc 
)

Definition at line 866 of file episodic_memory.cpp.

References slot_struct::acceptable_preference_wmes, symbol_union::id, IDENTIFIER_SYMBOL_TYPE, identifier_struct::impasse_wmes, identifier_struct::input_wmes, wme_struct::next, slot_struct::next, NIL, identifier_struct::slots, identifier_struct::tc_num, and slot_struct::wmes.

Referenced by epmem_build_dnf(), epmem_new_episode(), epmem_process_query(), and epmem_respond_to_cmd().

{
slot *s;
wme *w;
epmem_wme_list *return_val = new epmem_wme_list;
// augs only exist for identifiers
if ( ( id->common.symbol_type == IDENTIFIER_SYMBOL_TYPE ) &&
( id->id.tc_num != tc ) )
{
id->id.tc_num = tc;
// impasse wmes
for ( w=id->id.impasse_wmes; w!=NIL; w=w->next )
{
return_val->push_back( w );
}
// input wmes
for ( w=id->id.input_wmes; w!=NIL; w=w->next )
{
return_val->push_back( w );
}
// regular wmes
for ( s=id->id.slots; s!=NIL; s=s->next )
{
for ( w=s->wmes; w!=NIL; w=w->next )
{
return_val->push_back( w );
}
for ( w=s->acceptable_preference_wmes; w!=NIL; w=w->next )
{
return_val->push_back( w );
}
}
}
return return_val;
}
bool epmem_get_variable ( agent my_agent,
epmem_variable_key  variable_id,
int64_t *  variable_value 
)
bool epmem_gm_mcv_comparator ( const epmem_literal a,
const epmem_literal b 
)

Definition at line 3409 of file episodic_memory.cpp.

References epmem_literal_struct::matches.

Referenced by epmem_process_query().

{
return (a->matches.size() < b->matches.size());
}
void epmem_go ( agent my_agent,
bool  allow_store 
)

Definition at line 5853 of file episodic_memory.cpp.

References epmem_consider_new_episode(), epmem_respond_to_cmd(), agent_struct::epmem_timers, soar_module::timer::start(), soar_module::timer::stop(), and epmem_timer_container::total.

Referenced by do_one_top_level_phase().

{
my_agent->epmem_timers->total->start();
#ifndef EPMEM_EXPERIMENT
if ( allow_store )
{
}
epmem_respond_to_cmd( my_agent );
#else // EPMEM_EXPERIMENT
_epmem_exp( my_agent );
epmem_respond_to_cmd( my_agent );
#endif // EPMEM_EXPERIMENT
my_agent->epmem_timers->total->stop();
}
bool epmem_graph_match ( epmem_literal_deque::iterator &  dnf_iter,
epmem_literal_deque::iterator &  iter_end,
epmem_literal_node_pair_map bindings,
epmem_node_symbol_map  bound_nodes[],
agent my_agent,
int  depth = 0 
)

Definition at line 3734 of file episodic_memory.cpp.

References epmem_literal_struct::children, EPMEM_NODEID_BAD, epmem_literal_struct::matches, epmem_literal_struct::parents, epmem_literal_struct::q1, QUERY_DEBUG, epmem_literal_struct::value_is_id, and epmem_literal_struct::value_sym.

Referenced by epmem_process_query().

{
if (dnf_iter == iter_end) {
return true;
}
epmem_literal* literal = *dnf_iter;
if (bindings.count(literal)) {
return false;
}
epmem_literal_deque::iterator next_iter = dnf_iter;
next_iter++;
#ifdef USE_MEM_POOL_ALLOCATORS
epmem_node_set failed_parents = epmem_node_set(std::less<epmem_node_id>(), soar_module::soar_memory_pool_allocator<epmem_node_id>(my_agent));
epmem_node_set failed_children = epmem_node_set(std::less<epmem_node_id>(), soar_module::soar_memory_pool_allocator<epmem_node_id>(my_agent));
#else
epmem_node_set failed_parents;
epmem_node_set failed_children;
#endif
// go through the list of matches, binding each one to this literal in turn
for (epmem_node_pair_set::iterator match_iter = literal->matches.begin(); match_iter != literal->matches.end(); match_iter++) {
epmem_node_id q0 = (*match_iter).first;
epmem_node_id q1 = (*match_iter).second;
if (failed_parents.count(q0)) {
continue;
}
if (QUERY_DEBUG >= 2) {
for (int i = 0; i < depth; i++) {
std::cout << "\t";
}
std::cout << "TRYING " << literal << " " << q0 << std::endl;
}
bool relations_okay = true;
// for all parents
for (epmem_literal_set::iterator parent_iter = literal->parents.begin(); relations_okay && parent_iter != literal->parents.end(); parent_iter++) {
epmem_literal* parent = *parent_iter;
epmem_literal_node_pair_map::iterator bind_iter = bindings.find(parent);
if (bind_iter != bindings.end() && (*bind_iter).second.second != q0) {
relations_okay = false;
}
}
if (!relations_okay) {
if (QUERY_DEBUG >= 2) {
for (int i = 0; i < depth; i++) {
std::cout << "\t";
}
std::cout << "PARENT CONSTRAINT FAIL" << std::endl;
}
failed_parents.insert(q0);
continue;
}
// if the node has already been bound, make sure it's bound to the same thing
epmem_node_symbol_map::iterator binder = bound_nodes[literal->value_is_id].find(q1);
if (binder != bound_nodes[literal->value_is_id].end() && (*binder).second != literal->value_sym) {
failed_children.insert(q1);
continue;
}
if (QUERY_DEBUG >= 2) {
for (int i = 0; i < depth; i++) {
std::cout << "\t";
}
std::cout << "TRYING " << literal << " " << q0 << " " << q1 << std::endl;
}
if (literal->q1 != EPMEM_NODEID_BAD && literal->q1 != q1) {
relations_okay = false;
}
// for all children
for (epmem_literal_set::iterator child_iter = literal->children.begin(); relations_okay && child_iter != literal->children.end(); child_iter++) {
epmem_literal* child = *child_iter;
epmem_literal_node_pair_map::iterator bind_iter = bindings.find(child);
if (bind_iter != bindings.end() && (*bind_iter).second.first != q1) {
relations_okay = false;
}
}
if (!relations_okay) {
if (QUERY_DEBUG >= 2) {
for (int i = 0; i < depth; i++) {
std::cout << "\t";
}
std::cout << "CHILD CONSTRAINT FAIL" << std::endl;
}
failed_children.insert(q1);
continue;
}
if (QUERY_DEBUG >= 2) {
for (int i = 0; i < depth; i++) {
std::cout << "\t";
}
std::cout << literal << " " << q0 << " " << q1 << std::endl;
}
// temporarily modify the bindings and bound nodes
bindings[literal] = std::make_pair(q0, q1);
bound_nodes[literal->value_is_id][q1] = literal->value_sym;
// recurse on the rest of the list
bool list_satisfied = epmem_graph_match(next_iter, iter_end, bindings, bound_nodes, my_agent, depth + 1);
// if the rest of the list matched, we've succeeded
// otherwise, undo the temporarily modifications and try again
if (list_satisfied) {
return true;
} else {
bindings.erase(literal);
bound_nodes[literal->value_is_id].erase(q1);
}
}
// this means we've tried everything and this whole exercise was a waste of time
// EPIC FAIL
if (QUERY_DEBUG >= 2) {
for (int i = 0; i < depth; i++) {
std::cout << "\t";
}
std::cout << "EPIC FAIL" << std::endl;
}
return false;
}
void epmem_init_db ( agent my_agent,
bool  readonly = false 
)

Definition at line 1509 of file episodic_memory.cpp.

References epmem_graph_statement_container::add_edge_point, epmem_graph_statement_container::add_edge_range, epmem_graph_statement_container::add_node_point, epmem_graph_statement_container::add_node_range, epmem_rit_state_struct::add_query, epmem_common_statement_container::begin, soar_module::sqlite_statement::bind_int(), epmem_param_container::cache_size, soar_module::sqlite_statement::column_int(), soar_module::sqlite_statement::column_type(), soar_module::sqlite_database::connect(), epmem_param_container::database, soar_module::disconnected, agent_struct::epmem_db, agent_struct::epmem_edge_maxes, agent_struct::epmem_edge_mins, agent_struct::epmem_edge_removals, epmem_get_variable(), identifier_struct::epmem_id, agent_struct::epmem_id_ref_counts, agent_struct::epmem_id_repository, agent_struct::epmem_node_maxes, agent_struct::epmem_node_mins, agent_struct::epmem_node_removals, EPMEM_NODEID_ROOT, agent_struct::epmem_params, epmem_rit_insert_interval(), EPMEM_RIT_OFFSET_INIT, EPMEM_RIT_STATE_EDGE, agent_struct::epmem_rit_state_graph, EPMEM_RIT_STATE_NODE, epmem_set_variable(), agent_struct::epmem_stats, agent_struct::epmem_stmts_common, agent_struct::epmem_stmts_graph, agent_struct::epmem_timers, identifier_struct::epmem_valid, agent_struct::epmem_validation, agent_struct::epmem_wme_adds, soar_module::statement::execute(), soar_module::status_object< T >::get_errmsg(), soar_module::status_object< T >::get_status(), soar_module::primitive_param< T >::get_string(), soar_module::string_param::get_value(), soar_module::constant_param< T >::get_value(), soar_module::primitive_stat< T >::get_value(), symbol_union::id, epmem_timer_container::init, epmem_param_container::lazy_commit, epmem_rit_state_struct::leftroot, epmem_param_container::memory, epmem_rit_state_struct::minstep, epmem_stat_container::next_id, NIL, soar_module::null_t, epmem_rit_state_struct::offset, soar_module::on, soar_module::op_reinit, epmem_param_container::opt, epmem_param_container::opt_speed, epmem_param_container::page_16k, epmem_param_container::page_1k, epmem_param_container::page_2k, epmem_param_container::page_32k, epmem_param_container::page_4k, epmem_param_container::page_64k, epmem_param_container::page_8k, epmem_param_container::page_size, epmem_param_container::path, soar_module::statement::prepare(), soar_module::statement_container::prepare(), print(), soar_module::problem, epmem_rit_state_struct::rightroot, soar_module::row, soar_module::primitive_stat< T >::set_value(), soar_module::timer::start(), epmem_rit_state_param_struct::stat, soar_module::timer::stop(), soar_module::sqlite_statement_container::structure(), epmem_stat_container::time, agent_struct::top_goal, agent_struct::top_state, epmem_graph_statement_container::update_edge_unique_last, epmem_rit_state_param_struct::var_key, var_next_id, and xml_generate_warning().

Referenced by epmem_new_episode(), epmem_print_episode(), epmem_respond_to_cmd(), and epmem_visualize_episode().

{
{
return;
}
my_agent->epmem_timers->init->start();
const char *db_path;
{
db_path = ":memory:";
}
else
{
db_path = my_agent->epmem_params->path->get_value();
}
// attempt connection
my_agent->epmem_db->connect( db_path );
if ( my_agent->epmem_db->get_status() == soar_module::problem )
{
char buf[256];
SNPRINTF( buf, 254, "DB ERROR: %s", my_agent->epmem_db->get_errmsg() );
print( my_agent, buf );
xml_generate_warning( my_agent, buf );
}
else
{
epmem_time_id time_max;
// apply performance options
{
// page_size
{
switch ( my_agent->epmem_params->page_size->get_value() )
{
temp_q = new soar_module::sqlite_statement( my_agent->epmem_db, "PRAGMA page_size = 1024" );
break;
temp_q = new soar_module::sqlite_statement( my_agent->epmem_db, "PRAGMA page_size = 2048" );
break;
temp_q = new soar_module::sqlite_statement( my_agent->epmem_db, "PRAGMA page_size = 4096" );
break;
temp_q = new soar_module::sqlite_statement( my_agent->epmem_db, "PRAGMA page_size = 8192" );
break;
temp_q = new soar_module::sqlite_statement( my_agent->epmem_db, "PRAGMA page_size = 16384" );
break;
temp_q = new soar_module::sqlite_statement( my_agent->epmem_db, "PRAGMA page_size = 32768" );
break;
temp_q = new soar_module::sqlite_statement( my_agent->epmem_db, "PRAGMA page_size = 65536" );
break;
}
temp_q->prepare();
temp_q->execute();
delete temp_q;
temp_q = NULL;
}
// cache_size
{
std::string cache_sql( "PRAGMA cache_size = " );
char* str = my_agent->epmem_params->cache_size->get_string();
cache_sql.append( str );
free(str);
str = NULL;
temp_q = new soar_module::sqlite_statement( my_agent->epmem_db, cache_sql.c_str() );
temp_q->prepare();
temp_q->execute();
delete temp_q;
temp_q = NULL;
}
// optimization
{
// synchronous - don't wait for writes to complete (can corrupt the db in case unexpected crash during transaction)
temp_q = new soar_module::sqlite_statement( my_agent->epmem_db, "PRAGMA synchronous = OFF" );
temp_q->prepare();
temp_q->execute();
delete temp_q;
temp_q = NULL;
// journal_mode - no atomic transactions (can result in database corruption if crash during transaction)
temp_q = new soar_module::sqlite_statement( my_agent->epmem_db, "PRAGMA journal_mode = OFF" );
temp_q->prepare();
temp_q->execute();
delete temp_q;
temp_q = NULL;
// locking_mode - no one else can view the database after our first write
temp_q = new soar_module::sqlite_statement( my_agent->epmem_db, "PRAGMA locking_mode = EXCLUSIVE" );
temp_q->prepare();
temp_q->execute();
delete temp_q;
temp_q = NULL;
}
}
// point stuff
epmem_time_id range_start;
epmem_time_id time_last;
// update validation count
my_agent->epmem_validation++;
// setup common structures/queries
{
// setup graph structures/queries
my_agent->epmem_stmts_graph->prepare();
// initialize range tracking
my_agent->epmem_node_mins->clear();
my_agent->epmem_node_maxes->clear();
my_agent->epmem_node_removals->clear();
my_agent->epmem_edge_mins->clear();
my_agent->epmem_edge_maxes->clear();
my_agent->epmem_edge_removals->clear();
{
#ifdef USE_MEM_POOL_ALLOCATORS
epmem_wme_set* wms_temp = new epmem_wme_set( std::less< wme* >(), soar_module::soar_memory_pool_allocator< wme* >( my_agent ) );
#else
epmem_wme_set* wms_temp = new epmem_wme_set();
#endif
// voigtjr: Cast to wme* is necessary for compilation in VS10
// Without it, it picks insert(int) instead of insert(wme*) and does not compile.
wms_temp->insert( static_cast<wme*>(NULL) );
(*my_agent->epmem_id_ref_counts)[ EPMEM_NODEID_ROOT ] = wms_temp;
}
// initialize time
my_agent->epmem_stats->time->set_value( 1 );
// initialize next_id
my_agent->epmem_stats->next_id->set_value( 1 );
{
int64_t stored_id = NIL;
if ( epmem_get_variable( my_agent, var_next_id, &stored_id ) )
{
my_agent->epmem_stats->next_id->set_value( stored_id );
}
else
{
}
}
// initialize rit state
{
my_agent->epmem_rit_state_graph[ i ].minstep.stat->set_value( LONG_MAX );
}
// get/set RIT variables
{
int64_t var_val = NIL;
{
// offset
if ( epmem_get_variable( my_agent, my_agent->epmem_rit_state_graph[ i ].offset.var_key, &var_val ) )
{
my_agent->epmem_rit_state_graph[ i ].offset.stat->set_value( var_val );
}
else
{
}
// leftroot
if ( epmem_get_variable( my_agent, my_agent->epmem_rit_state_graph[ i ].leftroot.var_key, &var_val ) )
{
my_agent->epmem_rit_state_graph[ i ].leftroot.stat->set_value( var_val );
}
else
{
}
// rightroot
if ( epmem_get_variable( my_agent, my_agent->epmem_rit_state_graph[ i ].rightroot.var_key, &var_val ) )
{
my_agent->epmem_rit_state_graph[ i ].rightroot.stat->set_value( var_val );
}
else
{
}
// minstep
if ( epmem_get_variable( my_agent, my_agent->epmem_rit_state_graph[ i ].minstep.var_key, &var_val ) )
{
my_agent->epmem_rit_state_graph[ i ].minstep.stat->set_value( var_val );
}
else
{
}
}
}
// get max time
{
temp_q = new soar_module::sqlite_statement( my_agent->epmem_db, "SELECT MAX(id) FROM times" );
temp_q->prepare();
if ( temp_q->execute() == soar_module::row )
my_agent->epmem_stats->time->set_value( temp_q->column_int( 0 ) + 1 );
delete temp_q;
temp_q = NULL;
}
time_max = my_agent->epmem_stats->time->get_value();
// insert non-NOW intervals for all current NOW's
// remove NOW's
if ( !readonly )
{
time_last = ( time_max - 1 );
const char *now_select[] = { "SELECT id,start FROM node_now", "SELECT id,start FROM edge_now" };
const char *now_delete[] = { "DELETE FROM node_now", "DELETE FROM edge_now" };
{
temp_q = now_add[i];
temp_q->bind_int( 2, time_last );
temp_q2 = new soar_module::sqlite_statement( my_agent->epmem_db, now_select[i] );
temp_q2->prepare();
while ( temp_q2->execute() == soar_module::row )
{
range_start = temp_q2->column_int( 1 );
// point
if ( range_start == time_last )
{
temp_q->bind_int( 1, temp_q2->column_int( 0 ) );
}
else
{
epmem_rit_insert_interval( my_agent, range_start, time_last, temp_q2->column_int( 0 ), &( my_agent->epmem_rit_state_graph[i] ) );
}
{
my_agent->epmem_stmts_graph->update_edge_unique_last->bind_int( 1, time_last );
}
}
delete temp_q2;
temp_q2 = NULL;
temp_q = NULL;
// remove all NOW intervals
temp_q = new soar_module::sqlite_statement( my_agent->epmem_db, now_delete[i] );
temp_q->prepare();
temp_q->execute();
delete temp_q;
temp_q = NULL;
}
}
// get max id + max list
{
const char *minmax_select[] = { "SELECT MAX(child_id) FROM node_unique", "SELECT MAX(parent_id) FROM edge_unique" };
std::vector<bool> *minmax_max[] = { my_agent->epmem_node_maxes, my_agent->epmem_edge_maxes };
std::vector<epmem_time_id> *minmax_min[] = { my_agent->epmem_node_mins, my_agent->epmem_edge_mins };
{
temp_q = new soar_module::sqlite_statement( my_agent->epmem_db, minmax_select[i] );
temp_q->prepare();
temp_q->execute();
if ( temp_q->column_type( 0 ) != soar_module::null_t )
{
std::vector<bool>::size_type num_ids = temp_q->column_int( 0 );
minmax_max[i]->resize( num_ids, true );
minmax_min[i]->resize( num_ids, time_max );
}
delete temp_q;
temp_q = NULL;
}
}
// get id pools
{
int64_t w;
epmem_node_id parent_id;
temp_q = new soar_module::sqlite_statement( my_agent->epmem_db, "SELECT q0, w, q1, parent_id FROM edge_unique" );
temp_q->prepare();
while ( temp_q->execute() == soar_module::row )
{
q0 = temp_q->column_int( 0 );
w = temp_q->column_int( 1 );
q1 = temp_q->column_int( 2 );
parent_id = temp_q->column_int( 3 );
hp =& (*my_agent->epmem_id_repository)[ q0 ];
if ( !(*hp) )
(*hp) = new epmem_hashed_id_pool;
ip =& (*(*hp))[ w ];
if ( !(*ip) )
(*ip) = new epmem_id_pool;
(*ip)->push_front( std::make_pair( q1, parent_id ) );
hp =& (*my_agent->epmem_id_repository)[ q1 ];
if ( !(*hp) )
(*hp) = new epmem_hashed_id_pool;
}
delete temp_q;
temp_q = NULL;
}
// at init, top-state is considered the only known identifier
my_agent->top_goal->id.epmem_valid = my_agent->epmem_validation;
// capture augmentations of top-state as the sole set of adds,
// which catches up to what would have been incremental encoding
// to this point
{
my_agent->epmem_wme_adds->insert( my_agent->top_state );
}
}
// if lazy commit, then we encapsulate the entire lifetime of the agent in a single transaction
{
}
}
my_agent->epmem_timers->init->stop();
}
void epmem_install_memory ( agent my_agent,
Symbol state,
epmem_time_id  memory_id,
soar_module::symbol_triple_list meta_wmes,
soar_module::symbol_triple_list retrieval_wmes,
epmem_id_mapping id_record = NULL 
)

Definition at line 2829 of file episodic_memory.cpp.

References _epmem_install_id_wme(), epmem_buffer_add_wme(), identifier_struct::epmem_info, EPMEM_MEMID_NONE, EPMEM_NODEID_ROOT, agent_struct::epmem_params, identifier_struct::epmem_result_header, epmem_rit_clear_left_right(), epmem_rit_prep_left_right(), EPMEM_RIT_STATE_EDGE, agent_struct::epmem_rit_state_graph, EPMEM_RIT_STATE_NODE, agent_struct::epmem_stats, agent_struct::epmem_stmts_graph, agent_struct::epmem_sym_memory_id, agent_struct::epmem_sym_no_memory, agent_struct::epmem_sym_present_id, agent_struct::epmem_sym_retrieved, agent_struct::epmem_timers, epmem_valid_episode(), FLOAT_CONSTANT_SYMBOL_TYPE, epmem_graph_statement_container::get_edges, epmem_graph_statement_container::get_nodes, soar_module::constant_param< T >::get_value(), soar_module::primitive_stat< T >::get_value(), symbol_union::id, INT_CONSTANT_SYMBOL_TYPE, epmem_data_struct::last_memory, identifier_struct::level, make_float_constant(), make_int_constant(), make_new_identifier(), make_sym_constant(), epmem_param_container::merge, epmem_param_container::merge_add, epmem_timer_container::ncb_retrieval, epmem_stat_container::ncb_wmes, NIL, soar_module::null_t, epmem_edge_struct::q0, epmem_edge_struct::q1, soar_module::row, soar_module::primitive_stat< T >::set_value(), soar_module::timer::start(), soar_module::timer::stop(), SYM_CONSTANT_SYMBOL_TYPE, symbol_remove_ref(), epmem_stat_container::time, epmem_edge_struct::val_is_short_term, epmem_edge_struct::val_letter, epmem_edge_struct::val_num, and epmem_edge_struct::w.

Referenced by epmem_process_query(), and epmem_respond_to_cmd().

{
// get the ^result header for this state
Symbol *result_header = state->id.epmem_result_header;
// initialize stat
int64_t num_wmes = 0;
my_agent->epmem_stats->ncb_wmes->set_value( num_wmes );
// if no memory, say so
if ( ( memory_id == EPMEM_MEMID_NONE ) ||
!epmem_valid_episode( my_agent, memory_id ) )
{
epmem_buffer_add_wme( meta_wmes, result_header, my_agent->epmem_sym_retrieved, my_agent->epmem_sym_no_memory );
return;
}
// remember this as the last memory installed
state->id.epmem_info->last_memory = memory_id;
// create a new ^retrieved header for this result
Symbol *retrieved_header;
retrieved_header = make_new_identifier( my_agent, 'R', result_header->id.level );
if ( id_record )
{
(*id_record)[ EPMEM_NODEID_ROOT ] = retrieved_header;
}
epmem_buffer_add_wme( meta_wmes, result_header, my_agent->epmem_sym_retrieved, retrieved_header );
symbol_remove_ref( my_agent, retrieved_header );
// add *-id wme's
{
Symbol *my_meta;
my_meta = make_int_constant( my_agent, static_cast<int64_t>( memory_id ) );
epmem_buffer_add_wme( meta_wmes, result_header, my_agent->epmem_sym_memory_id, my_meta );
symbol_remove_ref( my_agent, my_meta );
my_meta = make_int_constant( my_agent, static_cast<int64_t>( my_agent->epmem_stats->time->get_value() ) );
epmem_buffer_add_wme( meta_wmes, result_header, my_agent->epmem_sym_present_id, my_meta );
symbol_remove_ref( my_agent, my_meta );
}
// install memory
{
// Big picture: create identifier skeleton, then hang non-identifers
//
// Because of shared WMEs at different levels of the storage breadth-first search,
// there is the possibility that the unique database id of an identifier can be
// greater than that of its parent. Because the retrieval query sorts by
// unique id ascending, it is thus possible to have an "orphan" - a child with
// no current parent. We keep track of orphans and add them later, hoping their
// parents have shown up. I *suppose* there could be a really evil case in which
// the ordering of the unique ids is exactly opposite of their insertion order.
// I just hope this isn't a common case...
// shared identifier lookup table
std::map< epmem_node_id, std::pair< Symbol*, bool > > ids;
bool dont_abide_by_ids_second = ( my_agent->epmem_params->merge->get_value() == epmem_param_container::merge_add );
// symbols used to create WMEs
Symbol *attr = NULL;
// lookup query
// initialize the lookup table
ids[ EPMEM_NODEID_ROOT ] = std::make_pair< Symbol*, bool >( retrieved_header, true );
// first identifiers (i.e. reconstruct)
my_q = my_agent->epmem_stmts_graph->get_edges;
{
// relates to finite automata: q1 = d(q0, w)
epmem_node_id q0; // id
epmem_node_id q1; // attribute
int64_t w_type; // we support any constant attribute symbol
bool val_is_short_term = false;
char val_letter = NIL;
int64_t val_num = NIL;
// used to lookup shared identifiers
// the bool in the pair refers to if children are allowed on this id (re: lti)
std::map< epmem_node_id, std::pair< Symbol*, bool> >::iterator id_p;
// orphaned children
std::queue< epmem_edge* > orphans;
epmem_edge *orphan;
epmem_rit_prep_left_right( my_agent, memory_id, memory_id, &( my_agent->epmem_rit_state_graph[ EPMEM_RIT_STATE_EDGE ] ) );
my_q->bind_int( 1, memory_id );
my_q->bind_int( 2, memory_id );
my_q->bind_int( 3, memory_id );
my_q->bind_int( 4, memory_id );
my_q->bind_int( 5, memory_id );
while ( my_q->execute() == soar_module::row )
{
// q0, w, q1, w_type
q0 = my_q->column_int( 0 );
q1 = my_q->column_int( 2 );
w_type = my_q->column_int( 3 );
switch ( w_type )
{
attr = make_int_constant( my_agent,my_q->column_int( 1 ) );
break;
attr = make_float_constant( my_agent, my_q->column_double( 1 ) );
break;
attr = make_sym_constant( my_agent, const_cast<char *>( reinterpret_cast<const char *>( my_q->column_text( 1 ) ) ) );
break;
}
// short vs. long-term
val_is_short_term = ( my_q->column_type( 4 ) == soar_module::null_t );
if ( !val_is_short_term )
{
val_letter = static_cast<char>( my_q->column_int( 4 ) );
val_num = static_cast<uint64_t>( my_q->column_int( 5 ) );
}
// get a reference to the parent
id_p = ids.find( q0 );
if ( id_p != ids.end() )
{
// if existing lti with kids don't touch
if ( dont_abide_by_ids_second || id_p->second.second )
{
_epmem_install_id_wme( my_agent, id_p->second.first, attr, &( ids ), q1, val_is_short_term, val_letter, val_num, id_record, retrieval_wmes );
num_wmes++;
}
symbol_remove_ref( my_agent, attr );
}
else
{
// out of order
orphan = new epmem_edge;
orphan->q0 = q0;
orphan->w = attr;
orphan->q1 = q1;
orphan->val_letter = NIL;
orphan->val_num = NIL;
orphan->val_is_short_term = val_is_short_term;
if ( !val_is_short_term )
{
orphan->val_letter = val_letter;
orphan->val_num = val_num;
}
orphans.push( orphan );
}
}
my_q->reinitialize();
// take care of any orphans
if ( !orphans.empty() )
{
std::queue<epmem_edge *>::size_type orphans_left;
std::queue<epmem_edge *> still_orphans;
do
{
orphans_left = orphans.size();
while ( !orphans.empty() )
{
orphan = orphans.front();
orphans.pop();
// get a reference to the parent
id_p = ids.find( orphan->q0 );
if ( id_p != ids.end() )
{
if ( dont_abide_by_ids_second || id_p->second.second )
{
_epmem_install_id_wme( my_agent, id_p->second.first, orphan->w, &( ids ), orphan->q1, orphan->val_is_short_term, orphan->val_letter, orphan->val_num, id_record, retrieval_wmes );
num_wmes++;
}
symbol_remove_ref( my_agent, orphan->w );
delete orphan;
}
else
{
still_orphans.push( orphan );
}
}
orphans = still_orphans;
while ( !still_orphans.empty() )
{
still_orphans.pop();
}
} while ( ( !orphans.empty() ) && ( orphans_left != orphans.size() ) );
while ( !orphans.empty() )
{
orphan = orphans.front();
orphans.pop();
symbol_remove_ref( my_agent, orphan->w );
delete orphan;
}
}
}
// then node_unique
my_q = my_agent->epmem_stmts_graph->get_nodes;
{
epmem_node_id child_id;
epmem_node_id parent_id;
int64_t attr_type;
int64_t value_type;
std::pair< Symbol*, bool > parent;
Symbol *value = NULL;
epmem_rit_prep_left_right( my_agent, memory_id, memory_id, &( my_agent->epmem_rit_state_graph[ EPMEM_RIT_STATE_NODE ] ) );
my_q->bind_int( 1, memory_id );
my_q->bind_int( 2, memory_id );
my_q->bind_int( 3, memory_id );
my_q->bind_int( 4, memory_id );
while ( my_q->execute() == soar_module::row )
{
// f.child_id, f.parent_id, f.name, f.value, f.attr_type, f.value_type
child_id = my_q->column_int( 0 );
parent_id = my_q->column_int( 1 );
attr_type = my_q->column_int( 4 );
value_type = my_q->column_int( 5 );
// get a reference to the parent
parent = ids[ parent_id ];
if ( dont_abide_by_ids_second || parent.second )
{
// make a symbol to represent the attribute
switch ( attr_type )
{
attr = make_int_constant( my_agent, my_q->column_int( 2 ) );
break;
attr = make_float_constant( my_agent, my_q->column_double( 2 ) );
break;
attr = make_sym_constant( my_agent, const_cast<char *>( reinterpret_cast<const char *>( my_q->column_text( 2 ) ) ) );
break;
}
// make a symbol to represent the value
switch ( value_type )
{
value = make_int_constant( my_agent,my_q->column_int( 3 ) );
break;
value = make_float_constant( my_agent, my_q->column_double( 3 ) );
break;
value = make_sym_constant( my_agent, const_cast<char *>( (const char *) my_q->column_text( 3 ) ) );
break;
}
epmem_buffer_add_wme( retrieval_wmes, parent.first, attr, value );
num_wmes++;
symbol_remove_ref( my_agent, attr );
symbol_remove_ref( my_agent, value );
}
}
my_q->reinitialize();
}
}
// adjust stat
my_agent->epmem_stats->ncb_wmes->set_value( num_wmes );
}
void epmem_new_episode ( agent my_agent)

Definition at line 2455 of file episodic_memory.cpp.

References _epmem_promote_id(), _epmem_store_level(), epmem_graph_statement_container::add_edge_now, epmem_graph_statement_container::add_edge_point, soar_module::add_module_wme(), epmem_graph_statement_container::add_node_now, epmem_graph_statement_container::add_node_point, epmem_graph_statement_container::add_time, soar_module::sqlite_statement::bind_int(), agent_struct::bottom_goal, soar_module::connected, epmem_graph_statement_container::delete_edge_now, epmem_graph_statement_container::delete_node_now, soar_module::disconnected, agent_struct::epmem_db, agent_struct::epmem_edge_maxes, agent_struct::epmem_edge_mins, agent_struct::epmem_edge_removals, epmem_get_augs_of_id(), identifier_struct::epmem_header, epmem_init_db(), agent_struct::epmem_node_maxes, agent_struct::epmem_node_mins, agent_struct::epmem_node_removals, EPMEM_NODEID_BAD, agent_struct::epmem_promotions, epmem_rit_insert_interval(), EPMEM_RIT_STATE_EDGE, agent_struct::epmem_rit_state_graph, EPMEM_RIT_STATE_NODE, agent_struct::epmem_stats, agent_struct::epmem_stmts_graph, agent_struct::epmem_sym_present_id, identifier_struct::epmem_time_wme, agent_struct::epmem_timers, agent_struct::epmem_validation, agent_struct::epmem_wme_adds, soar_module::statement::execute(), get_new_tc_number(), soar_module::status_object< T >::get_status(), soar_module::primitive_stat< T >::get_value(), identifier_struct::higher_goal, symbol_union::id, make_int_constant(), NIL, soar_module::op_reinit, print(), soar_module::remove_module_wme(), soar_module::primitive_stat< T >::set_value(), soar_module::timer::start(), soar_module::timer::stop(), epmem_timer_container::storage, symbol_remove_ref(), agent_struct::sysparams, epmem_stat_container::time, TRACE_EPMEM_SYSPARAM, epmem_graph_statement_container::update_edge_unique_last, and xml_generate_warning().

Referenced by epmem_consider_new_episode().

{
// if this is the first episode, initialize db components
{
epmem_init_db( my_agent );
}
// add the episode only if db is properly initialized
{
return;
}
my_agent->epmem_timers->storage->start();
epmem_time_id time_counter = my_agent->epmem_stats->time->get_value();
// provide trace output
if ( my_agent->sysparams[ TRACE_EPMEM_SYSPARAM ] )
{
char buf[256];
SNPRINTF( buf, 254, "NEW EPISODE: %ld", static_cast<long int>(time_counter) );
print( my_agent, buf );
xml_generate_warning( my_agent, buf );
}
// perform storage
{
// seen nodes (non-identifiers) and edges (identifiers)
std::queue<epmem_node_id> epmem_node;
std::queue<epmem_node_id> epmem_edge;
// walk appropriate levels
{
// prevents infinite loops
tc_number tc = get_new_tc_number( my_agent );
// children of the current identifier
epmem_wme_list* wmes = NULL;
// breadth first search state
std::queue< Symbol* > parent_syms;
Symbol* parent_sym = NULL;
std::queue< epmem_node_id > parent_ids;
epmem_node_id parent_id;
// cross-level information
std::map< wme*, epmem_id_reservation* > id_reservations;
std::set< Symbol* > new_identifiers;
// start with new WMEs attached to known identifiers
for ( epmem_symbol_set::iterator id_p = my_agent->epmem_wme_adds->begin(); id_p != my_agent->epmem_wme_adds->end(); id_p++ )
{
// make sure the WME is valid
// it can be invalid if a child WME was added, but then the parent was removed, setting the epmem_id to EPMEM_NODEID_BAD
if ((*id_p)->id.epmem_id != EPMEM_NODEID_BAD) {
parent_syms.push( (*id_p) );
parent_ids.push( (*id_p)->id.epmem_id );
while ( !parent_syms.empty() )
{
parent_sym = parent_syms.front();
parent_syms.pop();
parent_id = parent_ids.front();
parent_ids.pop();
wmes = epmem_get_augs_of_id( parent_sym, tc );
if ( ! wmes->empty() )
{
_epmem_store_level( my_agent, parent_syms, parent_ids, tc, wmes->begin(), wmes->end(), parent_id, time_counter, id_reservations, new_identifiers, epmem_node, epmem_edge );
}
delete wmes;
}
}
}
}
// all inserts
{
epmem_node_id *temp_node;
#ifdef EPMEM_EXPERIMENT
epmem_dc_interval_inserts = epmem_node.size() + epmem_edge.size();
#endif
// nodes
while ( !epmem_node.empty() )
{
temp_node =& epmem_node.front();
// add NOW entry
// id = ?, start = ?
my_agent->epmem_stmts_graph->add_node_now->bind_int( 1, (*temp_node) );
my_agent->epmem_stmts_graph->add_node_now->bind_int( 2, time_counter );
// update min
(*my_agent->epmem_node_mins)[ (*temp_node) - 1 ] = time_counter;
epmem_node.pop();
}
// edges
while ( !epmem_edge.empty() )
{
temp_node =& epmem_edge.front();
// add NOW entry
// id = ?, start = ?
my_agent->epmem_stmts_graph->add_edge_now->bind_int( 1, (*temp_node) );
my_agent->epmem_stmts_graph->add_edge_now->bind_int( 2, time_counter );
// update min
(*my_agent->epmem_edge_mins)[ (*temp_node) - 1 ] = time_counter;
my_agent->epmem_stmts_graph->update_edge_unique_last->bind_int( 1, LLONG_MAX );
my_agent->epmem_stmts_graph->update_edge_unique_last->bind_int( 2, *temp_node );
epmem_edge.pop();
}
}
// all removals
{
epmem_id_removal_map::iterator r;
epmem_time_id range_start;
epmem_time_id range_end;
#ifdef EPMEM_EXPERIMENT
epmem_dc_interval_removes = 0;
#endif
// nodes
r = my_agent->epmem_node_removals->begin();
while ( r != my_agent->epmem_node_removals->end() )
{
if ( r->second )
{
#ifdef EPMEM_EXPERIMENT
epmem_dc_interval_removes++;
#endif
// remove NOW entry
// id = ?
my_agent->epmem_stmts_graph->delete_node_now->bind_int( 1, r->first );
range_start = (*my_agent->epmem_node_mins)[ r->first - 1 ];
range_end = ( time_counter - 1 );
// point (id, start)
if ( range_start == range_end )
{
my_agent->epmem_stmts_graph->add_node_point->bind_int( 1, r->first );
my_agent->epmem_stmts_graph->add_node_point->bind_int( 2, range_start );
}
// node
else
{
epmem_rit_insert_interval( my_agent, range_start, range_end, r->first, &( my_agent->epmem_rit_state_graph[ EPMEM_RIT_STATE_NODE ] ) );
}
// update max
(*my_agent->epmem_node_maxes)[ r->first - 1 ] = true;
}
r++;
}
my_agent->epmem_node_removals->clear();
// edges
r = my_agent->epmem_edge_removals->begin();
while ( r != my_agent->epmem_edge_removals->end() )
{
if ( r->second )
{
#ifdef EPMEM_EXPERIMENT
epmem_dc_interval_removes++;
#endif
// remove NOW entry
// id = ?
my_agent->epmem_stmts_graph->delete_edge_now->bind_int( 1, r->first );
range_start = (*my_agent->epmem_edge_mins)[ r->first - 1 ];
range_end = ( time_counter - 1 );
my_agent->epmem_stmts_graph->update_edge_unique_last->bind_int( 1, range_end );
// point (id, start)
if ( range_start == range_end )
{
my_agent->epmem_stmts_graph->add_edge_point->bind_int( 1, r->first );
my_agent->epmem_stmts_graph->add_edge_point->bind_int( 2, range_start );
}
// node
else
{
epmem_rit_insert_interval( my_agent, range_start, range_end, r->first, &( my_agent->epmem_rit_state_graph[ EPMEM_RIT_STATE_EDGE ] ) );
}
// update max
(*my_agent->epmem_edge_maxes)[ r->first - 1 ] = true;
}
r++;
}
my_agent->epmem_edge_removals->clear();
}
// all in-place lti promotions
{
for ( epmem_symbol_set::iterator p_it=my_agent->epmem_promotions->begin(); p_it!=my_agent->epmem_promotions->end(); p_it++ )
{
if ( ( (*p_it)->id.smem_time_id == time_counter ) && ( (*p_it)->id.smem_valid == my_agent->epmem_validation ) )
{
_epmem_promote_id( my_agent, (*p_it), time_counter );
}
symbol_remove_ref( my_agent, (*p_it) );
}
my_agent->epmem_promotions->clear();
}
// add the time id to the times table
my_agent->epmem_stmts_graph->add_time->bind_int( 1, time_counter );
my_agent->epmem_stats->time->set_value( time_counter + 1 );
// update time wme on all states
{
Symbol* state = my_agent->bottom_goal;
Symbol* my_time_sym = make_int_constant( my_agent, time_counter + 1 );
while ( state != NULL )
{
if ( state->id.epmem_time_wme != NIL )
{
}
state->id.epmem_time_wme = soar_module::add_module_wme( my_agent, state->id.epmem_header, my_agent->epmem_sym_present_id, my_time_sym );
state = state->id.higher_goal;
}
symbol_remove_ref( my_agent, my_time_sym );
}
// clear add/remove maps
{
my_agent->epmem_wme_adds->clear();
}
}
my_agent->epmem_timers->storage->stop();
}
epmem_time_id epmem_next_episode ( agent my_agent,
epmem_time_id  memory_id 
)
epmem_time_id epmem_previous_episode ( agent my_agent,
epmem_time_id  memory_id 
)
void epmem_print_episode ( agent my_agent,
epmem_time_id  memory_id,
std::string *  buf 
)

Definition at line 4488 of file episodic_memory.cpp.

References _epmem_print_sti(), soar_module::sqlite_statement::bind_int(), soar_module::sqlite_statement::column_double(), soar_module::sqlite_statement::column_int(), soar_module::sqlite_statement::column_text(), soar_module::sqlite_statement::column_type(), soar_module::disconnected, agent_struct::epmem_db, epmem_init_db(), EPMEM_MEMID_NONE, epmem_rit_clear_left_right(), epmem_rit_prep_left_right(), EPMEM_RIT_STATE_EDGE, agent_struct::epmem_rit_state_graph, EPMEM_RIT_STATE_NODE, agent_struct::epmem_stmts_graph, epmem_valid_episode(), soar_module::statement::execute(), FLOAT_CONSTANT_SYMBOL_TYPE, epmem_graph_statement_container::get_edges, epmem_graph_statement_container::get_nodes, soar_module::status_object< T >::get_status(), INT_CONSTANT_SYMBOL_TYPE, soar_module::null_t, soar_module::statement::reinitialize(), soar_module::row, and SYM_CONSTANT_SYMBOL_TYPE.

{
// if this is before the first episode, initialize db components
{
epmem_init_db( my_agent );
}
// if bad memory, bail
buf->clear();
if ( ( memory_id == EPMEM_MEMID_NONE ) ||
!epmem_valid_episode( my_agent, memory_id ) )
{
return;
}
// fill episode map
std::map< epmem_node_id, std::string > ltis;
std::map< epmem_node_id, std::map< std::string, std::list< std::string > > > ep;
{
std::string temp_s, temp_s2, temp_s3;
double temp_d;
int64_t temp_i;
my_q = my_agent->epmem_stmts_graph->get_edges;
{
int64_t w_type;
bool val_is_short_term;
epmem_rit_prep_left_right( my_agent, memory_id, memory_id, &( my_agent->epmem_rit_state_graph[ EPMEM_RIT_STATE_EDGE ] ) );
// query for edges
my_q->bind_int( 1, memory_id );
my_q->bind_int( 2, memory_id );
my_q->bind_int( 3, memory_id );
my_q->bind_int( 4, memory_id );
my_q->bind_int( 5, memory_id );
while ( my_q->execute() == soar_module::row )
{
q0 = my_q->column_int( 0 );
q1 = my_q->column_int( 2 );
w_type = my_q->column_int( 3 );
val_is_short_term = ( my_q->column_type( 4 ) == soar_module::null_t );
switch ( w_type )
{
temp_i = static_cast<int64_t>( my_q->column_int( 1 ) );
to_string( temp_i, temp_s );
break;
temp_d = my_q->column_double( 1 );
to_string( temp_d, temp_s );
break;
temp_s.assign( const_cast<char *>( reinterpret_cast<const char *>( my_q->column_text( 1 ) ) ) );
break;
}
if ( val_is_short_term )
{
temp_s2 = _epmem_print_sti( q1 );
}
else
{
temp_s2.assign( "@" );
temp_s2.push_back( static_cast< char >( my_q->column_int( 4 ) ) );
temp_i = static_cast< uint64_t >( my_q->column_int( 5 ) );
to_string( temp_i, temp_s3 );
temp_s2.append( temp_s3 );
ltis[ q1 ] = temp_s2;
}
ep[ q0 ][ temp_s ].push_back( temp_s2 );
}
my_q->reinitialize();
}
my_q = my_agent->epmem_stmts_graph->get_nodes;
{
epmem_node_id parent_id;
int64_t attr_type, value_type;
epmem_rit_prep_left_right( my_agent, memory_id, memory_id, &( my_agent->epmem_rit_state_graph[ EPMEM_RIT_STATE_NODE ] ) );
my_q->bind_int( 1, memory_id );
my_q->bind_int( 2, memory_id );
my_q->bind_int( 3, memory_id );
my_q->bind_int( 4, memory_id );
while ( my_q->execute() == soar_module::row )
{
parent_id = my_q->column_int( 1 );
attr_type = my_q->column_int( 4 );
value_type = my_q->column_int( 5 );
switch ( attr_type )
{
temp_i = static_cast<int64_t>( my_q->column_int( 2 ) );
to_string( temp_i, temp_s );
break;
temp_d = my_q->column_double( 2 );
to_string( temp_d, temp_s );
break;
temp_s.assign( const_cast<char *>( reinterpret_cast<const char *>( my_q->column_text( 2 ) ) ) );
break;
}
switch ( value_type )
{
temp_i = static_cast<int64_t>( my_q->column_int( 3 ) );
to_string( temp_i, temp_s2 );
break;
temp_d = my_q->column_double( 3 );
to_string( temp_d, temp_s2 );
break;
temp_s2.assign( const_cast<char *>( reinterpret_cast<const char *>( my_q->column_text( 3 ) ) ) );
break;
}
ep[ parent_id ][ temp_s ].push_back( temp_s2 );
}
my_q->reinitialize();
}
}
// output
{
std::map< epmem_node_id, std::string >::iterator lti_it;
std::map< epmem_node_id, std::map< std::string, std::list< std::string > > >::iterator ep_it;
std::map< std::string, std::list< std::string > >::iterator slot_it;
std::list< std::string >::iterator val_it;
for ( ep_it=ep.begin(); ep_it!=ep.end(); ep_it++ )
{
buf->append( "(" );
// id
lti_it = ltis.find( ep_it->first );
if ( lti_it == ltis.end() )
{
buf->append( _epmem_print_sti( ep_it->first ) );
}
else
{
buf->append( lti_it->second );
}
// attr
for ( slot_it=ep_it->second.begin(); slot_it!=ep_it->second.end(); slot_it++ )
{
buf->append( " ^" );
buf->append( slot_it->first );
for ( val_it=slot_it->second.begin(); val_it!=slot_it->second.end(); val_it++ )
{
buf->append( " " );
buf->append( *val_it );
}
}
buf->append( ")\n" );
}
}
}
void epmem_print_retrieval_state ( epmem_wme_literal_map literals,
epmem_triple_pedge_map  pedge_caches[],
epmem_triple_uedge_map  uedge_caches[] 
)

Definition at line 3300 of file episodic_memory.cpp.

References EPMEM_NODEID_BAD, EPMEM_NODEID_ROOT, EPMEM_RIT_STATE_EDGE, EPMEM_RIT_STATE_NODE, epmem_literal_struct::id_sym, epmem_literal_struct::is_neg_q, epmem_pedge_struct::literals, epmem_literal_struct::matches, epmem_uedge_struct::pedges, epmem_triple_struct::q0, epmem_triple_struct::q1, epmem_literal_struct::q1, epmem_literal_struct::value_is_id, epmem_pedge_struct::value_is_id, epmem_literal_struct::value_sym, epmem_triple_struct::w, and epmem_literal_struct::w.

Referenced by epmem_process_query().

{
//std::map<epmem_node_id, std::string> tsh;
std::cout << std::endl;
std::cout << "digraph {" << std::endl;
std::cout << "node [style=\"filled\"];" << std::endl;
// LITERALS
std::cout << "subgraph cluster_literals {" << std::endl;
std::cout << "node [fillcolor=\"#0084D1\"];" << std::endl;
for (epmem_wme_literal_map::iterator lit_iter = literals.begin(); lit_iter != literals.end(); lit_iter++) {
epmem_literal* literal = (*lit_iter).second;
if (literal->id_sym) {
std::cout << "\"" << literal->value_sym << "\" [";
if (literal->q1 == EPMEM_NODEID_BAD) {
std::cout << "label=\"" << literal->value_sym << "\"";
} else {
std::cout << "label=\"" << literal->q1 << "\"";
}
if (!literal->value_is_id) {
std::cout << ", shape=\"rect\"";
}
if (literal->matches.size() == 0) {
std::cout << ", penwidth=\"2.0\"";
}
if (literal->is_neg_q) {
std::cout << ", fillcolor=\"#C5000B\"";
}
std::cout << "];" << std::endl;
std::cout << "\"" << literal->id_sym << "\" -> \"" << literal->value_sym << "\" [label=\"";
if (literal->w == EPMEM_NODEID_BAD) {
std::cout << "?";
} else {
std::cout << literal->w;
}
std::cout << "\\n" << literal << "\"];" << std::endl;
}
}
std::cout << "};" << std::endl;
// NODES / NODE->NODE
std::cout << "subgraph cluster_uedges{" << std::endl;
std::cout << "node [fillcolor=\"#FFD320\"];" << std::endl;
for (int type = EPMEM_RIT_STATE_NODE; type <= EPMEM_RIT_STATE_EDGE; type++) {
epmem_triple_uedge_map* uedge_cache = &uedge_caches[type];
for (epmem_triple_uedge_map::iterator uedge_iter = uedge_cache->begin(); uedge_iter != uedge_cache->end(); uedge_iter++) {
epmem_triple triple = (*uedge_iter).first;
if (triple.q1 != EPMEM_NODEID_ROOT) {
if (type == EPMEM_RIT_STATE_NODE) {
std::cout << "\"n" << triple.q1 << "\" [shape=\"rect\"];" << std::endl;
}
std::cout << "\"e" << triple.q0 << "\" -> \"" << (type == EPMEM_RIT_STATE_NODE ? "n" : "e") << triple.q1 << "\" [label=\"" << triple.w << "\"];" << std::endl;
}
}
}
std::cout << "};" << std::endl;
// PEDGES / LITERAL->PEDGE
std::cout << "subgraph cluster_pedges {" << std::endl;
std::cout << "node [fillcolor=\"#008000\"];" << std::endl;
std::multimap<epmem_node_id, epmem_pedge*> parent_pedge_map;
for (int type = EPMEM_RIT_STATE_NODE; type <= EPMEM_RIT_STATE_EDGE; type++) {
for (epmem_triple_pedge_map::iterator pedge_iter = pedge_caches[type].begin(); pedge_iter != pedge_caches[type].end(); pedge_iter++) {
epmem_triple triple = (*pedge_iter).first;
epmem_pedge* pedge = (*pedge_iter).second;
if (triple.w != EPMEM_NODEID_BAD) {
std::cout << "\"" << pedge << "\" [label=\"" << pedge << "\\n(" << triple.q0 << ", " << triple.w << ", ";
if (triple.q1 == EPMEM_NODEID_BAD) {
std::cout << "?";
} else {
std::cout << triple.q1;
}
std::cout << ")\"";
if (!pedge->value_is_id) {
std::cout << ", shape=\"rect\"";
}
std::cout << "];" << std::endl;
for (epmem_literal_set::iterator lit_iter = pedge->literals.begin(); lit_iter != pedge->literals.end(); lit_iter++) {
epmem_literal* literal = *lit_iter;
std::cout << "\"" << literal->value_sym << "\" -> \"" << pedge << "\";" << std::endl;
}
parent_pedge_map.insert(std::make_pair(triple.q0, pedge));
}
}
}
std::cout << "};" << std::endl;
// PEDGE->PEDGE / PEDGE->NODE
std::set<std::pair<epmem_pedge*, epmem_node_id> > drawn;
for (int type = EPMEM_RIT_STATE_NODE; type <= EPMEM_RIT_STATE_EDGE; type++) {
epmem_triple_uedge_map* uedge_cache = &uedge_caches[type];
for (epmem_triple_uedge_map::iterator uedge_iter = uedge_cache->begin(); uedge_iter != uedge_cache->end(); uedge_iter++) {
epmem_triple triple = (*uedge_iter).first;
epmem_uedge* uedge = (*uedge_iter).second;
if (triple.w != EPMEM_NODEID_BAD) {
for (epmem_pedge_set::iterator pedge_iter = uedge->pedges.begin(); pedge_iter != uedge->pedges.end(); pedge_iter++) {
epmem_pedge* pedge = *pedge_iter;
std::pair<epmem_pedge*, epmem_node_id> pair = std::make_pair(pedge, triple.q0);
if (!drawn.count(pair)) {
drawn.insert(pair);
std::cout << "\"" << pedge << "\" -> \"e" << triple.q0 << "\";" << std::endl;
}
std::cout << "\"" << pedge << "\" -> \"" << (pedge->value_is_id ? "e" : "n") << triple.q1 << "\" [style=\"dashed\"];" << std::endl;
std::pair<std::multimap<epmem_node_id, epmem_pedge*>::iterator, std::multimap<epmem_node_id, epmem_pedge*>::iterator> pedge_iters = parent_pedge_map.equal_range(triple.q1);
for (std::multimap<epmem_node_id, epmem_pedge*>::iterator pedge_iter = pedge_iters.first; pedge_iter != pedge_iters.second; pedge_iter++) {
std::cout << "\"" << pedge << "\" -> \"" << (*pedge_iter).second << "\";" << std::endl;
}
}
}
}
}
std::cout << "}" << std::endl;
}
void epmem_process_buffered_wmes ( agent my_agent,
Symbol state,
soar_module::wme_set cue_wmes,
soar_module::symbol_triple_list meta_wmes,
soar_module::symbol_triple_list retrieval_wmes 
)
inline

Definition at line 988 of file episodic_memory.cpp.

References _epmem_process_buffered_wme_list(), identifier_struct::epmem_info, epmem_data_struct::epmem_wmes, and symbol_union::id.

Referenced by epmem_respond_to_cmd().

{
_epmem_process_buffered_wme_list( my_agent, state, cue_wmes, meta_wmes, state->id.epmem_info->epmem_wmes );
_epmem_process_buffered_wme_list( my_agent, state, cue_wmes, retrieval_wmes, NULL );
}
void epmem_process_query ( agent my_agent,
Symbol state,
Symbol pos_query,
Symbol neg_query,
epmem_time_list prohibits,
epmem_time_id  before,
epmem_time_id  after,
epmem_symbol_set currents,
soar_module::wme_set cue_wmes,
soar_module::symbol_triple_list meta_wmes,
soar_module::symbol_triple_list retrieval_wmes,
int  level = 3 
)

Definition at line 3847 of file episodic_memory.cpp.

References epmem_uedge_struct::activated, epmem_uedge_struct::activation_count, soar_module::sqlite_statement::bind_int(), epmem_literal_struct::children, soar_module::sqlite_statement::column_int(), epmem_buffer_add_wme(), epmem_build_dnf(), epmem_get_augs_of_id(), epmem_gm_mcv_comparator(), epmem_graph_match(), epmem_install_memory(), agent_struct::epmem_interval_pool, agent_struct::epmem_literal_pool, EPMEM_MEMID_NONE, EPMEM_NODE_NEG, EPMEM_NODE_POS, EPMEM_NODEID_BAD, EPMEM_NODEID_ROOT, agent_struct::epmem_params, agent_struct::epmem_pedge_pool, epmem_print_retrieval_state(), EPMEM_RANGE_END, EPMEM_RANGE_EP, EPMEM_RANGE_NOW, EPMEM_RANGE_POINT, EPMEM_RANGE_START, epmem_register_pedges(), identifier_struct::epmem_result_header, EPMEM_RIT_STATE_EDGE, EPMEM_RIT_STATE_NODE, epmem_satisfy_literal(), agent_struct::epmem_stats, agent_struct::epmem_stmts_graph, agent_struct::epmem_sym_bad_cmd, agent_struct::epmem_sym_cue_size, agent_struct::epmem_sym_failure, agent_struct::epmem_sym_graph_match, agent_struct::epmem_sym_graph_match_mapping, agent_struct::epmem_sym_graph_match_mapping_cue, agent_struct::epmem_sym_graph_match_mapping_node, agent_struct::epmem_sym_match_cardinality, agent_struct::epmem_sym_match_score, agent_struct::epmem_sym_normalized_match_score, agent_struct::epmem_sym_retrieved, agent_struct::epmem_sym_status, agent_struct::epmem_sym_success, agent_struct::epmem_timers, agent_struct::epmem_uedge_pool, epmem_unsatisfy_literal(), soar_module::statement::execute(), epmem_graph_statement_container::find_lti_promotion_time, get_new_tc_number(), soar_module::pooled_sqlite_statement::get_pool(), soar_module::constant_param< T >::get_value(), soar_module::primitive_stat< T >::get_value(), epmem_param_container::gm_order_mcv, epmem_param_container::gm_order_undefined, epmem_param_container::gm_ordering, epmem_param_container::graph_match, epmem_pedge_struct::has_noncurrent, epmem_uedge_struct::has_noncurrent, symbol_union::id, epmem_literal_struct::id_sym, epmem_uedge_struct::intervals, epmem_literal_struct::is_current, epmem_interval_struct::is_end_point, epmem_literal_struct::is_leaf, epmem_literal_struct::is_neg_q, identifier_struct::level, epmem_pedge_struct::literals, make_float_constant(), make_int_constant(), make_new_identifier(), epmem_literal_struct::matches, soar_module::on, soar_module::op_reinit, epmem_literal_struct::parents, epmem_uedge_struct::pedges, epmem_graph_statement_container::pool_dummy, epmem_graph_statement_container::pool_find_interval_queries, epmem_graph_statement_container::pool_find_lti_queries, soar_module::statement::prepare(), print(), epmem_triple_struct::q0, epmem_triple_struct::q1, epmem_literal_struct::q1, epmem_timer_container::query, epmem_timer_container::query_cleanup, QUERY_DEBUG, epmem_timer_container::query_dnf, epmem_timer_container::query_graph_match, epmem_timer_container::query_result, epmem_timer_container::query_sql_end_ep, epmem_timer_container::query_sql_end_now, epmem_timer_container::query_sql_end_point, epmem_timer_container::query_sql_start_ep, epmem_timer_container::query_sql_start_now, epmem_timer_container::query_sql_start_point, epmem_timer_container::query_walk, epmem_timer_container::query_walk_edge, epmem_timer_container::query_walk_interval, soar_module::statement::reinitialize(), soar_module::sqlite_statement_pool::release(), soar_module::sqlite_statement_pool::request(), soar_module::row, epmem_pedge_struct::sql, epmem_interval_struct::sql, soar_module::timer::start(), soar_module::timer::stop(), symbol_remove_ref(), agent_struct::sysparams, epmem_stat_container::time, epmem_pedge_struct::time, epmem_interval_struct::time, TRACE_EPMEM_SYSPARAM, epmem_pedge_struct::triple, epmem_uedge_struct::triple, epmem_interval_struct::uedge, epmem_literal_struct::value_is_id, epmem_pedge_struct::value_is_id, epmem_uedge_struct::value_is_id, epmem_literal_struct::value_sym, epmem_literal_struct::values, epmem_triple_struct::w, epmem_literal_struct::w, epmem_literal_struct::weight, and xml_generate_warning().

Referenced by epmem_respond_to_cmd().

{
// a query must contain a positive cue
if (pos_query == NULL) {
return;
}
// before and after, if specified, must be valid relative to each other
if (before != EPMEM_MEMID_NONE && after != EPMEM_MEMID_NONE && before <= after) {
return;
}
if (QUERY_DEBUG >= 1) {
std::cout << std::endl << "==========================" << std::endl << std::endl;
}
my_agent->epmem_timers->query->start();
// sort probibit's
if (!prohibits.empty()) {
std::sort(prohibits.begin(), prohibits.end());
}
// epmem options
bool do_graph_match = (my_agent->epmem_params->graph_match->get_value() == soar_module::on);
// variables needed for cleanup
epmem_wme_literal_map literal_cache;
epmem_triple_pedge_map pedge_caches[2];
#ifdef USE_MEM_POOL_ALLOCATORS
epmem_triple_uedge_map uedge_caches[2] = {
epmem_triple_uedge_map(std::less<epmem_triple>(), soar_module::soar_memory_pool_allocator<std::pair<const epmem_triple, epmem_uedge*> >(my_agent)),
epmem_triple_uedge_map(std::less<epmem_triple>(), soar_module::soar_memory_pool_allocator<std::pair<const epmem_triple, epmem_uedge*> >(my_agent))
};
epmem_interval_set interval_cleanup = epmem_interval_set(std::less<epmem_interval*>(), soar_module::soar_memory_pool_allocator<epmem_interval*>(my_agent));
#else
epmem_interval_set interval_cleanup = epmem_interval_set();
#endif
// TODO additional indices
// variables needed for building the DNF
epmem_literal* root_literal;
allocate_with_pool(my_agent, &(my_agent->epmem_literal_pool), &root_literal);
epmem_literal_set leaf_literals;
// priority queues for interval walk
epmem_pedge_pq pedge_pq;
epmem_interval_pq interval_pq;
// variables needed to track satisfiability
epmem_symbol_int_map symbol_num_incoming; // number of literals with a certain symbol as its value
epmem_symbol_node_pair_int_map symbol_node_count; // number of times a symbol is matched by a node
// various things about the current and the best episodes
double best_score = 0;
bool best_graph_matched = false;
long int best_cardinality = 0;
double current_score = 0;
long int current_cardinality = 0;
// variables needed for graphmatch
epmem_literal_deque gm_ordering;
if (level > 1) {
// build the DNF graph while checking for leaf WMEs
{
my_agent->epmem_timers->query_dnf->start();
root_literal->id_sym = NULL;
root_literal->value_sym = pos_query;
root_literal->is_neg_q = EPMEM_NODE_POS;
root_literal->is_leaf = false;
root_literal->is_current = false;
root_literal->w = EPMEM_NODEID_BAD;
root_literal->q1 = EPMEM_NODEID_ROOT;
root_literal->weight = 0.0;
new(&(root_literal->parents)) epmem_literal_set();
new(&(root_literal->children)) epmem_literal_set();
#ifdef USE_MEM_POOL_ALLOCATORS
new(&(root_literal->matches)) epmem_node_pair_set(std::less<epmem_node_pair>(), soar_module::soar_memory_pool_allocator<epmem_node_pair>(my_agent));
#else
new(&(root_literal->matches)) epmem_node_pair_set();
#endif
new(&(root_literal->values)) epmem_node_int_map();
symbol_num_incoming[pos_query] = 1;
literal_cache[NULL] = root_literal;
std::set<Symbol*> visiting;
visiting.insert(pos_query);
visiting.insert(neg_query);
for (int query_type = EPMEM_NODE_POS; query_type <= EPMEM_NODE_NEG; query_type++) {
Symbol* query_root = NULL;
switch (query_type) {
query_root = pos_query;
break;
query_root = neg_query;
break;
}
if (!query_root) {
continue;
}
epmem_wme_list* children = epmem_get_augs_of_id(query_root, get_new_tc_number(my_agent));
// for each first level WME, build up a DNF
for (epmem_wme_list::iterator wme_iter = children->begin(); wme_iter != children->end(); wme_iter++) {
epmem_literal* child = epmem_build_dnf(*wme_iter, literal_cache, leaf_literals, symbol_num_incoming, gm_ordering, currents, query_type, visiting, cue_wmes, my_agent);
if (child) {
// force all first level literals to have the same id symbol
child->id_sym = pos_query;
child->parents.insert(root_literal);
root_literal->children.insert(child);
}
}
delete children;
}
my_agent->epmem_timers->query_dnf->stop();
}
// calculate the highest possible score and cardinality score
double perfect_score = 0;
int perfect_cardinality = 0;
for (epmem_literal_set::iterator iter = leaf_literals.begin(); iter != leaf_literals.end(); iter++) {
if (!(*iter)->is_neg_q) {
perfect_score += (*iter)->weight;
perfect_cardinality++;
}
}
// set default values for before and after
if (before == EPMEM_MEMID_NONE) {
before = my_agent->epmem_stats->time->get_value() - 1;
} else {
before = before - 1; // since before's are strict
}
if (after == EPMEM_MEMID_NONE) {
}
epmem_time_id current_episode = before;
epmem_time_id next_episode;
// create dummy edges and intervals
{
// insert dummy unique edge and interval end point queries for DNF root
// we make an SQL statement just so we don't have to do anything special at cleanup
epmem_pedge* root_pedge;
allocate_with_pool(my_agent, &(my_agent->epmem_pedge_pool), &root_pedge);
root_pedge->triple = triple;
root_pedge->has_noncurrent = false;
new(&(root_pedge->literals)) epmem_literal_set();
root_pedge->literals.insert(root_literal);
root_pedge->sql = my_agent->epmem_stmts_graph->pool_dummy->request();
root_pedge->sql->prepare();
root_pedge->sql->bind_int(1, LLONG_MAX);
root_pedge->time = LLONG_MAX;
pedge_pq.push(root_pedge);
pedge_caches[EPMEM_RIT_STATE_EDGE][triple] = root_pedge;
epmem_uedge* root_uedge;
allocate_with_pool(my_agent, &(my_agent->epmem_uedge_pool), &root_uedge);
root_uedge->triple = triple;
root_uedge->has_noncurrent = false;
root_uedge->activation_count = 0;
new(&(root_uedge->pedges)) epmem_pedge_set();
root_uedge->intervals = 1;
root_uedge->activated = false;
uedge_caches[EPMEM_RIT_STATE_EDGE][triple] = root_uedge;
epmem_interval* root_interval;
allocate_with_pool(my_agent, &(my_agent->epmem_interval_pool), &root_interval);
root_interval->uedge = root_uedge;
root_interval->is_end_point = true;
root_interval->sql = my_agent->epmem_stmts_graph->pool_dummy->request();
root_interval->sql->prepare();
root_interval->sql->bind_int(1, before);
root_interval->sql->execute( soar_module::op_reinit );
root_interval->time = before;
interval_pq.push(root_interval);
interval_cleanup.insert(root_interval);
}
if (QUERY_DEBUG >= 1) {
epmem_print_retrieval_state(literal_cache, pedge_caches, uedge_caches);
}
#ifdef EPMEM_EXPERIMENT
epmem_episodes_searched = 0;
#endif
// main loop of interval walk
my_agent->epmem_timers->query_walk->start();
while (pedge_pq.size() && current_episode > after) {
epmem_time_id next_edge;
epmem_time_id next_interval;
bool changed_score = false;
next_edge = pedge_pq.top()->time;
// process all edges which were last used at this time point
while (pedge_pq.size() && (pedge_pq.top()->time == next_edge || pedge_pq.top()->time >= current_episode)) {
epmem_pedge* pedge = pedge_pq.top();
pedge_pq.pop();
epmem_triple triple = pedge->triple;
triple.q1 = pedge->sql->column_int(1);
if (QUERY_DEBUG >= 1) {
std::cout << " EDGE " << triple.q0 << "-" << triple.w << "-" << triple.q1 << std::endl;
}
// create queries for the unique edge children of this partial edge
if (pedge->value_is_id) {
bool created = false;
for (epmem_literal_set::iterator literal_iter = pedge->literals.begin(); literal_iter != pedge->literals.end(); literal_iter++) {
epmem_literal* literal = *literal_iter;
for (epmem_literal_set::iterator child_iter = literal->children.begin(); child_iter != literal->children.end(); child_iter++) {
created |= epmem_register_pedges(triple.q1, *child_iter, pedge_pq, after, pedge_caches, uedge_caches, my_agent);
}
}
}
// TODO what I want to do here is, if there is no children which leads to a leaf, retract everything
// I'm not sure how to properly test for this though
// look for uedge with triple; if none exist, create one
// otherwise, link up the uedge with the pedge and consider score changes
epmem_triple_uedge_map* uedge_cache = &uedge_caches[pedge->value_is_id];
epmem_triple_uedge_map::iterator uedge_iter = uedge_cache->find(triple);
if (uedge_iter == uedge_cache->end()) {
// create a uedge for this
epmem_uedge* uedge;
allocate_with_pool(my_agent, &(my_agent->epmem_uedge_pool), &uedge);
uedge->triple = triple;
uedge->value_is_id = pedge->value_is_id;
uedge->has_noncurrent = pedge->has_noncurrent;
uedge->activation_count = 0;
new(&(uedge->pedges)) epmem_pedge_set();
uedge->intervals = 0;
uedge->activated = false;
// create interval queries for this partial edge
bool created = false;
int64_t edge_id = pedge->sql->column_int(0);
bool is_lti = (pedge->value_is_id && pedge->triple.q1 != EPMEM_NODEID_BAD && pedge->triple.q1 != EPMEM_NODEID_ROOT);
if (is_lti) {
// find the promotion time of the LTI
}
for (int interval_type = EPMEM_RANGE_EP; interval_type <= EPMEM_RANGE_POINT; interval_type++) {
for (int point_type = EPMEM_RANGE_START; point_type <= EPMEM_RANGE_END; point_type++) {
// pick a timer (any timer)
soar_module::timer* sql_timer = NULL;
switch (interval_type) {
if (point_type == EPMEM_RANGE_START) {
sql_timer = my_agent->epmem_timers->query_sql_start_ep;
} else {
sql_timer = my_agent->epmem_timers->query_sql_end_ep;
}
break;
if (point_type == EPMEM_RANGE_START) {
sql_timer = my_agent->epmem_timers->query_sql_start_now;
} else {
sql_timer = my_agent->epmem_timers->query_sql_end_now;
}
break;
if (point_type == EPMEM_RANGE_START) {
sql_timer = my_agent->epmem_timers->query_sql_start_point;
} else {
sql_timer = my_agent->epmem_timers->query_sql_end_point;
}
break;
}
// create the SQL query and bind it
// try to find an existing query first; if none exist, allocate a new one from the memory pools
if (is_lti) {
interval_sql = my_agent->epmem_stmts_graph->pool_find_lti_queries[point_type][interval_type]->request(sql_timer);
} else {
interval_sql = my_agent->epmem_stmts_graph->pool_find_interval_queries[pedge->value_is_id][point_type][interval_type]->request(sql_timer);
}
int bind_pos = 1;
if (point_type == EPMEM_RANGE_END && interval_type == EPMEM_RANGE_NOW) {
interval_sql->bind_int(bind_pos++, current_episode);
}
interval_sql->bind_int(bind_pos++, edge_id);
if (is_lti) {
// find the promotion time of the LTI, and use that as an after constraint
interval_sql->bind_int(bind_pos++, promo_time);
}
interval_sql->bind_int(bind_pos++, current_episode);
if (interval_sql->execute() == soar_module::row) {
epmem_interval* interval;
allocate_with_pool(my_agent, &(my_agent->epmem_interval_pool), &interval);
interval->is_end_point = point_type;
interval->uedge = uedge;
interval->time = interval_sql->column_int(0);
interval->sql = interval_sql;
interval_pq.push(interval);
interval_cleanup.insert(interval);
uedge->intervals++;
created = true;
} else {
interval_sql->get_pool()->release(interval_sql);
}
}
}
if (created) {
if (is_lti) {
// insert a dummy promo time start for LTIs
epmem_interval* start_interval;
allocate_with_pool(my_agent, &(my_agent->epmem_interval_pool), &start_interval);
start_interval->uedge = uedge;
start_interval->is_end_point = EPMEM_RANGE_START;
start_interval->time = promo_time - 1;
start_interval->sql = NULL;
interval_pq.push(start_interval);
interval_cleanup.insert(start_interval);
}
uedge->pedges.insert(pedge);
uedge_cache->insert(std::make_pair(triple, uedge));
} else {
uedge->pedges.~epmem_pedge_set();
free_with_pool(&(my_agent->epmem_uedge_pool), uedge);
}
} else {
epmem_uedge* uedge = (*uedge_iter).second;
uedge->pedges.insert(pedge);
if (uedge->activated) {
for (epmem_literal_set::iterator lit_iter = pedge->literals.begin(); lit_iter != pedge->literals.end(); lit_iter++) {
epmem_literal* literal = (*lit_iter);
if (!literal->is_current || uedge->activation_count == 1) {
changed_score |= epmem_satisfy_literal(literal, triple.q0, triple.q1, current_score, current_cardinality, symbol_node_count, uedge_caches, symbol_num_incoming);
}
}
}
}
// put the partial edge query back into the queue if there's more
// otherwise, reinitialize the query and put it in a pool
if (pedge->sql && pedge->sql->execute() == soar_module::row) {
pedge->time = pedge->sql->column_int(2);
pedge_pq.push(pedge);
} else if (pedge->sql) {
pedge->sql->get_pool()->release(pedge->sql);
pedge->sql = NULL;
}
}
next_edge = (pedge_pq.empty() ? after : pedge_pq.top()->time);
// process all intervals before the next edge arrives
while (interval_pq.size() && interval_pq.top()->time > next_edge && current_episode > after) {
if (QUERY_DEBUG >= 1) {
std::cout << "EPISODE " << current_episode << std::endl;
}
// process all interval endpoints at this time step
while (interval_pq.size() && interval_pq.top()->time >= current_episode) {
epmem_interval* interval = interval_pq.top();
interval_pq.pop();
epmem_uedge* uedge = interval->uedge;
epmem_triple triple = uedge->triple;
if (QUERY_DEBUG >= 1) {
std::cout << " INTERVAL (" << (interval->is_end_point ? "end" : "start") << "): " << triple.q0 << "-" << triple.w << "-" << triple.q1 << std::endl;
}
if (interval->is_end_point) {
uedge->activated = true;
uedge->activation_count++;
for (epmem_pedge_set::iterator pedge_iter = uedge->pedges.begin(); pedge_iter != uedge->pedges.end(); pedge_iter++) {
epmem_pedge* pedge = *pedge_iter;
for (epmem_literal_set::iterator lit_iter = pedge->literals.begin(); lit_iter != pedge->literals.end(); lit_iter++) {
epmem_literal* literal = *lit_iter;
if (!literal->is_current || uedge->activation_count == 1) {
changed_score |= epmem_satisfy_literal(literal, triple.q0, triple.q1, current_score, current_cardinality, symbol_node_count, uedge_caches, symbol_num_incoming);
}
}
}
} else {
uedge->activated = false;
for (epmem_pedge_set::iterator pedge_iter = uedge->pedges.begin(); pedge_iter != uedge->pedges.end(); pedge_iter++) {
epmem_pedge* pedge = *pedge_iter;
for (epmem_literal_set::iterator lit_iter = pedge->literals.begin(); lit_iter != pedge->literals.end(); lit_iter++) {
changed_score |= epmem_unsatisfy_literal(*lit_iter, triple.q0, triple.q1, current_score, current_cardinality, symbol_node_count);
}
}
}
// put the interval query back into the queue if there's more and some literal cares
// otherwise, reinitialize the query and put it in a pool
if (interval->uedge->has_noncurrent && interval->sql && interval->sql->execute() == soar_module::row) {
interval->time = interval->sql->column_int(0);
interval_pq.push(interval);
} else if (interval->sql) {
interval->sql->get_pool()->release(interval->sql);
interval->sql = NULL;
uedge->intervals--;
if (uedge->intervals) {
interval_cleanup.erase(interval);
free_with_pool(&(my_agent->epmem_interval_pool), interval);
} else {
// TODO retract intervals
}
}
}
next_interval = (interval_pq.empty() ? after : interval_pq.top()->time);
next_episode = (next_edge > next_interval ? next_edge : next_interval);
// update the prohibits list to catch up
while (prohibits.size() && prohibits.back() > current_episode) {
prohibits.pop_back();
}
// ignore the episode if it is prohibited
while (prohibits.size() && current_episode > next_episode && current_episode == prohibits.back()) {
current_episode--;
prohibits.pop_back();
}
if (QUERY_DEBUG >= 2) {
epmem_print_retrieval_state(literal_cache, pedge_caches, uedge_caches);
}
if (my_agent->sysparams[TRACE_EPMEM_SYSPARAM]) {
char buf[256];
SNPRINTF(buf, 254, "CONSIDERING EPISODE (time, cardinality, score) (%lld, %ld, %f)\n", static_cast<long long int>(current_episode), current_cardinality, current_score);
print(my_agent, buf);
xml_generate_warning(my_agent, buf);
}
#ifdef EPMEM_EXPERIMENT
epmem_episodes_searched++;
#endif
// if
// * the current time is still before any new intervals
// * and the score was changed in this period
// * and the new score is higher than the best score
// then save the current time as the best one
if (current_episode > next_episode && changed_score && (best_episode == EPMEM_MEMID_NONE || current_score > best_score || (do_graph_match && current_score == best_score && !best_graph_matched))) {
bool new_king = false;
if (best_episode == EPMEM_MEMID_NONE || current_score > best_score) {
best_episode = current_episode;
best_score = current_score;
best_cardinality = current_cardinality;
new_king = true;
}
// we should graph match if the option is set and all leaf literals are satisfied
if (current_cardinality == perfect_cardinality) {
bool graph_matched = false;
if (do_graph_match) {
std::sort(gm_ordering.begin(), gm_ordering.end());
} else if (gm_order == epmem_param_container::gm_order_mcv) {
std::sort(gm_ordering.begin(), gm_ordering.end(), epmem_gm_mcv_comparator);
}
epmem_literal_deque::iterator begin = gm_ordering.begin();
epmem_literal_deque::iterator end = gm_ordering.end();
best_bindings.clear();
epmem_node_symbol_map bound_nodes[2];
if (QUERY_DEBUG >= 1) {
std::cout << " GRAPH MATCH" << std::endl;
epmem_print_retrieval_state(literal_cache, pedge_caches, uedge_caches);
}
graph_matched = epmem_graph_match(begin, end, best_bindings, bound_nodes, my_agent, 2);
}
if (!do_graph_match || graph_matched) {
best_episode = current_episode;
best_graph_matched = true;
current_episode = EPMEM_MEMID_NONE;
new_king = true;
}
}
if (new_king && my_agent->sysparams[TRACE_EPMEM_SYSPARAM]) {
char buf[256];
SNPRINTF(buf, 254, "NEW KING (perfect, graph-match): (%s, %s)\n", (current_cardinality == perfect_cardinality ? "true" : "false"), (best_graph_matched ? "true" : "false"));
print(my_agent, buf);
xml_generate_warning(my_agent, buf);
}
}
if (current_episode == EPMEM_MEMID_NONE) {
break;
} else {
current_episode = next_episode;
}
}
}
my_agent->epmem_timers->query_walk->stop();
// if the best episode is the default, fail
// otherwise, put the episode in working memory
if (best_episode == EPMEM_MEMID_NONE) {
epmem_buffer_add_wme(meta_wmes, state->id.epmem_result_header, my_agent->epmem_sym_failure, pos_query);
if (neg_query) {
epmem_buffer_add_wme(meta_wmes, state->id.epmem_result_header, my_agent->epmem_sym_failure, neg_query);
}
} else {
Symbol* temp_sym;
epmem_id_mapping node_map_map;
epmem_id_mapping node_mem_map;
// cue size
temp_sym = make_int_constant(my_agent, leaf_literals.size());
epmem_buffer_add_wme(meta_wmes, state->id.epmem_result_header, my_agent->epmem_sym_cue_size, temp_sym);
symbol_remove_ref(my_agent, temp_sym);
// match cardinality
temp_sym = make_int_constant(my_agent, best_cardinality);
symbol_remove_ref(my_agent, temp_sym);
// match score
temp_sym = make_float_constant(my_agent, best_score);
epmem_buffer_add_wme(meta_wmes, state->id.epmem_result_header, my_agent->epmem_sym_match_score, temp_sym);
symbol_remove_ref(my_agent, temp_sym);
// normalized match score
temp_sym = make_float_constant(my_agent, best_score / perfect_score);
symbol_remove_ref(my_agent, temp_sym);
// status
epmem_buffer_add_wme(meta_wmes, state->id.epmem_result_header, my_agent->epmem_sym_success, pos_query);
if (neg_query) {
epmem_buffer_add_wme(meta_wmes, state->id.epmem_result_header, my_agent->epmem_sym_success, neg_query);
}
// give more metadata if graph match is turned on
if (do_graph_match) {
// graph match
temp_sym = make_int_constant(my_agent, (best_graph_matched ? 1 : 0));
epmem_buffer_add_wme(meta_wmes, state->id.epmem_result_header, my_agent->epmem_sym_graph_match, temp_sym);
symbol_remove_ref(my_agent, temp_sym);
// mapping
if (best_graph_matched) {
// mapping identifier
Symbol* mapping = make_new_identifier(my_agent, 'M', level);
symbol_remove_ref(my_agent, mapping);
for (epmem_literal_node_pair_map::iterator iter = best_bindings.begin(); iter != best_bindings.end(); iter++) {
if ((*iter).first->value_is_id) {
// create the node
temp_sym = make_new_identifier(my_agent, 'N', level);
epmem_buffer_add_wme(meta_wmes, mapping, my_agent->epmem_sym_graph_match_mapping_node, temp_sym);
symbol_remove_ref(my_agent, temp_sym);
// point to the cue identifier
epmem_buffer_add_wme(meta_wmes, temp_sym, my_agent->epmem_sym_graph_match_mapping_cue, (*iter).first->value_sym);
// save the mapping point for the episode
node_map_map[(*iter).second.second] = temp_sym;
node_mem_map[(*iter).second.second] = NULL;
}
}
}
}
// reconstruct the actual episode
if (level > 2) {
epmem_install_memory(my_agent, state, best_episode, meta_wmes, retrieval_wmes, &node_mem_map);
}
if (best_graph_matched) {
for (epmem_id_mapping::iterator iter = node_mem_map.begin(); iter != node_mem_map.end(); iter++) {
epmem_id_mapping::iterator map_iter = node_map_map.find((*iter).first);
if (map_iter != node_map_map.end() && (*iter).second) {
epmem_buffer_add_wme(meta_wmes, (*map_iter).second, my_agent->epmem_sym_retrieved, (*iter).second);
}
}
}
}
}
// cleanup
for (epmem_interval_set::iterator iter = interval_cleanup.begin(); iter != interval_cleanup.end(); iter++) {
epmem_interval* interval = *iter;
if (interval->sql) {
interval->sql->get_pool()->release(interval->sql);
}
free_with_pool(&(my_agent->epmem_interval_pool), interval);
}
for (int type = EPMEM_RIT_STATE_NODE; type <= EPMEM_RIT_STATE_EDGE; type++) {
for (epmem_triple_pedge_map::iterator iter = pedge_caches[type].begin(); iter != pedge_caches[type].end(); iter++) {
epmem_pedge* pedge = (*iter).second;
if (pedge->sql) {
pedge->sql->get_pool()->release(pedge->sql);
}
pedge->literals.~epmem_literal_set();
free_with_pool(&(my_agent->epmem_pedge_pool), pedge);
}
for (epmem_triple_uedge_map::iterator iter = uedge_caches[type].begin(); iter != uedge_caches[type].end(); iter++) {
epmem_uedge* uedge = (*iter).second;
uedge->pedges.~epmem_pedge_set();
free_with_pool(&(my_agent->epmem_uedge_pool), uedge);
}
}
for (epmem_wme_literal_map::iterator iter = literal_cache.begin(); iter != literal_cache.end(); iter++) {
epmem_literal* literal = (*iter).second;
literal->parents.~epmem_literal_set();
literal->children.~epmem_literal_set();
literal->matches.~epmem_node_pair_set();
literal->values.~epmem_node_int_map();
free_with_pool(&(my_agent->epmem_literal_pool), literal);
}
my_agent->epmem_timers->query->stop();
}
bool epmem_register_pedges ( epmem_node_id  parent,
epmem_literal literal,
epmem_pedge_pq pedge_pq,
epmem_time_id  after,
epmem_triple_pedge_map  pedge_caches[],
epmem_triple_uedge_map  uedge_caches[],
agent my_agent 
)

Definition at line 3521 of file episodic_memory.cpp.

References soar_module::sqlite_statement::bind_int(), epmem_literal_struct::children, soar_module::sqlite_statement::column_int(), EPMEM_NODEID_BAD, agent_struct::epmem_pedge_pool, agent_struct::epmem_stmts_graph, agent_struct::epmem_timers, soar_module::statement::execute(), soar_module::pooled_sqlite_statement::get_pool(), epmem_pedge_struct::has_noncurrent, epmem_literal_struct::is_current, epmem_literal_struct::is_leaf, epmem_pedge_struct::literals, epmem_graph_statement_container::pool_find_edge_queries, epmem_triple_struct::q0, epmem_triple_struct::q1, epmem_literal_struct::q1, QUERY_DEBUG, epmem_timer_container::query_sql_edge, soar_module::sqlite_statement_pool::release(), soar_module::sqlite_statement_pool::request(), soar_module::row, epmem_pedge_struct::sql, epmem_pedge_struct::time, epmem_pedge_struct::triple, epmem_literal_struct::value_is_id, epmem_pedge_struct::value_is_id, epmem_uedge_struct::value_is_id, epmem_triple_struct::w, and epmem_literal_struct::w.

Referenced by epmem_process_query().

{
// we don't need to keep track of visited literals/nodes because the literals are guaranteed to be acyclic
// that is, the expansion to the literal's children will eventually bottom out
// select the query
epmem_triple triple = {parent, literal->w, literal->q1};
int is_edge = literal->value_is_id;
if (QUERY_DEBUG >= 1) {
std::cout << " RECURSING ON " << parent << " " << literal << std::endl;
}
// if the unique edge does not exist, create a new unique edge query
// otherwse, if the pedge has not been registered with this literal
epmem_triple_pedge_map* pedge_cache = &(pedge_caches[is_edge]);
epmem_triple_pedge_map::iterator pedge_iter = pedge_cache->find(triple);
epmem_pedge* child_pedge = (*pedge_iter).second;
if (pedge_iter == pedge_cache->end() || (*pedge_iter).second == NULL) {
int has_value = (literal->q1 != EPMEM_NODEID_BAD ? 1 : 0);
int bind_pos = 1;
if (!is_edge) {
pedge_sql->bind_int(bind_pos++, LLONG_MAX);
}
pedge_sql->bind_int(bind_pos++, triple.q0);
pedge_sql->bind_int(bind_pos++, triple.w);
if (has_value) {
pedge_sql->bind_int(bind_pos++, triple.q1);
}
if (is_edge) {
pedge_sql->bind_int(bind_pos++, after);
}
if (pedge_sql->execute() == soar_module::row) {
epmem_pedge* child_pedge;
allocate_with_pool(my_agent, &(my_agent->epmem_pedge_pool), &child_pedge);
child_pedge->triple = triple;
child_pedge->value_is_id = literal->value_is_id;
child_pedge->has_noncurrent = !literal->is_current;
child_pedge->sql = pedge_sql;
new(&(child_pedge->literals)) epmem_literal_set();
child_pedge->literals.insert(literal);
child_pedge->time = child_pedge->sql->column_int(2);
pedge_pq.push(child_pedge);
(*pedge_cache)[triple] = child_pedge;
return true;
} else {
pedge_sql->get_pool()->release(pedge_sql);
return false;
}
} else if (!child_pedge->literals.count(literal)) {
child_pedge->literals.insert(literal);
if (!literal->is_current) {
child_pedge->has_noncurrent = true;
}
// if the literal is an edge with no specified value, add the literal to all potential pedges
if (!literal->is_leaf && literal->q1 == EPMEM_NODEID_BAD) {
bool created = false;
epmem_triple_uedge_map* uedge_cache = &uedge_caches[is_edge];
for (epmem_triple_uedge_map::iterator uedge_iter = uedge_cache->lower_bound(triple); uedge_iter != uedge_cache->end(); uedge_iter++) {
epmem_triple child_triple = (*uedge_iter).first;
// make sure we're still looking at the right edge(s)
if (child_triple.q0 != triple.q0 || child_triple.w != triple.w) {
break;
}
epmem_uedge* child_uedge = (*uedge_iter).second;
if (child_triple.q1 != EPMEM_NODEID_BAD && child_uedge->value_is_id) {
for (epmem_literal_set::iterator child_iter = literal->children.begin(); child_iter != literal->children.end(); child_iter++) {
created |= epmem_register_pedges(child_triple.q1, *child_iter, pedge_pq, after, pedge_caches, uedge_caches, my_agent);
}
}
}
return created;
}
}
return true;
}
void epmem_reset ( agent my_agent,
Symbol state 
)

Definition at line 1466 of file episodic_memory.cpp.

References identifier_struct::epmem_info, EPMEM_MEMID_NONE, epmem_data_struct::epmem_wmes, symbol_union::id, epmem_data_struct::last_cmd_count, epmem_data_struct::last_cmd_time, epmem_data_struct::last_memory, epmem_data_struct::last_ol_time, identifier_struct::lower_goal, and agent_struct::top_goal.

Referenced by remove_existing_context_and_descendents().

{
if ( state == NULL )
{
state = my_agent->top_goal;
}
while( state )
{
epmem_data *data = state->id.epmem_info;
data->last_ol_time = 0;
data->last_cmd_time = 0;
data->last_cmd_count = 0;
// this will be called after prefs from goal are already removed,
// so just clear out result stack
data->epmem_wmes->clear();
state = state->id.lower_goal;
}
}
void epmem_respond_to_cmd ( agent my_agent)

Definition at line 5216 of file episodic_memory.cpp.

References _epmem_respond_to_cmd_parse(), epmem_timer_container::api, agent_struct::bottom_goal, epmem_stat_container::cbr, soar_module::connected, soar_module::disconnected, do_working_memory_phase(), epmem_buffer_add_wme(), epmem_clear_result(), identifier_struct::epmem_cmd_header, agent_struct::epmem_db, epmem_get_augs_of_id(), identifier_struct::epmem_info, epmem_init_db(), epmem_install_memory(), EPMEM_MEMID_NONE, epmem_next_episode(), epmem_previous_episode(), epmem_process_buffered_wmes(), epmem_process_query(), identifier_struct::epmem_result_header, agent_struct::epmem_stats, agent_struct::epmem_sym_bad_cmd, agent_struct::epmem_sym_failure, agent_struct::epmem_sym_status, agent_struct::epmem_sym_success, agent_struct::epmem_timers, get_new_tc_number(), soar_module::status_object< T >::get_status(), soar_module::primitive_stat< T >::get_value(), identifier_struct::higher_goal, symbol_union::id, IDENTIFIER_SYMBOL_TYPE, epmem_data_struct::last_cmd_count, epmem_data_struct::last_cmd_time, epmem_data_struct::last_memory, epmem_stat_container::nexts, NIL, epmem_stat_container::prevs, soar_module::primitive_stat< T >::set_value(), soar_module::timer::start(), soar_module::timer::stop(), symbol_remove_ref(), and epmem_timer_container::wm_phase.

Referenced by epmem_go().

{
// if this is before the first episode, initialize db components
{
epmem_init_db( my_agent );
}
// respond to query only if db is properly initialized
{
return;
}
// start at the bottom and work our way up
// (could go in the opposite direction as well)
Symbol *state = my_agent->bottom_goal;
epmem_wme_list::iterator w_p;
epmem_time_id retrieve;
Symbol *next;
Symbol *previous;
Symbol *query;
Symbol *neg_query;
epmem_time_list prohibit;
epmem_time_id before, after;
#ifdef USE_MEM_POOL_ALLOCATORS
#else
#endif
bool good_cue;
int path;
uint64_t wme_count;
bool new_cue;
bool do_wm_phase = false;
while ( state != NULL )
{
my_agent->epmem_timers->api->start();
// make sure this state has had some sort of change to the cmd
new_cue = false;
wme_count = 0;
cmds = NULL;
{
tc_number tc = get_new_tc_number( my_agent );
std::queue<Symbol *> syms;
Symbol *parent_sym;
// initialize BFS at command
syms.push( state->id.epmem_cmd_header );
while ( !syms.empty() )
{
// get state
parent_sym = syms.front();
syms.pop();
// get children of the current identifier
wmes = epmem_get_augs_of_id( parent_sym, tc );
{
for ( w_p=wmes->begin(); w_p!=wmes->end(); w_p++ )
{
wme_count++;
if ( (*w_p)->timetag > state->id.epmem_info->last_cmd_time )
{
new_cue = true;
state->id.epmem_info->last_cmd_time = (*w_p)->timetag;
}
if ( (*w_p)->value->common.symbol_type == IDENTIFIER_SYMBOL_TYPE )
{
syms.push( (*w_p)->value );
}
}
// free space from aug list
if ( cmds == NIL )
{
cmds = wmes;
}
else
{
delete wmes;
}
}
}
// see if any WMEs were removed
if ( state->id.epmem_info->last_cmd_count != wme_count )
{
new_cue = true;
state->id.epmem_info->last_cmd_count = wme_count;
}
if ( new_cue )
{
// clear old results
epmem_clear_result( my_agent, state );
do_wm_phase = true;
}
}
// a command is issued if the cue is new
// and there is something on the cue
if ( new_cue && wme_count )
{
_epmem_respond_to_cmd_parse( my_agent, cmds, good_cue, path, retrieve, next, previous, query, neg_query, prohibit, before, after, currents, cue_wmes );
my_agent->epmem_timers->api->stop();
retrieval_wmes.clear();
meta_wmes.clear();
// process command
if ( good_cue )
{
// retrieve
if ( path == 1 )
{
epmem_install_memory( my_agent, state, retrieve, meta_wmes, retrieval_wmes );
}
// previous or next
else if ( path == 2 )
{
if ( next )
{
epmem_install_memory( my_agent, state, epmem_next_episode( my_agent, state->id.epmem_info->last_memory ), meta_wmes, retrieval_wmes );
// add one to the next stat
my_agent->epmem_stats->nexts->set_value( my_agent->epmem_stats->nexts->get_value() + 1 );
}
else
{
epmem_install_memory( my_agent, state, epmem_previous_episode( my_agent, state->id.epmem_info->last_memory ), meta_wmes, retrieval_wmes );
// add one to the prev stat
my_agent->epmem_stats->prevs->set_value( my_agent->epmem_stats->prevs->get_value() + 1 );
}
{
epmem_buffer_add_wme( meta_wmes, state->id.epmem_result_header, my_agent->epmem_sym_failure, ( ( next )?( next ):( previous ) ) );
}
else
{
epmem_buffer_add_wme( meta_wmes, state->id.epmem_result_header, my_agent->epmem_sym_success, ( ( next )?( next ):( previous ) ) );
}
}
// query
else if ( path == 3 )
{
epmem_process_query( my_agent, state, query, neg_query, prohibit, before, after, currents, cue_wmes, meta_wmes, retrieval_wmes );
// add one to the cbr stat
my_agent->epmem_stats->cbr->set_value( my_agent->epmem_stats->cbr->get_value() + 1 );
}
}
else
{
}
// clear prohibit list
prohibit.clear();
if ( !retrieval_wmes.empty() || !meta_wmes.empty() )
{
// process preference assertion en masse
epmem_process_buffered_wmes( my_agent, state, cue_wmes, meta_wmes, retrieval_wmes );
// clear cache
{
soar_module::symbol_triple_list::iterator mw_it;
for ( mw_it=retrieval_wmes.begin(); mw_it!=retrieval_wmes.end(); mw_it++ )
{
symbol_remove_ref( my_agent, (*mw_it)->id );
symbol_remove_ref( my_agent, (*mw_it)->attr );
symbol_remove_ref( my_agent, (*mw_it)->value );
delete (*mw_it);
}
retrieval_wmes.clear();
for ( mw_it=meta_wmes.begin(); mw_it!=meta_wmes.end(); mw_it++ )
{
symbol_remove_ref( my_agent, (*mw_it)->id );
symbol_remove_ref( my_agent, (*mw_it)->attr );
symbol_remove_ref( my_agent, (*mw_it)->value );
delete (*mw_it);
}
meta_wmes.clear();
}
// process wm changes on this state
do_wm_phase = true;
}
// clear cue wmes
cue_wmes.clear();
}
else
{
my_agent->epmem_timers->api->stop();
}
// free space from command aug list
if ( cmds )
{
delete cmds;
}
state = state->id.higher_goal;
}
if ( do_wm_phase )
{
my_agent->epmem_timers->wm_phase->start();
my_agent->epmem_timers->wm_phase->stop();
}
}
void epmem_rit_add_left ( agent my_agent,
epmem_time_id  min,
epmem_time_id  max 
)
void epmem_rit_add_right ( agent my_agent,
epmem_time_id  id 
)
void epmem_rit_clear_left_right ( agent my_agent)
int64_t epmem_rit_fork_node ( int64_t  lower,
int64_t  upper,
bool  ,
int64_t *  step_return,
epmem_rit_state rit_state 
)

Definition at line 1064 of file episodic_memory.cpp.

References EPMEM_RIT_ROOT, soar_module::primitive_stat< T >::get_value(), epmem_rit_state_struct::leftroot, epmem_rit_state_struct::rightroot, and epmem_rit_state_param_struct::stat.

Referenced by epmem_rit_insert_interval().

{
// never called
/*if ( !bounds_offset )
{
int64_t offset = rit_state->offset.stat->get_value();
lower = ( lower - offset );
upper = ( upper - offset );
}*/
// descend the tree down to the fork node
int64_t node = EPMEM_RIT_ROOT;
if ( upper < EPMEM_RIT_ROOT )
{
node = rit_state->leftroot.stat->get_value();
}
else if ( lower > EPMEM_RIT_ROOT )
{
node = rit_state->rightroot.stat->get_value();
}
int64_t step;
for ( step = ( ( ( node >= 0 )?( node ):( -1 * node ) ) / 2 ); step >= 1; step /= 2 )
{
if ( upper < node )
{
node -= step;
}
else if ( node < lower )
{
node += step;
}
else
{
break;
}
}
// never used
// if ( step_return != NULL )
{
(*step_return) = step;
}
return node;
}
void epmem_rit_insert_interval ( agent my_agent,
int64_t  lower,
int64_t  upper,
epmem_node_id  id,
epmem_rit_state rit_state 
)

Definition at line 1252 of file episodic_memory.cpp.

References epmem_rit_state_struct::add_query, soar_module::sqlite_statement::bind_int(), EPMEM_LN_2, epmem_rit_fork_node(), EPMEM_RIT_OFFSET_INIT, EPMEM_RIT_ROOT, epmem_set_variable(), soar_module::statement::execute(), soar_module::primitive_stat< T >::get_value(), epmem_rit_state_struct::leftroot, epmem_rit_state_struct::minstep, epmem_rit_state_struct::offset, soar_module::op_reinit, epmem_rit_state_struct::rightroot, soar_module::primitive_stat< T >::set_value(), epmem_rit_state_param_struct::stat, and epmem_rit_state_param_struct::var_key.

Referenced by epmem_init_db(), and epmem_new_episode().

{
// initialize offset
int64_t offset = rit_state->offset.stat->get_value();
if ( offset == EPMEM_RIT_OFFSET_INIT )
{
offset = lower;
// update database
epmem_set_variable( my_agent, rit_state->offset.var_key, offset );
// update stat
rit_state->offset.stat->set_value( offset );
}
// get node
int64_t node;
{
int64_t left_root = rit_state->leftroot.stat->get_value();
int64_t right_root = rit_state->rightroot.stat->get_value();
int64_t min_step = rit_state->minstep.stat->get_value();
// shift interval
int64_t l = ( lower - offset );
int64_t u = ( upper - offset );
// update left_root
if ( ( u < EPMEM_RIT_ROOT ) && ( l <= ( 2 * left_root ) ) )
{
left_root = static_cast<int64_t>( pow( -2.0, floor( log( static_cast<double>( -l ) ) / EPMEM_LN_2 ) ) );
// update database
epmem_set_variable( my_agent, rit_state->leftroot.var_key, left_root );
// update stat
rit_state->leftroot.stat->set_value( left_root );
}
// update right_root
if ( ( l > EPMEM_RIT_ROOT ) && ( u >= ( 2 * right_root ) ) )
{
right_root = static_cast<int64_t>( pow( 2.0, floor( log( static_cast<double>( u ) ) / EPMEM_LN_2 ) ) );
// update database
epmem_set_variable( my_agent, rit_state->rightroot.var_key, right_root );
// update stat
rit_state->rightroot.stat->set_value( right_root );
}
// update min_step
int64_t step;
node = epmem_rit_fork_node( l, u, true, &step, rit_state );
if ( ( node != EPMEM_RIT_ROOT ) && ( step < min_step ) )
{
min_step = step;
// update database
epmem_set_variable( my_agent, rit_state->minstep.var_key, min_step );
// update stat
rit_state->minstep.stat->set_value( min_step );
}
}
// perform insert
// ( node, start, end, id )
rit_state->add_query->bind_int( 1, node );
rit_state->add_query->bind_int( 2, lower );
rit_state->add_query->bind_int( 3, upper );
rit_state->add_query->bind_int( 4, id );
}
void epmem_rit_prep_left_right ( agent my_agent,
int64_t  lower,
int64_t  upper,
epmem_rit_state rit_state 
)

Definition at line 1152 of file episodic_memory.cpp.

References epmem_rit_add_left(), epmem_rit_add_right(), EPMEM_RIT_ROOT, soar_module::primitive_stat< T >::get_value(), epmem_rit_state_struct::leftroot, epmem_rit_state_struct::offset, epmem_rit_state_struct::rightroot, soar_module::timer::start(), epmem_rit_state_param_struct::stat, soar_module::timer::stop(), and epmem_rit_state_struct::timer.

Referenced by epmem_install_memory(), epmem_print_episode(), and epmem_visualize_episode().

{
rit_state->timer->start();
int64_t offset = rit_state->offset.stat->get_value();
int64_t node, step;
int64_t left_node, left_step;
int64_t right_node, right_step;
lower = ( lower - offset );
upper = ( upper - offset );
// auto add good range
epmem_rit_add_left( my_agent, lower, upper );
// go to fork
step = 0;
if ( ( lower > node ) || (upper < node ) )
{
if ( lower > node )
{
node = rit_state->rightroot.stat->get_value();
}
else
{
node = rit_state->leftroot.stat->get_value();
}
for ( step = ( ( ( node >= 0 )?( node ):( -1 * node ) ) / 2 ); step >= 1; step /= 2 )
{
if ( lower > node )
{
epmem_rit_add_left( my_agent, node, node );
node += step;
}
else if ( upper < node )
{
epmem_rit_add_right( my_agent, node );
node -= step;
}
else
{
break;
}
}
}
// go left
left_node = node - step;
for ( left_step = ( step / 2 ); left_step >= 1; left_step /= 2 )
{
if ( lower == left_node )
{
break;
}
else if ( lower > left_node )
{
epmem_rit_add_left( my_agent, left_node, left_node );
left_node += left_step;
}
else
{
left_node -= left_step;
}
}
// go right
right_node = node + step;
for ( right_step = ( step / 2 ); right_step >= 1; right_step /= 2 )
{
if ( upper == right_node )
{
break;
}
else if ( upper < right_node )
{
epmem_rit_add_right( my_agent, right_node );
right_node -= right_step;
}
else
{
right_node += right_step;
}
}
rit_state->timer->stop();
}
bool epmem_satisfy_literal ( epmem_literal literal,
epmem_node_id  parent,
epmem_node_id  child,
double &  current_score,
long int current_cardinality,
epmem_symbol_node_pair_int_map symbol_node_count,
epmem_triple_uedge_map  uedge_caches[],
epmem_symbol_int_map symbol_num_incoming 
)

Definition at line 3595 of file episodic_memory.cpp.

References epmem_uedge_struct::activated, epmem_uedge_struct::activation_count, epmem_literal_struct::children, EPMEM_NODEID_BAD, epmem_literal_struct::id_sym, epmem_literal_struct::is_current, epmem_literal_struct::is_leaf, epmem_literal_struct::is_neg_q, epmem_literal_struct::matches, epmem_triple_struct::q0, epmem_triple_struct::q1, epmem_literal_struct::q1, QUERY_DEBUG, epmem_literal_struct::value_is_id, epmem_literal_struct::value_sym, epmem_literal_struct::values, epmem_triple_struct::w, epmem_literal_struct::w, and epmem_literal_struct::weight.

Referenced by epmem_process_query().

{
epmem_symbol_node_pair_int_map::iterator match_iter;
if (QUERY_DEBUG >= 1) {
std::cout << " RECURSING ON " << parent << " " << child << " " << literal << std::endl;
}
// check if the ancestors of this literal are satisfied
bool parents_satisfied = (literal->id_sym == NULL);
if (!parents_satisfied) {
// ancestors are satisfied if:
// 1. all incoming literals are satisfied
// 2. all incoming literals have this particular node satisfying it
int num_incoming = symbol_num_incoming[literal->id_sym];
match_iter = symbol_node_count.find(std::make_pair(literal->id_sym, parent));
// since, by definition, if a node satisfies all incoming literals, all incoming literals are satisfied
parents_satisfied = (match_iter != symbol_node_count.end()) && ((*match_iter).second == num_incoming);
}
// if yes
if (parents_satisfied) {
// add the edge as a match
literal->matches.insert(std::make_pair(parent, child));
epmem_node_int_map::iterator values_iter = literal->values.find(child);
if (values_iter == literal->values.end()) {
literal->values[child] = 1;
if (literal->is_leaf) {
if (literal->matches.size() == 1) {
current_score += literal->weight;
current_cardinality += (literal->is_neg_q ? -1 : 1);
if (QUERY_DEBUG >= 1) {
std::cout << " NEW SCORE: " << current_score << ", " << current_cardinality << std::endl;
}
return true;
}
} else {
bool changed_score = false;
// change bookkeeping information about ancestry
epmem_symbol_node_pair match = std::make_pair(literal->value_sym, child);
match_iter = symbol_node_count.find(match);
if (match_iter == symbol_node_count.end()) {
symbol_node_count[match] = 1;
} else {
symbol_node_count[match]++;
}
// recurse over child literals
for (epmem_literal_set::iterator child_iter = literal->children.begin(); child_iter != literal->children.end(); child_iter++) {
epmem_literal* child_lit = *child_iter;
epmem_triple_uedge_map* uedge_cache = &uedge_caches[child_lit->value_is_id];
epmem_triple child_triple = {child, child_lit->w, child_lit->q1};
epmem_triple_uedge_map::iterator uedge_iter;
epmem_uedge* child_uedge = NULL;
if (child_lit->q1 == EPMEM_NODEID_BAD) {
uedge_iter = uedge_cache->lower_bound(child_triple);
while (uedge_iter != uedge_cache->end()) {
child_triple = (*uedge_iter).first;
child_uedge = (*uedge_iter).second;
if (child_triple.q0 != child || child_triple.w != child_lit->w) {
break;
}
if (child_uedge->activated && (!literal->is_current || child_uedge->activation_count == 1)) {
changed_score |= epmem_satisfy_literal(child_lit, child_triple.q0, child_triple.q1, current_score, current_cardinality, symbol_node_count, uedge_caches, symbol_num_incoming);
}
uedge_iter++;
}
} else {
uedge_iter = uedge_cache->find(child_triple);
child_uedge = (*uedge_iter).second;
if (uedge_iter != uedge_cache->end() && child_uedge->activated && (!literal->is_current || child_uedge->activation_count == 1)) {
changed_score |= epmem_satisfy_literal(child_lit, child_triple.q0, child_triple.q1, current_score, current_cardinality, symbol_node_count, uedge_caches, symbol_num_incoming);
}
}
}
return changed_score;
}
} else {
(*values_iter).second++;
}
}
return false;
}
void epmem_schedule_promotion ( agent my_agent,
Symbol id 
)
void epmem_set_variable ( agent my_agent,
epmem_variable_key  variable_id,
int64_t  variable_value 
)
epmem_hash_id epmem_temporal_hash ( agent my_agent,
Symbol sym,
bool  add_on_fail = true 
)

Definition at line 1924 of file episodic_memory.cpp.

References soar_module::sqlite_statement::bind_double(), soar_module::sqlite_statement::bind_int(), soar_module::sqlite_statement::bind_text(), soar_module::sqlite_statement::column_int(), agent_struct::epmem_db, agent_struct::epmem_stmts_common, agent_struct::epmem_timers, agent_struct::epmem_validation, soar_module::statement::execute(), symbol_union::fc, FLOAT_CONSTANT_SYMBOL_TYPE, epmem_timer_container::hash, epmem_common_statement_container::hash_add, epmem_common_statement_container::hash_get, symbol_union::ic, INT_CONSTANT_SYMBOL_TYPE, soar_module::sqlite_database::last_insert_rowid(), sym_constant_struct::name, NIL, soar_module::op_reinit, soar_module::statement::reinitialize(), soar_module::row, symbol_union::sc, soar_module::timer::start(), soar_module::timer::stop(), SYM_CONSTANT_SYMBOL_TYPE, int_constant_struct::value, and float_constant_struct::value.

Referenced by _epmem_store_level(), and epmem_build_dnf().

{
epmem_hash_id return_val = NIL;
my_agent->epmem_timers->hash->start();
if ( ( sym->common.symbol_type == SYM_CONSTANT_SYMBOL_TYPE ) ||
( sym->common.symbol_type == INT_CONSTANT_SYMBOL_TYPE ) ||
( sym->common.symbol_type == FLOAT_CONSTANT_SYMBOL_TYPE ) )
{
if ( ( !sym->common.epmem_hash ) || ( sym->common.epmem_valid != my_agent->epmem_validation ) )
{
sym->common.epmem_hash = NIL;
sym->common.epmem_valid = my_agent->epmem_validation;
// basic process:
// - search
// - if found, return
// - else, add
my_agent->epmem_stmts_common->hash_get->bind_int( 1, sym->common.symbol_type );
switch ( sym->common.symbol_type )
{
my_agent->epmem_stmts_common->hash_get->bind_text( 2, static_cast<const char *>( sym->sc.name ) );
break;
my_agent->epmem_stmts_common->hash_get->bind_int( 2, sym->ic.value );
break;
break;
}
{
return_val = static_cast<epmem_hash_id>( my_agent->epmem_stmts_common->hash_get->column_int( 0 ) );
}
//
if ( !return_val && add_on_fail )
{
my_agent->epmem_stmts_common->hash_add->bind_int( 1, sym->common.symbol_type );
switch ( sym->common.symbol_type )
{
my_agent->epmem_stmts_common->hash_add->bind_text( 2, static_cast<const char *>( sym->sc.name ) );
break;
my_agent->epmem_stmts_common->hash_add->bind_int( 2, sym->ic.value );
break;
break;
}
return_val = static_cast<epmem_hash_id>( my_agent->epmem_db->last_insert_rowid() );
}
// cache results for later re-use
sym->common.epmem_hash = return_val;
sym->common.epmem_valid = my_agent->epmem_validation;
}
return_val = sym->common.epmem_hash;
}
my_agent->epmem_timers->hash->stop();
return return_val;
}
bool epmem_unsatisfy_literal ( epmem_literal literal,
epmem_node_id  parent,
epmem_node_id  child,
double &  current_score,
long int current_cardinality,
epmem_symbol_node_pair_int_map symbol_node_count 
)

Definition at line 3674 of file episodic_memory.cpp.

References epmem_literal_struct::children, EPMEM_NODEID_BAD, epmem_literal_struct::is_leaf, epmem_literal_struct::is_neg_q, epmem_literal_struct::matches, QUERY_DEBUG, epmem_literal_struct::value_sym, epmem_literal_struct::values, and epmem_literal_struct::weight.

Referenced by epmem_process_query().

{
epmem_symbol_int_map::iterator count_iter;
if (literal->matches.size() == 0) {
return false;
}
if (QUERY_DEBUG >= 1) {
std::cout << " RECURSING ON " << parent << " " << child << " " << literal << std::endl;
}
// we only need things if this parent-child pair is matching the literal
epmem_node_pair_set::iterator lit_match_iter = literal->matches.find(std::make_pair(parent, child));
if (lit_match_iter != literal->matches.end()) {
// erase the edge from this literal's matches
literal->matches.erase(lit_match_iter);
epmem_node_int_map::iterator values_iter = literal->values.find(child);
(*values_iter).second--;
if ((*values_iter).second == 0) {
literal->values.erase(values_iter);
if (literal->is_leaf) {
if (literal->matches.size() == 0) {
current_score -= literal->weight;
current_cardinality -= (literal->is_neg_q ? -1 : 1);
if (QUERY_DEBUG >= 1) {
std::cout << " NEW SCORE: " << current_score << ", " << current_cardinality << std::endl;
}
return true;
}
} else {
bool changed_score = false;
epmem_symbol_node_pair match = std::make_pair(literal->value_sym, child);
epmem_symbol_node_pair_int_map::iterator match_iter = symbol_node_count.find(match);
(*match_iter).second--;
if ((*match_iter).second == 0) {
symbol_node_count.erase(match_iter);
}
// if this literal is no longer satisfied, recurse on all children
// if this literal is still satisfied, recurse on children who is matching on descendants of this edge
if (literal->matches.size() == 0) {
for (epmem_literal_set::iterator child_iter = literal->children.begin(); child_iter != literal->children.end(); child_iter++) {
epmem_literal* child_lit = *child_iter;
for (epmem_node_pair_set::iterator node_iter = child_lit->matches.begin(); node_iter != child_lit->matches.end(); node_iter++) {
changed_score |= epmem_unsatisfy_literal(child_lit, (*node_iter).first, (*node_iter).second, current_score, current_cardinality, symbol_node_count);
}
}
} else {
epmem_node_pair node_pair = std::make_pair(child, EPMEM_NODEID_BAD);
for (epmem_literal_set::iterator child_iter = literal->children.begin(); child_iter != literal->children.end(); child_iter++) {
epmem_literal* child_lit = *child_iter;
epmem_node_pair_set::iterator node_iter = child_lit->matches.lower_bound(node_pair);
if (node_iter != child_lit->matches.end() && (*node_iter).first == child) {
changed_score |= epmem_unsatisfy_literal(child_lit, (*node_iter).first, (*node_iter).second, current_score, current_cardinality, symbol_node_count);
}
}
}
return changed_score;
}
}
}
return false;
}
bool epmem_valid_episode ( agent my_agent,
epmem_time_id  memory_id 
)
void epmem_visualize_episode ( agent my_agent,
epmem_time_id  memory_id,
std::string *  buf 
)

Definition at line 4672 of file episodic_memory.cpp.

References soar_module::sqlite_statement::bind_int(), soar_module::sqlite_statement::column_double(), soar_module::sqlite_statement::column_int(), soar_module::sqlite_statement::column_text(), soar_module::sqlite_statement::column_type(), soar_module::disconnected, agent_struct::epmem_db, epmem_init_db(), EPMEM_MEMID_NONE, epmem_rit_clear_left_right(), epmem_rit_prep_left_right(), EPMEM_RIT_STATE_EDGE, agent_struct::epmem_rit_state_graph, EPMEM_RIT_STATE_NODE, agent_struct::epmem_stmts_graph, epmem_valid_episode(), soar_module::statement::execute(), FLOAT_CONSTANT_SYMBOL_TYPE, epmem_graph_statement_container::get_edges, epmem_graph_statement_container::get_nodes, soar_module::status_object< T >::get_status(), INT_CONSTANT_SYMBOL_TYPE, soar_module::null_t, soar_module::statement::reinitialize(), soar_module::row, and SYM_CONSTANT_SYMBOL_TYPE.

{
// if this is before the first episode, initialize db components
{
epmem_init_db( my_agent );
}
// if bad memory, bail
buf->clear();
if ( ( memory_id == EPMEM_MEMID_NONE ) ||
!epmem_valid_episode( my_agent, memory_id ) )
{
return;
}
// init
{
buf->append( "digraph epmem {\n" );
}
// taken heavily from install
{
// first identifiers (i.e. reconstruct)
my_q = my_agent->epmem_stmts_graph->get_edges;
{
// for printing
std::map< epmem_node_id, std::string > stis;
std::map< epmem_node_id, std::pair< std::string, std::string > > ltis;
std::list< std::string > edges;
std::map< epmem_node_id, std::string >::iterator sti_p;
std::map< epmem_node_id, std::pair< std::string, std::string > >::iterator lti_p;
// relates to finite automata: q1 = d(q0, w)
epmem_node_id q0; // id
epmem_node_id q1; // attribute
int64_t w_type; // we support any constant attribute symbol
std::string temp, temp2, temp3, temp4;
double temp_d;
int64_t temp_i;
bool val_is_short_term;
char val_letter;
uint64_t val_num;
// 0 is magic
temp.assign( "ID_0" );
stis.insert( std::make_pair< epmem_node_id, std::string >( 0, temp ) );
// prep rit
epmem_rit_prep_left_right( my_agent, memory_id, memory_id, &( my_agent->epmem_rit_state_graph[ EPMEM_RIT_STATE_EDGE ] ) );
// query for edges
my_q->bind_int( 1, memory_id );
my_q->bind_int( 2, memory_id );
my_q->bind_int( 3, memory_id );
my_q->bind_int( 4, memory_id );
my_q->bind_int( 5, memory_id );
while ( my_q->execute() == soar_module::row )
{
// q0, w, q1, w_type, letter, num
q0 = my_q->column_int( 0 );
q1 = my_q->column_int( 2 );
w_type = my_q->column_int( 3 );
// "ID_Q0"
temp.assign( "ID_" );
to_string( q0, temp2 );
temp.append( temp2 );
// "ID_Q1"
temp3.assign( "ID_" );
to_string( q1, temp2 );
temp3.append( temp2 );
val_is_short_term = ( my_q->column_type( 4 ) == soar_module::null_t );
if ( val_is_short_term )
{
sti_p = stis.find( q1 );
if ( sti_p == stis.end() )
{
stis.insert( std::make_pair< epmem_node_id, std::string >( q1, temp3 ) );
}
}
else
{
lti_p = ltis.find( q1 );
if ( lti_p == ltis.end() )
{
// "L#"
val_letter = static_cast<char>( my_q->column_int( 4 ) );
to_string( val_letter, temp4 );
val_num = static_cast<uint64_t>( my_q->column_int( 5 ) );
to_string( val_num, temp2 );
temp4.append( temp2 );
ltis.insert( std::make_pair< epmem_node_id, std::pair< std::string, std::string > >( q1, std::make_pair< std::string, std::string >( temp3, temp4 ) ) );
}
}
// " -> ID_Q1"
temp.append( " -> " );
temp.append( temp3 );
// " [ label="w" ];\n"
temp.append( " [ label=\"" );
switch ( w_type )
{
temp_i = static_cast<int64_t>( my_q->column_int( 1 ) );
to_string( temp_i, temp2 );
break;
temp_d = my_q->column_double( 1 );
to_string( temp_d, temp2 );
break;
temp2.assign( const_cast<char *>( reinterpret_cast<const char *>( my_q->column_text( 1 ) ) ) );
break;
}
temp.append( temp2 );
temp.append( "\" ];\n" );
edges.push_back( temp );
}
my_q->reinitialize();
// identifiers
{
// short-term
{
buf->append( "node [ shape = circle ];\n" );
for ( sti_p=stis.begin(); sti_p!=stis.end(); sti_p++ )
{
buf->append( sti_p->second );
buf->append( " " );
}
buf->append( ";\n" );
}
// long-term
{
buf->append( "node [ shape = doublecircle ];\n" );
for ( lti_p=ltis.begin(); lti_p!=ltis.end(); lti_p++ )
{
buf->append( lti_p->second.first );
buf->append( " [ label=\"" );
buf->append( lti_p->second.second );
buf->append( "\" ];\n" );
}
buf->append( "\n" );
}
}
// edges
{
std::list< std::string >::iterator e_p;
for ( e_p=edges.begin(); e_p!=edges.end(); e_p++ )
{
buf->append( (*e_p) );
}
}
}
// then node_unique
my_q = my_agent->epmem_stmts_graph->get_nodes;
{
epmem_node_id child_id;
epmem_node_id parent_id;
int64_t attr_type;
int64_t value_type;
std::list< std::string > edges;
std::list< std::string > consts;
std::string temp, temp2;
double temp_d;
int64_t temp_i;
epmem_rit_prep_left_right( my_agent, memory_id, memory_id, &( my_agent->epmem_rit_state_graph[ EPMEM_RIT_STATE_NODE ] ) );
my_q->bind_int( 1, memory_id );
my_q->bind_int( 2, memory_id );
my_q->bind_int( 3, memory_id );
my_q->bind_int( 4, memory_id );
while ( my_q->execute() == soar_module::row )
{
// f.child_id, f.parent_id, f.name, f.value, f.attr_type, f.value_type
child_id = my_q->column_int( 0 );
parent_id = my_q->column_int( 1 );
attr_type = my_q->column_int( 4 );
value_type = my_q->column_int( 5 );
temp.assign( "ID_" );
to_string( parent_id, temp2 );
temp.append( temp2 );
temp.append( " -> C_" );
to_string( child_id, temp2 );
temp.append( temp2 );
temp.append( " [ label=\"" );
// make a symbol to represent the attribute
switch ( attr_type )
{
temp_i = static_cast<int64_t>( my_q->column_int( 2 ) );
to_string( temp_i, temp2 );
break;
temp_d = my_q->column_double( 2 );
to_string( temp_d, temp2 );
break;
temp2.assign( const_cast<char *>( reinterpret_cast<const char *>( my_q->column_text( 2 ) ) ) );
break;
}
temp.append( temp2 );
temp.append( "\" ];\n" );
edges.push_back( temp );
temp.assign( "C_" );
to_string( child_id, temp2 );
temp.append( temp2 );
temp.append( " [ label=\"" );
// make a symbol to represent the value
switch ( value_type )
{
temp_i = static_cast<int64_t>( my_q->column_int( 3 ) );
to_string( temp_i, temp2 );
break;
temp_d = my_q->column_double( 3 );
to_string( temp_d, temp2 );
break;
temp2.assign( const_cast<char *>( reinterpret_cast<const char *>( my_q->column_text( 3 ) ) ) );
break;
}
temp.append( temp2 );
temp.append( "\" ];\n" );
consts.push_back( temp );
}
my_q->reinitialize();
// constant nodes
{
std::list< std::string >::iterator e_p;
buf->append( "node [ shape = plaintext ];\n" );
for ( e_p=consts.begin(); e_p!=consts.end(); e_p++ )
{
buf->append( (*e_p) );
}
}
// edges
{
std::list< std::string >::iterator e_p;
for ( e_p=edges.begin(); e_p!=edges.end(); e_p++ )
{
buf->append( (*e_p) );
}
}
}
}
// close
{
buf->append( "\n}\n" );
}
}