[PEAK] PEAK Components: beginner questions
Duncan McGreggor
python at adytumsolutions.com
Tue Sep 21 03:10:49 EDT 2004
Hey everyone,
Some colleagues and I have been working on behavioral modeling in
python, and it's just now getting to the point of moving from sandboxes
and test code to prototype classes. Intuitively, PEAK felt like a
perfect match for this kind of thing.
I've been reading the "Composing Hierarchies" entry on the wiki
(http://peak.telecommunity.com/DevCenter/ComposingHierarchies) and
trying to learn from it for about a couple days. I'm really new to
these concepts, and the wiki example isn't practical enough for me, so
I tried building another one. Now that I've had the chance to juggle
the code and ideas around, I was hoping to get some feedback from the
community about the approach I have tried and suggestions for
improvements, best practices, or misconceptions I have worked into the
code.
I have pasted the sample code below. The code is very silly and meant
to be an experiment in PEAK, and not a serious model for a software
agent ;-) Also, after the code, I've pasted a list of questions that
came up as a result of going through this process.
I would like to integrate code, questions, answers and feedback and
then post it on the wiki as an additional example for PEAK beginners
like myself. Any objections?
General plan of hierarchy/component-relationships:
Body provides an interface IBody
Physiology provides an interface IPhysiology and depends on Body
Intellect, Vision and Hearing provide an interface IMind
Movement provides and interface IMovement
Emotion provides an interface IEmotion and depends on Physiology,
Vision, and Hearing
Action depends on Emotion, Physiology, Intellect, and Movement
Code:
from protocols import Interface, advise
from peak.binding.components import Component, Obtain, Make
from random import random
from math import ceil
#------------------------------------------------------------
class IBody(Interface):
'''Body interface. Body can be mechanical, bio, or other'''
def getFuelLevel():
"how long can we operate?"
def getDamageLevel():
"are we disabled?"
class IPhysiology(IBody):
'''Physiology interface'''
def getHeartRate():
'''provide information about the heart rate'''
class Body(Component):
'''
>>> b = Body()
>>> b.getFuelLevel()
'half full'
>>> b.getDamageLevel()
'minimal damage'
'''
advise(instancesProvide=[IBody])
def getFuelLevel(self):
return "half full"
def getDamageLevel(self):
return "minimal damage"
class Physiology(Component):
'''
>>> p = Physiology()
>>> p.getHeartRate()
'nice rhythm!'
>>> p.body.getFuelLevel()
'half full'
>>> p.body.getDamageLevel()
'minimal damage'
'''
advise(instancesProvide=[IPhysiology])
body = Make(Body, offerAs=[IBody])
def getHeartRate(self):
return "nice rhythm!"
#------------------------------------------------------------
class IMind(Interface):
'''Mind interface'''
def perceive():
'''provide perception'''
def think():
'''provide 'thought' mechanism'''
class Intellect(Component):
advise(instancesProvide=[IMind])
def think(self):
print "hmmm, fire bad, thinking hard..."
class Vision(Component):
advise(instancesProvide=[IMind])
def perceive(self):
if ceil(random()*2)%2: return "see threat!"
class Hearing(Component):
advise(instancesProvide=[IMind])
def perceive(self):
if ceil(random()*3)%3: return "hear threat!"
#------------------------------------------------------------
class IEmotion(Interface):
'''Emotion interface'''
def getIntensity():
'''provide aa means for obtaining emotional intensities'''
class Emotion(Component):
'''
>>> e = Emotion()
>>> e.vision.perceive() in [None, 'see threat!']
True
>>> e.hearing.perceive() in [None, 'hear threat!']
True
>>> e.physiology.getHeartRate()
'nice rhythm!'
>>> type(e.getIntensity()).__name__
'int'
'''
advise(instancesProvide=[IEmotion])
def __init__(self):
self.feeling = 0
vision = Make(Vision, offerAs=[IMind])
hearing = Make(Hearing, offerAs=[IMind])
physiology = Make(Physiology, offerAs=[IPhysiology])
def getIntensity(self):
'''
Silly emotional intensity method
'''
if self.hearing.perceive():
self.feeling -= 1
else:
self.feeling += 1
if self.vision.perceive():
self.feeling -= 1
else:
self.feeling += 1
if self.physiology.getHeartRate():
self.feeling += 1
else:
self.feeling -= 1
return self.feeling
#------------------------------------------------------------
class IMovement(Interface):
'''Movement interface'''
def north():
'''go north'''
def south():
'''go south'''
class IAction(Interface):
'''Action interface'''
def doSomething():
'''Determine an agent action'''
class Movement(Component):
advise(instancesProvide=[IMind])
def north(self):
print "you are now one step north of where you were"
def south(self):
print "you are now one step south of where you were"
class Action(Component):
'''
>>> a = Action()
>>> a.physiology.getHeartRate()
'nice rhythm!'
>>> a.physiology.body.getFuelLevel()
'half full'
>>> a.physiology.body.getDamageLevel()
'minimal damage'
>>> type(a.emotion.getIntensity()).__name__
'int'
>>> a.intellect.think()
hmmm, fire bad, thinking hard...
>>> a.movement.north()
you are now one step north of where you were
>>> a.doSomething()
'action!'
'''
advise(instancesProvide=[IAction])
emotion = Make(Emotion, offerAs=[IMind, IPhysiology])
physiology = Make(Physiology, offerAs=[IPhysiology])
intellect = Make(Intellect, offerAs=[IMind])
movement = Make(Movement, offerAs=[IMovement])
def doSomething(self):
'''
Here, we can get info about the agent from
the various components which comprise it,
and produce some action.
'''
return "action!"
#------------------------------------------------------------
def _test():
import doctest, components
return doctest.testmod(components)
if __name__ == '__main__':
_test()
* What's the best way for an interface to inherit from another
interface? (I know this has been discussed... I just can't find it)
* I used Make for adding components to a class; is that the right
approach?
* When would I choose Make over Obtain? and vice versa?
* Right now, a physiology instance p has to use p.body to get to the
Body methods; is there are better/more direct way to do this? Seems a
little awkward... (since I'm used to object inheritance)
* How does it complicate things that Physiology is both "in" Emotion
and "in" Action, with action "containing" Emotion which "contains"
Physiology?
* "In" and "contains" seem poor word choices for the last question;
what are the standard terms used to describe such things?
* The Russian Doll component code of Emotion and Action may not be
appropriate for an agent model, but I wanted to experiment with
component "depth"... my approach seems amateurish, since I don't know
what I am doing. Better approaches?
* In the Action class, Emotion is offered as IMind and IPhysiology, due
to the fact that Vision and Hearing (in Emotion) provide IMind
interfaces. Is this the right way to do something like this?
* Given this python/PEAK agent model, are there other interesting
PEAK-specific questions I should be asking that I am not? Questions
that might give better insight into design choices?
More information about the PEAK
mailing list