Soar Kernel  9.3.2 08-06-12
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
prefmem.cpp
Go to the documentation of this file.
1 #include <portability.h>
2 
3 /*************************************************************************
4  * PLEASE SEE THE FILE "license.txt" (INCLUDED WITH THIS SOFTWARE PACKAGE)
5  * FOR LICENSE AND COPYRIGHT INFORMATION.
6  *************************************************************************/
7 
8 /*************************************************************************
9  *
10  * file: prefmem.cpp
11  *
12  * =======================================================================
13  * NOTE: need some comments here
14  * =======================================================================
15  */
16 
17 /* ======================================================================
18  Preference Memory routines for Soar 6
19  ====================================================================== */
20 
21 /* Debugging stuff: #define DEBUG_PREFS to get preference printouts */
22 
23 /* #define DEBUG_PREFS */
24 
25 #include <stdlib.h>
26 #include "mem.h"
27 #include "kernel.h"
28 #include "agent.h"
29 #include "gdatastructs.h"
30 #include "instantiations.h"
31 #include "symtab.h"
32 #include "recmem.h"
33 #include "tempmem.h"
34 #include "decide.h"
35 #include "prefmem.h"
36 #include "print.h"
37 #include "wma.h"
38 #include "wmem.h"
39 
40 const char * preference_name[] =
41 { "acceptable",
42  "require",
43  "reject",
44  "prohibit",
45  "reconsider",
46  "unary indifferent",
47  "unary parallel",
48  "best",
49  "worst",
50  "binary indifferent",
51  "binary parallel",
52  "better",
53  "worse",
54  "numeric indifferent"};
55 
56 
57 /* Preference Management Routines
58 
59 ====================================================================== */
60 
61 /* ----------------------------------------------------------------------
62  Make_preference() creates a new preference structure of the given type
63  with the given id/attribute/value/referent. (Referent is only used
64  for binary preferences.) The preference is not yet added to preference
65  memory, however.
66 ---------------------------------------------------------------------- */
67 
69  Symbol *value, Symbol *referent) {
70  preference *p;
71 
72  allocate_with_pool (thisAgent, &thisAgent->preference_pool, &p);
73  p->type = type;
74  p->in_tm = FALSE;
75  p->o_supported = FALSE;
76  p->on_goal_list = FALSE;
77  p->reference_count = 0;
78  p->id = id;
79  p->attr = attr;
80  p->value = value;
81  p->referent = referent;
82  p->slot = NIL;
83  p->next_clone = NIL;
84  p->prev_clone = NIL;
86  p->numeric_value = 0;
87  p->rl_contribution = false;
88  p->wma_o_set = NIL;
89 
90 #ifdef DEBUG_PREFS
91  print (thisAgent, "\nAllocating preference at 0x%8x: ", reinterpret_cast<uintptr_t>(p));
92  print_preference (thisAgent, p);
93 #endif
94 
95  return p;
96 
97  /* BUGBUG check to make sure the pref doesn't have
98  value or referent .isa_goal or .isa_impasse; */
99 }
100 
101 /* ----------------------------------------------------------------------
102  Deallocate_preference() deallocates a given preference.
103 ---------------------------------------------------------------------- */
104 
105 void deallocate_preference (agent* thisAgent, preference *pref) {
106 
107 #ifdef DEBUG_PREFS
108  print (thisAgent, "\nDeallocating preference at 0x%8x: ",reinterpret_cast<uintptr_t>(pref));
109  print_preference (thisAgent, pref);
110  if (pref->reference_count != 0) { /* --- sanity check --- */
111  char msg[BUFFER_MSG_SIZE];
112  strncpy (msg, "prefmem.c: Internal Error: Deallocating preference with ref. count != 0\n", BUFFER_MSG_SIZE);
113  msg[BUFFER_MSG_SIZE - 1] = 0; /* ensure null termination */
114  abort_with_fatal_error(thisAgent, msg);
115  }
116 #endif
117 
118  /* --- remove it from the list of pref's for its match goal --- */
119  if (pref->on_goal_list)
121  pref, all_of_goal_next, all_of_goal_prev);
122 
123  /* --- remove it from the list of pref's from that instantiation --- */
125  inst_next, inst_prev);
126  possibly_deallocate_instantiation (thisAgent, pref->inst);
127 
128  /* --- dereference component symbols --- */
129  symbol_remove_ref (thisAgent, pref->id);
130  symbol_remove_ref (thisAgent, pref->attr);
131  symbol_remove_ref (thisAgent, pref->value);
132  if (preference_is_binary(pref->type))
133  symbol_remove_ref (thisAgent, pref->referent);
134 
135  if ( pref->wma_o_set )
136  {
137  wma_remove_pref_o_set( thisAgent, pref );
138  }
139 
140  /* --- free the memory --- */
141  free_with_pool (&thisAgent->preference_pool, pref);
142 }
143 
144 /* ----------------------------------------------------------------------
145  Possibly_deallocate_preference_and_clones() checks whether a given
146  preference and all its clones have reference_count 0, and deallocates
147  them all if they do. It returns TRUE if they were actually
148  deallocated, FALSE otherwise.
149 ---------------------------------------------------------------------- */
150 
152  preference *clone, *next;
153 
154  if (pref->reference_count) return FALSE;
155  for (clone=pref->next_clone; clone!=NIL; clone=clone->next_clone)
156  if (clone->reference_count) return FALSE;
157  for (clone=pref->prev_clone; clone!=NIL; clone=clone->prev_clone)
158  if (clone->reference_count) return FALSE;
159 
160  /* --- deallocate all the clones --- */
161  clone = pref->next_clone;
162  while (clone) {
163  next = clone->next_clone;
164  deallocate_preference (thisAgent, clone);
165  clone = next;
166  }
167  clone = pref->prev_clone;
168  while (clone) {
169  next = clone->prev_clone;
170  deallocate_preference (thisAgent, clone);
171  clone = next;
172  }
173 
174  /* --- deallocate pref --- */
175  deallocate_preference (thisAgent, pref);
176 
177  return TRUE;
178 }
179 
180 /* ----------------------------------------------------------------------
181  Remove_preference_from_clones() splices a given preference out of the
182  list of clones. If the preference's reference_count is 0, it also
183  deallocates it and returns TRUE. Otherwise it returns FALSE.
184 ---------------------------------------------------------------------- */
185 
187  preference *any_clone;
188 
189  any_clone = NIL;
190  if (pref->next_clone) {
191  any_clone = pref->next_clone;
192  pref->next_clone->prev_clone = pref->prev_clone;
193  }
194  if (pref->prev_clone) {
195  any_clone = pref->prev_clone;
196  pref->prev_clone->next_clone = pref->next_clone;
197  }
198  pref->next_clone = pref->prev_clone = NIL;
199  if (any_clone) possibly_deallocate_preference_and_clones (thisAgent, any_clone);
200  if (! pref->reference_count) {
201  deallocate_preference (thisAgent, pref);
202  return TRUE;
203  } else {
204  return FALSE;
205  }
206 }
207 
208 /* ------------------------------------------------------------------------
209  Add_preference_to_tm() adds a given preference to preference memory (and
210  hence temporary memory).
211 ------------------------------------------------------------------------ */
212 
213 bool add_preference_to_tm (agent* thisAgent, preference *pref)
214 {
215 #ifdef DEBUG_PREFS
216  print (thisAgent, "\nAdd preference at 0x%8x: ",reinterpret_cast<uintptr_t>(pref));
217  print_preference (thisAgent, pref);
218 #endif
219 
220  slot *s = make_slot( thisAgent, pref->id, pref->attr );
221  preference *p2;
222 
223  if ( !s->isa_context_slot && pref->o_supported && ( pref->type == ACCEPTABLE_PREFERENCE_TYPE ) && ( pref->inst->match_goal == thisAgent->top_state ) )
224  {
225  bool already_top_o_supported = false;
226 
227  for ( p2=s->all_preferences; ( p2 && !already_top_o_supported ); p2=p2->all_of_slot_next )
228  {
229  if ( ( p2->value == pref->value ) && p2->o_supported && ( p2->inst->match_goal == thisAgent->top_state ) )
230  {
231  already_top_o_supported = true;
232  }
233  }
234 
235  if ( already_top_o_supported )
236  {
237  // NLD: if it is suspected that this code is causing an issue, simply comment out the following line to debug.
238  return false;
239  }
240  }
241 
242  pref->slot = s;
243 
245  all_of_slot_next, all_of_slot_prev);
246 
247  /* --- add preference to the list (in the right place, according to match
248  goal level of the instantiations) for the slot --- */
249 
250  if (!s->preferences[pref->type])
251  {
252  /* --- this is the only pref. of its type, just put it at the head --- */
253  insert_at_head_of_dll (s->preferences[pref->type], pref, next, prev);
254  }
255  else if (s->preferences[pref->type]->inst->match_goal_level >= pref->inst->match_goal_level)
256  {
257  /* --- it belongs at the head of the list, so put it there --- */
258  insert_at_head_of_dll (s->preferences[pref->type], pref, next, prev);
259  }
260  else
261  {
262  /* --- scan through the pref. list, find the one to insert after --- */
263  for (p2 = s->preferences[pref->type]; p2->next != NIL; p2 = p2->next)
264  {
265  if (p2->next->inst->match_goal_level >= pref->inst->match_goal_level)
266  break;
267  }
268 
269  /* --- insert pref after p2 --- */
270  pref->next = p2->next;
271  pref->prev = p2;
272  p2->next = pref;
273  if (pref->next)
274  pref->next->prev = pref;
275  }
276 
277  /* --- other miscellaneous stuff --- */
278  pref->in_tm = TRUE;
279  preference_add_ref (pref);
280 
281  // if it's the case that the slot is unchanged, but has
282  // some references laying around, clear them
283  // this doesn't cause immediate memory deallocate/allocate
284  // but once the WMEs are resolved, this should free the
285  // memory, as opposed to lead to a "leak"
286  if ( wma_enabled( thisAgent ) && !s->isa_context_slot )
287  {
288  if ( !s->changed )
289  {
290  if ( s->wma_val_references != NIL )
291  {
292  s->wma_val_references->clear();
293  }
294  }
295  }
296 
297  mark_slot_as_changed (thisAgent, s);
298 
299  if ( wma_enabled( thisAgent ) && !s->isa_context_slot )
300  {
301  bool exists = false;
302  wme* w = pref->slot->wmes;
303  while ( !exists && w )
304  {
305  if ( w->value == pref->value )
306  {
307  exists = true;
308  }
309 
310  w = w->next;
311  }
312 
313  // if wme exists, it should already have been updated
314  // during assertion of new preferences
315  if ( !exists )
316  {
317  if ( s->wma_val_references == NIL )
318  {
319  allocate_with_pool( thisAgent, &( thisAgent->wma_slot_refs_pool ), &( s->wma_val_references ) );
320 #ifdef USE_MEM_POOL_ALLOCATORS
322 #else
324 #endif
325  }
326 
327  (*s->wma_val_references)[ pref->value ]++;
328  }
329  }
330 
331  /* --- update identifier levels --- */
332  if (pref->value->common.symbol_type == IDENTIFIER_SYMBOL_TYPE)
333  {
334  post_link_addition (thisAgent, pref->id, pref->value);
335  }
336 
337  if (preference_is_binary(pref->type))
338  {
339  if (pref->referent->common.symbol_type == IDENTIFIER_SYMBOL_TYPE)
340  post_link_addition (thisAgent, pref->id, pref->referent);
341  }
342 
343  /* --- if acceptable/require pref for context slot, we may need to add a
344  wme later --- */
345  if ((s->isa_context_slot) &&
346  ((pref->type==ACCEPTABLE_PREFERENCE_TYPE) ||
347  (pref->type==REQUIRE_PREFERENCE_TYPE)))
348  {
350  }
351 
352  return true;
353 }
354 
355 /* ------------------------------------------------------------------------
356  Remove_preference_from_tm() removes a given preference from PM and TM.
357 ------------------------------------------------------------------------ */
358 
359 void remove_preference_from_tm (agent* thisAgent, preference *pref) {
360  slot *s;
361 
362  s = pref->slot;
363 
364 #ifdef DEBUG_PREFS
365  print (thisAgent, "\nRemove preference at 0x%8x: ",reinterpret_cast<uintptr_t>(pref));
366  print_preference (thisAgent, pref);
367 #endif
368 
369  /* --- remove preference from the list for the slot --- */
371  all_of_slot_next, all_of_slot_prev);
372  remove_from_dll (s->preferences[pref->type], pref, next, prev);
373 
374  /* --- other miscellaneous stuff --- */
375  pref->in_tm = FALSE;
376  pref->slot = NIL; /* BUG shouldn't we use pref->slot in place of pref->in_tm? */
377  mark_slot_as_changed (thisAgent, s);
378 
379  /* --- if acceptable/require pref for context slot, we may need to remove
380  a wme later --- */
381  if ((s->isa_context_slot) &&
382  ((pref->type==ACCEPTABLE_PREFERENCE_TYPE) ||
383  (pref->type==REQUIRE_PREFERENCE_TYPE)))
385 
386  /* --- update identifier levels --- */
387  if (pref->value->common.symbol_type==IDENTIFIER_SYMBOL_TYPE)
388  post_link_removal (thisAgent, pref->id, pref->value);
389  if (preference_is_binary(pref->type))
390  if (pref->referent->common.symbol_type==IDENTIFIER_SYMBOL_TYPE)
391  post_link_removal (thisAgent, pref->id, pref->referent);
392 
393  /* --- deallocate it and clones if possible --- */
394  preference_remove_ref (thisAgent, pref);
395 }
396 
397 /* ------------------------------------------------------------------------
398  Process_o_rejects_and_deallocate_them() handles the processing of
399  o-supported reject preferences. This routine is called from the firer
400  and passed a list of all the o-rejects generated in the current
401  preference phase (the list is linked via the "next" fields on the
402  preference structures). This routine removes all preferences for
403  matching values from TM, and deallocates the o-reject preferences when
404  done.
405 ------------------------------------------------------------------------ */
406 
407 void process_o_rejects_and_deallocate_them (agent* thisAgent, preference *o_rejects, pref_buffer_list& bufdeallo)
408 {
409  preference *pref, *next_pref, *p, *next_p;
410  slot *s;
411 
412  for (pref=o_rejects; pref!=NIL; pref=pref->next) {
413  preference_add_ref (pref); /* prevents it from being deallocated if it's
414  a clone of some other pref we're about to
415  remove */
416 #ifdef DEBUG_PREFS
417  print (thisAgent, "\nO-reject posted at 0x%8x: ",reinterpret_cast<uintptr_t>(pref));
418  print_preference (thisAgent, pref);
419 #endif
420  }
421 
422  pref = o_rejects;
423  while (pref) {
424  next_pref = pref->next;
425  s = find_slot (pref->id, pref->attr);
426  if (s) {
427  /* --- remove all pref's in the slot that have the same value --- */
428  p = s->all_preferences;
429  while (p) {
430  next_p = p->all_of_slot_next;
431  if (p->value==pref->value) {
432  // Buffer deallocation by adding a reference here and putting it
433  // on a list. These are deallocated after the inner elaboration
434  // loop completes.
436  bufdeallo.push_back(p);
437  remove_preference_from_tm (thisAgent, p);
438  }
439  p = next_p;
440  }
441  }
442  preference_remove_ref (thisAgent, pref);
443  pref = next_pref;
444  }
445 }
446