1 """Class for defining the default parameters of an individual agent"""
2 from xml.dom.minidom import *
3
4 from teamwork.math.Keys import StateKey
5 from teamwork.agent.stereotypes import *
6 from teamwork.agent.audit import *
7 from teamwork.agent.support import *
8 from teamwork.action.DecisionSpace import *
9 from teamwork.dynamics.pwlDynamics import PWLDynamics
10 from teamwork.math.matrices import DecisionTree
11
13 """
14 A container of default values for an L{Agent}
15
16 0. Creating a new generic model:
17 C{model = L{GenericModel}(name)}
18
19 1. Society-specific methods
20 - C{model.L{getParents}()}
21
22 2. Picking a specific stereotypical mental model
23 - C{model.L{setModel}(name)}
24
25 3. Manipulating the space of stereotypical mental models:
26 - C{model[models]} --- a dictionary of the form C{modelName: modelObj, ...}, where modelObj is a L{GenericModel}. Currently we read/write only the goals and policy attributes of modelObj.
27
28 4. Manipulating the goals
29 - C{model.L{getGoals}()}
30 - C{model.L{setGoals}(goalList)}
31 - C{model.L{getGoalWeight}(goal)}
32 - C{model.L{setGoalWeight}(goal,num)}
33
34 5. Manipulating the recursive belief structure
35 - C{model.L{ancestry}()}
36 - C{model.L{getBelief}(entityName,feature)}
37 - C{model.L{setBelief}(entityName,feature,num)}
38 - C{model.L{getEntities}()}
39 - C{model.L{getEntity}(entityName)}
40 - C{model.L{setEntity}(entityName,entityObj)}
41 - C{model.L{getEntityBeliefs}()}
42
43 6. Manipulating the state
44 - C{model.L{getState}(feature)}
45 - C{model.L{setState}(feature,num)}
46
47 7. Manipulating the actions
48 - C{model.actions}: a L{DecisionSpace} object
49
50 8. Manipulating the dynamics
51 - C{model.dynamics}: a L{PWLDynamics} instance
52 @ivar depth: maximum depth of nesting of recursive beliefs
53 @type depth: int
54 """
55
67
69 """Sets the hierarchy of L{GenericModel} instances that this agent uses for its default values
70 @type classes: L{GenericSociety<teamwork.multiagent.GenericSociety.GenericSociety>}
71 """
72 self.hierarchy = classes
73
100
102 """
103 @param old: the current name of the member
104 @param new: the new name of the member
105 @type old,new: str
106 """
107
108 if self.name == old:
109 self.setName(new)
110
111 try:
112 index = self.parentModels.index(old)
113 self.parentModels[index] = new
114 except ValueError:
115
116 pass
117
118 for goal in self.getGoals():
119 if old in goal.entity:
120 weight = self.getGoalWeight(goal)
121 del self.goals[goal]
122 eList = goal.entity[:]
123 while True:
124 try:
125 index = eList.index(old)
126 except ValueError:
127 break
128 eList[index] = new
129 goal = goal.__class__(eList,goal.direction,goal.type,
130 goal.key,goal.value)
131 self.goals[goal] = weight
132
133 for option in self.actions.getOptions():
134 for action in option:
135 if action['object'] == old:
136 action['object'] = new
137 if self.name == new:
138 action['actor'] = new
139
140 for relation,fillers in self.relationships.items():
141 for name in fillers[:]:
142 if name == old:
143 fillers.remove(old)
144 fillers.append(new)
145
146 for key,value in self.links.items():
147 remove = False
148 if key['subject'] == old:
149 remove = True
150 if key['object'] == old:
151 remove = True
152 obj = new
153 else:
154 obj = key['object']
155 if remove:
156 del self.links[key]
157 self.setLink(key['verb'],obj,value)
158
159 if self.hasBelief(old):
160 self.entities.renameMember(old,new)
161
162 for dynamics in sum(map(lambda d:d.values(),
163 self.dynamics.values()),[]):
164 dynamics.renameEntity(old,new)
165
167 """Move up through the generic model hierarchy
168 @return: the immediate parent models of this generic model
169 @rtype: C{str[]}"""
170 return self.parentModels
171
173 """
174 @return: C{True} iff this class is a subclass (inclusive) of the named class
175 @rtype: boolean
176 @param cls: The class name to test on
177 @type cls: str
178 """
179 if self.name == cls:
180 return True
181 else:
182 for parent in self.getParents():
183 if self.hierarchy[parent].isSubclass(cls):
184 return True
185 return False
186
188 """
189 @return: all fillers of a slot (e.g, 'state', 'action', 'goal') on this model I{and} all superclasses
190 @rtype: str[]
191 """
192 values = []
193
194 for name in self.ancestors():
195 entity = self.hierarchy[name]
196 if attribute == 'state':
197 potential = entity.getStateFeatures()
198 elif attribute == 'action':
199 potential = entity.actions.getOptions()
200 else:
201 raise NotImplementedError,\
202 'Unable to get %s slots from superclasses' % (attribute)
203 for value in potential:
204 if not value in values:
205 values.append(value)
206 return values
207
209 """
210 @param attribute: the agent model slot to look for (e.g., 'state', 'action', 'goal')
211 @type attribute,value: str
212 @param value: the slot filler to look for (e.g., state feature)
213 @return: the lowest class (either this one or some ancestory) that defines the given value in the given agent attributes
214 @rtype: str
215 @param includeSelf: if C{True}, then include self in search (default is C{True})
216 @type includeSelf: bool
217 """
218 if includeSelf:
219 classes = [self.name]
220 else:
221 classes = self.getParents()[:]
222 while len(classes) > 0:
223 for cls in classes[:]:
224 classes.remove(cls)
225 classes += self.hierarchy[cls].getParents()
226 if attribute == 'state':
227 if value in self.hierarchy[cls].getStateFeatures():
228 return cls
229 else:
230 raise NotImplementedError,'Unable to get %s slots from superclasses' % (attribute)
231
232 if includeSelf:
233 raise KeyError,'No %s value %s for %s' % (attribute,value,
234 self.name)
235 else:
236 return None
237
241
243 """Removes the given feature from the state
244 @type feature: str
245 """
246
247 key = StateKey({'entity':self.name,'feature':feature})
248 self.state = self.state.marginalize(key)
249
250 if self.dynamics.has_key(feature):
251 del self.dynamics[feature]
252
254 """
255 @param order: if C{True}, then order the results from general to specific (default is C{False})
256 @type order: bool
257 @return: all ancestor classes of this class, including itself
258 @rtype: str[]
259 """
260 result = {}
261 next = [self.name]
262 while len(next) > 0:
263 name = next.pop()
264 if not result.has_key(name):
265 result[name] = True
266 next += self.hierarchy[name].getParents()
267 if order:
268 remaining = result.keys()
269 result = []
270 while len(remaining) > 1:
271 index = 0
272 while True:
273 entity = self.hierarchy[remaining[index]]
274 if len(filter(lambda p: not p in result,
275 entity.getParents())) == 0:
276 break
277 index += 1
278 else:
279 raise UserWarning,'Cycle in hierarchy'
280 result.append(entity.name)
281 del remaining[index]
282 result.append(remaining[0])
283 return result
284 else:
285 return result.keys()
286
288 """
289 @return: all the relationships available to this generic model (including those to its superclasses
290 @rtype: str[]
291 """
292 relationships = {}
293 for name in self.ancestors():
294 for relationship in self.hierarchy[name].relationships.keys():
295 relationships[relationship] = True
296 relationships = relationships.keys()
297 relationships.sort()
298 return relationships
299
301 """Returns an XML Document representing this model"""
302 if doc is None:
303 doc = Stereotyper.__xml__(self)
304 root = doc.documentElement
305 root.setAttribute('depth',str(self.depth))
306 node = doc.createElement('parents')
307 root.appendChild(node)
308 for name in self.parentModels:
309 child = doc.createElement('parent')
310 child.appendChild(doc.createTextNode(name))
311 node.appendChild(child)
312 node = doc.createElement('state')
313 node.appendChild(self.state.__xml__().documentElement)
314 root.appendChild(node)
315 doc = Supporter.__xml__(self,doc)
316 return doc
317
318 - def parse(self,element):
319 """Extracts model elements from the provided XML element
320 @type element: Element"""
321 Supporter.parse(self,element)
322 try:
323 self.depth = int(element.getAttribute('depth'))
324 except ValueError:
325
326 pass
327 node = element.firstChild
328 while node:
329 if node.nodeType != node.ELEMENT_NODE:
330 pass
331 elif node.tagName == 'parents':
332 parent = node.firstChild
333 while parent:
334 if parent.nodeType == node.ELEMENT_NODE:
335 name = str(parent.firstChild.data).strip()
336 self.parentModels.append(name)
337 parent = parent.nextSibling
338 elif node.tagName == 'state':
339 parent = node.firstChild
340 while parent:
341 if parent.nodeType == node.ELEMENT_NODE:
342 self.state.parse(parent,KeyedVector)
343 parent = parent.nextSibling
344 node = node.nextSibling
345
347 """Updates generic model from dictionary-style spec"""
348
349 try:
350 self.parentModels = generic['parent']
351 except KeyError:
352 pass
353
354 if generic.has_key('state'):
355 for feature,value in generic['state'].items():
356 self.setState(feature,value)
357
358 if generic.has_key('actions'):
359 self.actions = extractSpace(generic['actions'])
360
361 if generic.has_key('goals'):
362 self.setGoals(generic['goals'])
363
364 if generic.has_key('models'):
365 for name,model in generic['models'].items():
366 agent = GenericModel(name)
367 agent.setGoals(model['goals'])
368 agent.policy = model['policy']
369 self.models[name] = agent
370 if generic.has_key('model'):
371 self.model = generic['model']
372
373 if generic.has_key('relationships'):
374 self.relationships = generic['relationships']
375 for label,targets in self.relationships.items():
376 if not isinstance(targets,list):
377 raise UserWarning,'For consistency, we require that the target class(es) for a relationship be provided in a list, rather than as a singleton (i.e., %s: [%s])' % (label,targets)
378
379 if generic.has_key('beliefs'):
380 for other,belief in generic['beliefs'].items():
381 if other:
382 if other == 'self':
383 entity = GenericModel(self.name)
384 else:
385 entity = GenericModel(other)
386 self.setEntity(entity)
387 for key,value in belief.items():
388 if key == 'model':
389 entity.model = {'name':value,
390 'fixed':False}
391 else:
392 entity.setState(key,value)
393 else:
394
395 raise DeprecationWarning,'Do not use "None" keys in generic model hierarchy'
396
397 if generic.has_key('dynamics'):
398 if isinstance(generic['dynamics'],list):
399 dynamicsList = generic['dynamics']
400 else:
401 dynamicsList = [generic['dynamics']]
402 for dynamics in dynamicsList:
403 for feature,dynDict in dynamics.items():
404 self.dynamics[feature] = {}
405 for act,dyn in dynDict.items():
406 if isinstance(dyn,DecisionTree):
407 dyn = {'class':PWLDynamics,
408 'args':{'tree':dyn}}
409 fun = dyn['class']
410 args = dyn['args']
411 self.dynamics[feature][act] = apply(fun,(args,))
412
413 if generic.has_key('observations'):
414 for omega,entries in generic['observations'].items():
415 new = copy.deepcopy(entries)
416 if isinstance(omega,ObservationKey):
417 key = omega
418 else:
419 key = ObservationKey({'type': omega})
420 try:
421 self.observations[key].update(new)
422 except KeyError:
423 self.observations[key] = new
424
425 if generic.has_key('depth'):
426 self.depth = generic['depth']
427
428 if generic.has_key('horizon'):
429 self.horizon = generic['horizon']
430