def getActions(self,vector): targets = [] resources = vector[stateKey(self.name,self.resourceName)] for obj in self.legalObjects(vector): targets.append(obj) actions = self.getCombos(targets,resources) return Agent.getActions(self,vector,actions).union(Agent.getActions(self,vector))
def run_univariate_function(name, symbol_fmt, func): print('\n*************************************') print('Testing {} function'.format(name)) # PsychSim elements world = World() agent = Agent('The Agent') world.addAgent(agent) # gets samples from real non-linear function x_params, y_params, sample_values = \ get_bivariate_samples(func, MIN_X, MAX_X, MIN_Y, MAX_Y, NUM_SAMPLES, NUM_SAMPLES) sample_mean = np.nanmean(sample_values) # create two features: one holding the variable, the other the result (dependent) var_x = world.defineState(agent.name, 'var_x', float, lo=MIN_X, hi=MAX_X) var_y = world.defineState(agent.name, 'var_y', float, lo=MIN_Y, hi=MAX_Y) result = world.defineState(agent.name, 'result', float, lo=np.min(sample_values), hi=np.max(sample_values)) world.setFeature(result, 0) # create action that is approximates the function, storing the result in the result feature action = agent.addAction({'verb': 'operation', 'action': name}) tree = makeTree( tree_from_bivariate_samples(result, var_x, var_y, x_params, y_params, sample_values)) world.setDynamics(result, action, tree) world.setOrder([agent.name]) np.random.seed(SEED) values_original = [] values_approx = [] for i in range(NUM_TEST_SAMPLES): # gets random sample parameters x = MIN_X + np.random.rand() * (MAX_X - MIN_X) y = MIN_Y + np.random.rand() * (MAX_Y - MIN_Y) # sets variable and updates result world.setFeature(var_x, x) world.setFeature(var_y, y) world.step() real = func(x, y) psych = world.getValue(result) print('{:3}: {:30} | Expected: {:10.2f} | PsychSim: {:10.2f}'.format( i, symbol_fmt.format(x, y), real, psych)) values_original.append(real) values_approx.append(psych) # gets error stats rmse = np.sqrt(np.mean((np.array(values_approx) - values_original)**2)) print('=====================================') print('RMSE = {:.3f}'.format(rmse)) print('\nPress \'Enter\' to continue...') input()
def setUp(self): # Create world self.world = World() # Create agents self.tom = Agent('Tom') self.world.addAgent(self.tom) self.jerry = Agent('Jerry') self.world.addAgent(self.jerry)
def __init__(self,name,resource=None,verb=None,objects=None): Agent.__init__(self,name) if not resource is None: self.resourceName = resource self.verbName = verb self.objects = objects self.objectLegality = {} for obj in objects: self.objectLegality[obj] = makeTree(True) self.allocateAll = False
def parse(self,element): Agent.parse(self,element) self.resourceName = str(element.getAttribute('resource')) self.verbName = str(element.getAttribute('verb')) self.objects = [] self.objectLegality = {} node = element.firstChild while node: if node.nodeType == node.ELEMENT_NODE: if node.tagName == 'object': self.objects.append(str(node.firstChild.data).strip()) elif node.tagName == 'objectlegal': obj = str(node.getAttribute('object')) subnode = node.firstChild while subnode: if subnode.nodeType == subnode.ELEMENT_NODE: tree = KeyedTree(subnode) self.objectLegality[obj] = tree break subnode = subnode.nextSibling node = node.nextSibling
def __xml__(self): doc = Agent.__xml__(self) doc.documentElement.setAttribute('resource',self.resourceName) doc.documentElement.setAttribute('verb',self.verbName) for obj in self.objects: node = doc.createElement('object') node.appendChild(doc.createTextNode(obj)) doc.documentElement.appendChild(node) for obj,tree in self.objectLegality.items(): node = doc.createElement('objectlegal') node.setAttribute('object',obj) node.appendChild(tree.__xml__().documentElement) doc.documentElement.appendChild(node) return doc
'This method can be used to discretize features\' values at each timestep by having a "dummy" agent ' \ 'that has a single action, i.e., the discretization action. The agent can be placed in the turn ' \ 'order such that it acts *after* all other agents.' \ 'A similar method can be used to have discretized rewards, i.e., to create a reward function whose ' \ 'value is the discretized value of a feature.' HIGH = 100 LOW = 50 NUM_BINS = 11 NUM_SAMPLES = 100 if __name__ == '__main__': # create world and add agent world = World() agent = Agent('Agent') world.addAgent(agent) # add variable feat = world.defineState(agent.name, 'x', float, lo=LOW, hi=HIGH) # add single action that discretizes the feature action = agent.addAction({'verb': '', 'action': 'discretize'}) tree = makeTree(discretization_tree(world, feat, NUM_BINS)) world.setDynamics(feat, action, tree) world.setOrder([{agent.name}]) print('====================================') print('High:\t{}'.format(HIGH)) print('Low:\t{}'.format(LOW))
def __init__(self, turnOrder): self.maxRounds = 8 self.world = World() totals = {'apple': 1, 'pear': 2} batna_prePref = totals['apple'] + totals['pear'] stacy = Agent('Stacy') david = Agent('David') agts = [stacy, david] # Player state, actions and parameters common to both players for i in range(2): me = agts[i] other = agts[1 - i] self.world.addAgent(me) # State self.world.defineState(me.name, 'appleOwned', int, lo=0, hi=totals['apple']) me.setState('appleOwned', 0) self.world.defineState(me.name, 'appleOffered', int, lo=0, hi=totals['apple']) me.setState('appleOffered', 0) self.world.defineState(me.name, 'pearOwned', int, lo=0, hi=totals['pear']) me.setState('pearOwned', 0) self.world.defineState(me.name, 'pearOffered', int, lo=0, hi=totals['pear']) me.setState('pearOffered', 0) self.world.defineState(me.name, 'Batna', int, lo=0, hi=10) me.setState('Batna', batna_prePref) self.world.defineState(me.name, 'BatnaOwned', int, lo=0, hi=10) me.setState('BatnaOwned', 0) self.world.defineState(me.name, 'agree', bool) me.setState('agree', False) # Actions me.addAction({'verb': 'do nothing'}) for amt in range(totals['apple'] + 1): tmp = me.addAction({ 'verb': 'offerApple', 'object': other.name, 'amount': amt }) me.setLegal( tmp, makeTree({ 'if': trueRow(stateKey(None, 'agreement')), False: { 'if': trueRow(stateKey(None, 'rejectedNegotiation')), True: False, False: True }, True: False })) for amt in range(totals['pear'] + 1): tmp = me.addAction({ 'verb': 'offerPear', 'object': other.name, 'amount': amt }) me.setLegal( tmp, makeTree({ 'if': trueRow(stateKey(None, 'agreement')), False: { 'if': trueRow(stateKey(None, 'rejectedNegotiation')), True: False, False: True }, True: False })) meReject = me.addAction({ 'verb': 'rejectNegotiation', 'object': other.name }) me.setLegal( meReject, makeTree({ 'if': trueRow(stateKey(None, 'agreement')), False: { 'if': trueRow(stateKey(None, 'rejectedNegotiation')), True: False, False: True }, True: False })) meAccept = me.addAction({ 'verb': 'accept offer', 'object': other.name }) me.setLegal( meAccept, makeTree({ 'if': trueRow(stateKey(None, 'appleOffer')), True: { 'if': trueRow(stateKey(None, 'pearOffer')), True: { 'if': trueRow(stateKey(None, 'agreement')), False: { 'if': trueRow(stateKey(None, 'rejectedNegotiation')), True: False, False: True }, True: False }, False: False }, False: False })) # Parameters me.setHorizon(6) me.setParameter('discount', 0.9) # Levels of belief david.setRecursiveLevel(3) stacy.setRecursiveLevel(3) # Turn order: Uncomment the following if you want agents to act in parallel # world.setOrder([{agts[0].name,agts[1].name}]) # Turn order: Uncomment the following if you want agents to act sequentially self.world.setOrder(turnOrder) # World state self.world.defineState(None, 'agreement', bool) self.world.setState(None, 'agreement', False) self.world.defineState(None, 'appleOffer', bool) self.world.setState(None, 'appleOffer', False) self.world.defineState(None, 'pearOffer', bool) self.world.setState(None, 'pearOffer', False) self.world.defineState( None, 'round', int, description='The current round of the negotiation') self.world.setState(None, 'round', 0) self.world.defineState( None, 'rejectedNegotiation', bool, description='Have one of the players walked out?') self.world.setState(None, 'rejectedNegotiation', False) # dont terminate so agent sees benefit of early agreement # world.addTermination(makeTree({'if': trueRow(stateKey(None,'agreement')), # True: True, # False: False})) # world.addTermination(makeTree({'if': trueRow(stateKey(None,'rejectedNegotiation')), # True: True, # False: False})) self.world.addTermination( makeTree({ 'if': thresholdRow(stateKey(None, 'round'), self.maxRounds), True: True, False: False })) # Dynamics of offers agents = [david.name, stacy.name] for i in range(2): for fruit in ['apple', 'pear']: atom = Action({ 'subject': agents[i], 'verb': 'offer%s' % (fruit.capitalize()), 'object': agents[1 - i] }) parties = [atom['subject'], atom['object']] for j in range(2): # Set offer amount offer = stateKey(parties[j], '%sOffered' % (fruit)) amount = actionKey('amount') if j == 1 else '%d-%s' % ( totals[fruit], actionKey('amount')) tree = makeTree(setToConstantMatrix(offer, amount)) self.world.setDynamics(parties[j], '%sOffered' % (fruit), atom, tree) # reset agree flags whenever an offer is made agreeFlag = stateKey(parties[j], 'agree') tree = makeTree(setFalseMatrix(agreeFlag)) self.world.setDynamics(parties[j], 'agree', atom, tree) # Offers set offer flag in world state tree = makeTree( setTrueMatrix(stateKey(None, '%sOffer' % (fruit)))) self.world.setDynamics(None, '%sOffer' % (fruit), atom, tree) # agents = [david.name,stacy.name] # Dynamics of agreements for i in range(2): atom = Action({ 'subject': agents[i], 'verb': 'accept offer', 'object': agents[1 - i] }) # accept offer sets accept tree = makeTree(setTrueMatrix(stateKey(atom['subject'], 'agree'))) self.world.setDynamics(atom['subject'], 'agree', atom, tree) # accept offer sets agreement if object has accepted tree = makeTree({ 'if': trueRow(stateKey(atom['object'], 'agree')), True: setTrueMatrix(stateKey(None, 'agreement')), False: noChangeMatrix(stateKey(None, 'agreement')) }) self.world.setDynamics(None, 'agreement', atom, tree) # Accepting offer sets ownership parties = [atom['subject'], atom['object']] for fruit in ['apple', 'pear']: # atom = Action({'subject': agents[i],'verb': 'accept offer', 'object': agents[1-i]}) for j in range(2): offer = stateKey(parties[j], '%sOffered' % (fruit)) owned = stateKey(parties[j], '%sOwned' % (fruit)) tree = makeTree({ 'if': trueRow(stateKey(atom['object'], 'agree')), False: noChangeMatrix(owned), True: setToFeatureMatrix(owned, offer) }) self.world.setDynamics(parties[j], '%sOwned' % (fruit), atom, tree) # rejecting give us batna and ends negotiation atom = Action({ 'subject': agents[i], 'verb': 'rejectNegotiation', 'object': agents[1 - i] }) tree = makeTree( setToFeatureMatrix(stateKey(atom['subject'], 'BatnaOwned'), stateKey(atom['subject'], 'Batna'))) self.world.setDynamics(atom['subject'], 'BatnaOwned', atom, tree) tree = makeTree( setToFeatureMatrix(stateKey(atom['object'], 'BatnaOwned'), stateKey(atom['object'], 'Batna'))) self.world.setDynamics(atom['object'], 'BatnaOwned', atom, tree) tree = makeTree( setTrueMatrix(stateKey(None, 'rejectedNegotiation'))) self.world.setDynamics(None, 'rejectedNegotiation', atom, tree) for action in stacy.actions | david.actions: tree = makeTree(incrementMatrix(stateKey(None, 'round'), 1)) self.world.setDynamics(None, 'round', action, tree) for agent in self.world.agents.values(): agent.addModel('pearLover', R={}, level=2, rationality=0.01) agent.addModel('appleLover', R={}, level=2, rationality=0.01)
def setup(): global args np.random.seed(args.seed) # create world and add agents world = World() world.memory = False world.parallel = args.parallel agents = [] agent_features = {} for ag in range(args.agents): agent = Agent('Agent' + str(ag)) world.addAgent(agent) agents.append(agent) # set agent's params agent.setAttribute('discount', 1) agent.setHorizon(args.horizon) # add features, initialize at random features = [] agent_features[agent] = features for f in range(args.features_agent): feat = world.defineState(agent.name, 'Feature{}'.format(f), int, lo=0, hi=1000) world.setFeature(feat, np.random.randint(0, MAX_FEATURE_VALUE)) features.append(feat) # set random reward function agent.setReward(maximizeFeature(np.random.choice(features), agent.name), 1) # add mental copy of true model and make it static (we do not have beliefs in the models) agent.addModel(get_fake_model_name(agent), parent=get_true_model_name(agent)) agent.setAttribute('static', True, get_fake_model_name(agent)) # add actions for ac in range(args.actions): action = agent.addAction({'verb': '', 'action': 'Action{}'.format(ac)}) i = ac while i + args.features_action < args.features_agent: weights = {} for j in range(args.features_action): weights[features[i + j + 1]] = 1 tree = makeTree(multi_set_matrix(features[i], weights)) world.setDynamics(features[i], action, tree) i += args.features_action # define order world.setOrder([set(ag.name for ag in agents)]) for agent in agents: # test belief update: # - set a belief in one feature to the actual initial value (should not change outcomes) # world.setModel(agent.name, Distribution({True: 1.0})) rand_feat = np.random.choice(agent_features[agent]) agent.setBelief(rand_feat, world.getValue(rand_feat)) print('{} will always observe {}={}'.format(agent.name, rand_feat, world.getValue(rand_feat))) # set mental model of each agent in all other agents for i in range(args.agents): for j in range(i + 1, args.agents): world.setMentalModel(agents[i].name, agents[j].name, Distribution({get_fake_model_name(agents[j]): 1})) world.setMentalModel(agents[j].name, agents[i].name, Distribution({get_fake_model_name(agents[i]): 1})) return world
__email__ = '*****@*****.**' __description__ = 'Example of how to discretize a feature\'s value in-place using a helper function. ' \ 'Discretization occurs by directly approximating the value of the feature to the closest bin from ' \ 'a discrete set of bins.' \ 'This method can be used to discretize features\' values at each timestep after world.update().' HIGH = 100 LOW = 50 NUM_BINS = 11 NUM_SAMPLES = 100 if __name__ == '__main__': # create world and add agent world = World() agent = Agent('Agent') world.addAgent(agent) # add feature to world feat = world.defineState(agent.name, 'x', float, lo=LOW, hi=HIGH) print('====================================') print('High:\t{}'.format(HIGH)) print('Low:\t{}'.format(LOW)) print('Bins:\t{}'.format(NUM_BINS)) print('\nSamples:') values_original = [] values_discrete = [] for i in range(NUM_SAMPLES): num = np.random.uniform(LOW, HIGH)
def createWorld(username='******', level=0, ability='good', explanation='none', embodiment='robot', acknowledgment='no', sequence=False, root='.', ext='xml', beliefs=True): """ Creates the initial PsychSim scenario and saves it @param username: name of user ID to use in filenames @param level: robot mission level to use as template @param ability: the level of the robot's ability - good or C{True}: perfect sensors and sensor model - badSensor or C{False}: noisy sensors, but perfect model of noisy sensors - badModel: perfect sensors, but imperfect model of sensors @type ability: bool @param explanation: the type of explanation to use - none: No explanations - ability: Explanation based on robot ability provided. - abilitybenevolence: Explanation based on both robot's ability and benevolence provided. @type explanation: str @param embodiment: the robot's embodiment - robot: The robot looks like a robot - dog: The robot looks like a dog @type embodiment: str @param acknowledgment: the robot's behavior regarding the acknowledgment of errors - no: The robot does not acknowledge its errors - yes: The robot acknowledges its errors @type acknowledgment: str @param root: the root directory to use for files (default is current working directory) @param ext: the file extension for the PsychSim scenario file - xml: Save as uncompressed XML - psy: Save as bzipped XML @type ext: str @param beliefs: if C{True}, store robot's uncertain beliefs in scenario file, rather than compute them on the fly. Storing in scenario file makes the scenario a more complete model, but greatly increases file sixe. Default is C{True} @type beliefs: bool """ print "**************************createWorld***********************" print 'Username:\t%s\nLevel:\t\t%s' % (username, level + 1) print 'Ability\t\t%s\nExplanation:\t%s\nEmbodiment:\t%s\nAcknowledge:\t%s' % \ (ability,explanation,embodiment,acknowledgment) # Pre-compute symbols for this level's waypoints for point in WAYPOINTS[level]: if not point.has_key('symbol'): point['symbol'] = point['name'].replace(' ', '') world = World() world.defineState( None, 'level', int, lo=0, hi=len(WAYPOINTS) - 1, description='Static variable indicating what mission level') world.setState(None, 'level', level) world.defineState(None, 'time', float) world.setState(None, 'time', 0.) world.defineState(None, 'complete', bool) world.setState(None, 'complete', False) world.addTermination( makeTree({ 'if': trueRow('complete'), True: True, False: False })) # Buildings threats = ['none', 'NBC', 'armed'] for waypoint in WAYPOINTS[level]: if not waypoint.has_key('symbol'): waypoint['symbol'] = waypoint['name'].replace(' ', '') world.addAgent(Agent(waypoint['symbol'])) # Have we visited this waypoint? key = world.defineState(waypoint['symbol'], 'visited', bool) world.setFeature(key, False) # Are there dangerous chemicals or armed people here? key = world.defineState(waypoint['symbol'], 'danger', list, threats[:]) if waypoint.has_key('NBC') and waypoint['NBC']: world.setFeature(key, 'NBC') elif waypoint.has_key('armed') and waypoint['armed']: world.setFeature(key, 'armed') else: world.setFeature(key, 'none') key = world.defineState(waypoint['symbol'], 'recommendation', list, ['none', 'protected', 'unprotected']) world.setFeature(key, 'none') # Human human = Agent('human') world.addAgent(human) world.defineState(human.name, 'alive', bool) human.setState('alive', True) world.defineState(human.name, 'deaths', int) human.setState('deaths', 0) # Robot robot = Agent('robot') world.addAgent(robot) # Robot states world.defineState(robot.name, 'waypoint', list, [point['symbol'] for point in WAYPOINTS[level]]) robot.setState('waypoint', WAYPOINTS[level][getStart(level)]['symbol']) world.defineState(robot.name, 'explanation', list, [ 'none', 'ability', 'abilitybenevolence', 'abilityconfidence', 'confidence' ]) robot.setState('explanation', explanation) world.defineState(robot.name, 'embodiment', list, ['robot', 'dog']) robot.setState('embodiment', embodiment) world.defineState(robot.name, 'acknowledgment', list, ['no', 'yes']) robot.setState('acknowledgment', acknowledgment) world.defineState(robot.name, 'ability', list, ['badSensor', 'badModel', 'good']) if ability is True: # Backward compatibility with boolean ability ability = 'good' elif ability is False: ability = 'badSensor' robot.setState('ability', ability) # State of the robot's sensors world.defineState(robot.name, 'sensorModel', list, ['good', 'bad']) robot.setState('sensorModel', 'good') world.defineState(robot.name, 'command', list, ['none'] + [point['symbol'] for point in WAYPOINTS[level]]) robot.setState('command', 'none') # Actions for end in range(len(WAYPOINTS[level])): symbol = WAYPOINTS[level][end]['symbol'] # Robot movement action = robot.addAction({'verb': 'moveto', 'object': symbol}) # Legal if no contradictory command tree = makeTree({ 'if': equalRow(stateKey(robot.name, 'command'), 'none'), True: True, False: { 'if': equalRow(stateKey(robot.name, 'command'), symbol), True: True, False: False } }) robot.setLegal(action, tree) # Dynamics of robot's location tree = makeTree( setToConstantMatrix(stateKey(action['subject'], 'waypoint'), symbol)) world.setDynamics(stateKey(action['subject'], 'waypoint'), action, tree) # Dynamics of visited flag key = stateKey(symbol, 'visited') tree = makeTree(setTrueMatrix(key)) world.setDynamics(key, action, tree) # Dynamics of time key = stateKey(None, 'time') tree = setToConstantMatrix(key, 0.) for start in range(len(WAYPOINTS[level])): if start != end: startsymbol = WAYPOINTS[level][start]['symbol'] if sequence: # Distance is measured by level sequence distance = abs(start - end) * 50 else: try: distance = DISTANCES[WAYPOINTS[level][start]['name']][ WAYPOINTS[level][end]['name']] except KeyError: try: distance = DISTANCES[WAYPOINTS[level][end][ 'name']][WAYPOINTS[level][start]['name']] except KeyError: distance = 250 tree = { 'if': equalRow(stateKey(action['subject'], 'waypoint'), startsymbol), True: setToConstantMatrix(key, float(distance) / 1000.), False: tree } world.setDynamics(key, action, makeTree(tree)) # Human entry: Dead or alive if unprotected? key = stateKey(human.name, 'alive') action = robot.addAction({ 'verb': 'recommend unprotected', 'object': symbol }) tree = makeTree({ 'if': equalRow(stateKey(symbol, 'danger'), 'none'), True: setTrueMatrix(key), False: setFalseMatrix(key) }) world.setDynamics(key, action, tree) robot.setLegal(action, makeTree(False)) # Human entry: How much "time" if protected? action = robot.addAction({ 'verb': 'recommend protected', 'object': symbol }) key = stateKey(None, 'time') world.setDynamics(key, action, makeTree(setToConstantMatrix(key, 0.25))) robot.setLegal(action, makeTree(False)) # Robot goals goal = minimizeFeature(stateKey(None, 'time')) robot.setReward(goal, 2.) goal = maximizeFeature(stateKey(human.name, 'alive')) robot.setReward(goal, 1.) for point in WAYPOINTS[level]: robot.setReward(maximizeFeature(stateKey(point['symbol'], 'visited')), 1.) if beliefs: # omega = 'danger' world.defineVariable(robot.name, ActionSet) # Robot beliefs world.setModel(robot.name, True) value = 1. / float(len(WAYPOINTS[level])) # tree = KeyedVector({CONSTANT: world.value2float(omega,'none')}) for index in range(len(WAYPOINTS[level])): waypoint = WAYPOINTS[level][index] key = stateKey(waypoint['symbol'], 'danger') # if index > 0: # Starting state is safe robot.setBelief( key, psychsim.probability.Distribution({ 'NBC': value / 2., 'armed': value / 2., 'none': 1. - value })) # Observation function # tree = {'if': equalRow(stateKey(robot.name,'waypoint'),waypoint['symbol']), # True: generateO(world,key), # False: tree} # robot.defineObservation(omega,makeTree(tree),domain=list,lo=['none','NBC','armed']) robot.defineObservation('microphone', makeTree(None), None, domain=list, lo=['nobody', 'friendly', 'suspicious']) robot.defineObservation('NBCsensor', makeTree(None), None, domain=bool) robot.defineObservation('camera', makeTree(None), None, domain=bool) else: robot.defineObservation('microphone', makeTree(None), None, domain=list, lo=['nobody', 'friendly', 'suspicious']) robot.defineObservation('NBCsensor', makeTree(None), None, domain=bool) robot.defineObservation('camera', makeTree(None), None, domain=bool) robot.setAttribute('horizon', 1) world.setOrder([robot.name]) filename = getFilename(username, level, ext, root) world.save(filename, ext == 'psy') WriteLogData('%s user %s, level %d, ability %s, explanation %s' % \ (CREATE_TAG,username,level,ability,explanation),username,level,root=root) return world
def __init__(self, turnOrder, maxRounds, payoff): self.maxRounds = maxRounds self.payoff = payoff print self.payoff self.world = World() stacy = Agent('Stacy') david = Agent('David') agts = [stacy, david] # Player state, actions and parameters common to both players for i in range(2): me = agts[i] other = agts[1 - i] self.world.addAgent(me) # State self.world.defineState(me.name, 'money', int) me.setState('money', 0) mePass = me.addAction({'verb': 'pass', 'object': other.name}) meTake = me.addAction({'verb': 'take', 'object': other.name}) # Parameters me.setHorizon(6) me.setParameter('discount', 1.) # me.setParameter('discount',0.9) # Levels of belief david.setRecursiveLevel(3) stacy.setRecursiveLevel(3) self.world.setOrder(turnOrder) # World state self.world.defineState(None, 'round', int, description='The current round') self.world.setState(None, 'round', 0) self.world.defineState(None, 'gameOver', bool, description='whether game is over') self.world.setState(None, 'gameOver', False) self.world.addTermination( makeTree({ 'if': thresholdRow(stateKey(None, 'round'), self.maxRounds), True: True, False: { 'if': trueRow(stateKey(None, 'gameOver')), True: True, False: False } })) # Dynamics for action in stacy.actions | david.actions: tree = makeTree(incrementMatrix(stateKey(None, 'round'), 1)) self.world.setDynamics(None, 'round', action, tree) if (action['verb'] == 'take'): tree = makeTree(setTrueMatrix(stateKey(None, 'gameOver'))) self.world.setDynamics(None, 'gameOver', action, tree) agts = ['Stacy', 'David'] for i in range(2): key = stateKey(agts[i], 'money') tree = makeTree( self.buildPayoff(0, key, self.payoff[agts[i]])) self.world.setDynamics(agts[i], 'money', action, tree) elif action['verb'] == 'pass': agts = ['Stacy', 'David'] for i in range(2): key = stateKey(agts[i], 'money') tree = makeTree({ 'if': equalRow(stateKey(None, 'round'), self.maxRounds - 1), True: setToConstantMatrix( key, self.payoff[agts[i]][self.maxRounds]), False: noChangeMatrix(key) }) self.world.setDynamics(agts[i], 'money', action, tree) # really need to ask david about these levels - if adding modesl with levels, can # the true model point to these but have a different level for agent in self.world.agents.values(): agent.addModel('Christian', R={}, level=2, rationality=10., selection='distribution') agent.addModel('Capitalist', R={}, level=2, rationality=10., selection='distribution')
def scenarioCreationUseCase(enemy='Sylvania',model='powell',web=False, fCollapse=None,sCollapse=None,maxRounds=15): """ An example of how to create a scenario @param enemy: the name of the agent-controlled side, i.e., Freedonia's opponent (default: Sylvania) @type enemy: str @param model: which model do we use (default is "powell") @type model: powell or slantchev @param web: if C{True}, then create the web-based experiment scenario (default: C{False}) @type web: bool @param fCollapse: the probability that Freedonia collapses (under powell, default: 0.1) or loses battle (under slantchev, default: 0.7) @type fCollapse: float @param sCollapse: the probability that Sylvania collapses, under powell (default: 0.1) @type sCollapse: float @param maxRounds: the maximum number of game rounds (default: 15) @type maxRounds: int @return: the scenario created @rtype: L{World} """ # Handle defaults for battle probabilities, under each model posLo = 0 posHi = 10 if fCollapse is None: if model == 'powell': fCollapse = 0.1 elif model == 'slantchev': fCollapse = 0.7 if sCollapse is None: sCollapse = 0.1 # Create scenario world = World() # Agents free = Agent('Freedonia') world.addAgent(free) sylv = Agent(enemy) world.addAgent(sylv) # User state world.defineState(free.name,'troops',int,lo=0,hi=50000, description='Number of troops you have left') free.setState('troops',40000) world.defineState(free.name,'territory',int,lo=0,hi=100, description='Percentage of disputed territory owned by you') free.setState('territory',15) world.defineState(free.name,'cost',int,lo=0,hi=50000, description='Number of troops %s loses in an attack' % (free.name)) free.setState('cost',2000) world.defineState(free.name,'position',int,lo=posLo,hi=posHi, description='Current status of war (%d=%s is winner, %d=you are winner)' % (posLo,sylv.name,posHi)) free.setState('position',5) world.defineState(free.name,'offered',int,lo=0,hi=100, description='Percentage of disputed territory that %s last offered to you' % (sylv.name)) free.setState('offered',0) if model == 'slantchev': # Compute new value for territory only *after* computing new value for position world.addDependency(stateKey(free.name,'territory'),stateKey(free.name,'position')) # Agent state world.defineState(sylv.name,'troops',int,lo=0,hi=500000, description='Number of troops %s has left' % (sylv.name)) sylv.setState('troops',30000) world.defineState(sylv.name,'cost',int,lo=0,hi=50000, description='Number of troops %s loses in an attack' % (sylv.name)) sylv.setState('cost',2000) world.defineState(sylv.name,'offered',int,lo=0,hi=100, description='Percentage of disputed territory that %s last offered to %s' % (free.name,sylv.name)) sylv.setState('offered',0) # World state world.defineState(None,'treaty',bool, description='Have the two sides reached an agreement?') world.setState(None,'treaty',False) # Stage of negotiation, illustrating the use of an enumerated state feature world.defineState(None,'phase',list,['offer','respond','rejection','end','paused','engagement'], description='The current stage of the negotiation game') world.setState(None,'phase','paused') # Game model, static descriptor world.defineState(None,'model',list,['powell','slantchev'], description='The model underlying the negotiation game') world.setState(None,'model',model) # Round of negotiation world.defineState(None,'round',int,description='The current round of the negotiation') world.setState(None,'round',0) if not web: # Relationship value key = world.defineRelation(free.name,sylv.name,'trusts') world.setFeature(key,0.) # Game over if there is a treaty world.addTermination(makeTree({'if': trueRow(stateKey(None,'treaty')), True: True, False: False})) # Game over if Freedonia has no territory world.addTermination(makeTree({'if': thresholdRow(stateKey(free.name,'territory'),1), True: False, False: True}) ) # Game over if Freedonia has all the territory world.addTermination(makeTree({'if': thresholdRow(stateKey(free.name,'territory'),99), True: True, False: False})) # Game over if number of rounds exceeds limit world.addTermination(makeTree({'if': thresholdRow(stateKey(None,'round'),maxRounds), True: True, False: False})) # Turn order: Uncomment the following if you want agents to act in parallel # world.setOrder([set(world.agents.keys())]) # Turn order: Uncomment the following if you want agents to act sequentially world.setOrder([free.name,sylv.name]) # User actions freeBattle = free.addAction({'verb': 'attack','object': sylv.name}) for amount in range(20,100,20): free.addAction({'verb': 'offer','object': sylv.name,'amount': amount}) if model == 'powell': # Powell has null stages freeNOP = free.addAction({'verb': 'continue'}) elif model == 'slantchev': # Slantchev has both sides receiving offers free.addAction({'verb': 'accept offer','object': sylv.name}) free.addAction({'verb': 'reject offer','object': sylv.name}) # Agent actions sylvBattle = sylv.addAction({'verb': 'attack','object': free.name}) sylvAccept = sylv.addAction({'verb': 'accept offer','object': free.name}) sylvReject = sylv.addAction({'verb': 'reject offer','object': free.name}) if model == 'powell': # Powell has null stages sylvNOP = sylv.addAction({'verb': 'continue'}) elif model == 'slantchev': # Slantchev has both sides making offers for amount in range(10,100,10): sylv.addAction({'verb': 'offer','object': free.name,'amount': amount}) # Restrictions on when actions are legal, based on phase of game for action in filterActions({'verb': 'offer'},free.actions | sylv.actions): agent = world.agents[action['subject']] agent.setLegal(action,makeTree({'if': equalRow(stateKey(None,'phase'),'offer'), True: True, # Offers are legal in the offer phase False: False})) # Offers are illegal in all other phases if model == 'powell': # Powell has a special rejection phase for action in [freeNOP,freeBattle]: free.setLegal(action,makeTree({'if': equalRow(stateKey(None,'phase'),'rejection'), True: True, # Attacking and doing nothing are legal only in rejection phase False: False})) # Attacking and doing nothing are illegal in all other phases # Once offered, agent can respond if model == 'powell': # Under Powell, only Sylvania has to respond, and it can attack responses = [sylvBattle,sylvAccept,sylvReject] elif model == 'slantchev': # Under Slantchev, only accept/reject responses = filterActions({'verb': 'accept offer'},free.actions | sylv.actions) responses += filterActions({'verb': 'reject offer'},free.actions | sylv.actions) for action in responses: agent = world.agents[action['subject']] agent.setLegal(action,makeTree({'if': equalRow(stateKey(None,'phase'),'respond'), True: True, # Offeree must act in the response phase False: False})) # Offeree cannot act in any other phase if model == 'powell': # NOP is legal in exactly opposite situations to all other actions sylv.setLegal(sylvNOP,makeTree({'if': equalRow(stateKey(None,'phase'),'end'), True: True, # Sylvania does not do anything in the null phase after Freedonia responds to rejection False: False})) # Sylvania must act in its other phases if model == 'slantchev': # Attacking legal only under engagement phase for action in filterActions({'verb': 'attack'},free.actions | sylv.actions): agent = world.agents[action['subject']] agent.setLegal(action,makeTree({'if': equalRow(stateKey(None,'phase'),'engagement'), True: True, # Attacking legal only in engagement False: False})) # Attacking legal every other phase # Goals for Freedonia goalFTroops = maximizeFeature(stateKey(free.name,'troops')) free.setReward(goalFTroops,1.) goalFTerritory = maximizeFeature(stateKey(free.name,'territory')) free.setReward(goalFTerritory,1.) # Goals for Sylvania goalSTroops = maximizeFeature(stateKey(sylv.name,'troops')) sylv.setReward(goalSTroops,1.) goalSTerritory = minimizeFeature(stateKey(free.name,'territory')) sylv.setReward(goalSTerritory,1.) # Possible goals applicable to both goalAgreement = maximizeFeature(stateKey(None,'treaty')) # Silly goal, provided as an example of an achievement goal goalAchieve = achieveFeatureValue(stateKey(None,'phase'),'respond') # Horizons if model == 'powell': free.setAttribute('horizon',4) sylv.setAttribute('horizon',4) elif model == 'slantchev': free.setAttribute('horizon',6) sylv.setAttribute('horizon',6) # Discount factors free.setAttribute('discount',-1) sylv.setAttribute('discount',-1) # Levels of belief free.setRecursiveLevel(2) sylv.setRecursiveLevel(2) # Dynamics of battle freeTroops = stateKey(free.name,'troops') freeTerr = stateKey(free.name,'territory') sylvTroops = stateKey(sylv.name,'troops') # Effect of fighting for action in filterActions({'verb': 'attack'},free.actions | sylv.actions): # Effect on troops (cost of battle) tree = makeTree(addFeatureMatrix(freeTroops,stateKey(free.name,'cost'),-1.)) world.setDynamics(freeTroops,action,tree,enforceMin=not web) tree = makeTree(addFeatureMatrix(sylvTroops,stateKey(sylv.name,'cost'),-1.)) world.setDynamics(sylvTroops,action,tree,enforceMin=not web) if model == 'powell': # Effect on territory (probability of collapse) tree = makeTree({'distribution': [ ({'distribution': [(setToConstantMatrix(freeTerr,100),1.-fCollapse), # Sylvania collapses, Freedonia does not (noChangeMatrix(freeTerr), fCollapse)]}, # Both collapse sCollapse), ({'distribution': [(setToConstantMatrix(freeTerr,0),fCollapse), # Freedonia collapses, Sylvania does not (noChangeMatrix(freeTerr), 1.-fCollapse)]}, # Neither collapses 1.-sCollapse)]}) world.setDynamics(freeTerr,action,tree) elif model == 'slantchev': # Effect on position pos = stateKey(free.name,'position') tree = makeTree({'distribution': [(incrementMatrix(pos,1),1.-fCollapse), # Freedonia wins battle (incrementMatrix(pos,-1),fCollapse)]}) # Freedonia loses battle world.setDynamics(pos,action,tree) # Effect on territory tree = makeTree({'if': thresholdRow(pos,posHi-.5), True: setToConstantMatrix(freeTerr,100), # Freedonia won False: {'if': thresholdRow(pos,posLo+.5), True: noChangeMatrix(freeTerr), False: setToConstantMatrix(freeTerr,0)}}) # Freedonia lost world.setDynamics(freeTerr,action,tree) # Dynamics of offers for index in range(2): atom = Action({'subject': world.agents.keys()[index],'verb': 'offer', 'object': world.agents.keys()[1-index]}) if atom['subject'] == free.name or model != 'powell': offer = stateKey(atom['object'],'offered') amount = actionKey('amount') tree = makeTree({'if': trueRow(stateKey(None,'treaty')), True: noChangeMatrix(offer), False: setToConstantMatrix(offer,amount)}) world.setDynamics(offer,atom,tree,enforceMax=not web) # Dynamics of treaties for action in filterActions({'verb': 'accept offer'},free.actions | sylv.actions): # Accepting an offer means that there is now a treaty key = stateKey(None,'treaty') tree = makeTree(setTrueMatrix(key)) world.setDynamics(key,action,tree) # Accepting offer sets territory offer = stateKey(action['subject'],'offered') territory = stateKey(free.name,'territory') if action['subject'] == free.name: # Freedonia accepts sets territory to last offer tree = makeTree(setToFeatureMatrix(territory,offer)) world.setDynamics(freeTerr,action,tree) else: # Sylvania accepts sets territory to 1-last offer tree = makeTree(setToFeatureMatrix(territory,offer,pct=-1.,shift=100.)) world.setDynamics(freeTerr,action,tree) # Dynamics of phase phase = stateKey(None,'phase') roundKey = stateKey(None,'round') # OFFER -> RESPOND for index in range(2): action = Action({'subject': world.agents.keys()[index],'verb': 'offer', 'object': world.agents.keys()[1-index]}) if action['subject'] == free.name or model != 'powell': tree = makeTree(setToConstantMatrix(phase,'respond')) world.setDynamics(phase,action,tree) # RESPOND -> REJECTION or ENGAGEMENT for action in filterActions({'verb': 'reject offer'},free.actions | sylv.actions): if model == 'powell': tree = makeTree(setToConstantMatrix(phase,'rejection')) elif model == 'slantchev': tree = makeTree(setToConstantMatrix(phase,'engagement')) world.setDynamics(phase,action,tree) # accepting -> OFFER for action in filterActions({'verb': 'accept offer'},free.actions | sylv.actions): tree = makeTree(setToConstantMatrix(phase,'offer')) world.setDynamics(phase,action,tree) # attacking -> OFFER for action in filterActions({'verb': 'attack'},free.actions | sylv.actions): tree = makeTree(setToConstantMatrix(phase,'offer')) world.setDynamics(phase,action,tree) if action['subject'] == sylv.name or model == 'slantchev': tree = makeTree(incrementMatrix(roundKey,1)) world.setDynamics(roundKey,action,tree) if model == 'powell': # REJECTION -> END for atom in [freeNOP,freeBattle]: tree = makeTree(setToConstantMatrix(phase,'end')) world.setDynamics(phase,atom,tree) # END -> OFFER atom = Action({'subject': sylv.name,'verb': 'continue'}) tree = makeTree(setToConstantMatrix(phase,'offer')) world.setDynamics(phase,atom,tree) tree = makeTree(incrementMatrix(roundKey,1)) world.setDynamics(roundKey,atom,tree) if not web: # Relationship dynamics: attacking is bad for trust atom = Action({'subject': sylv.name,'verb': 'attack','object': free.name}) key = binaryKey(free.name,sylv.name,'trusts') tree = makeTree(approachMatrix(key,0.1,-1.)) world.setDynamics(key,atom,tree) # Handcrafted policy for Freedonia # free.setPolicy(makeTree({'if': equalRow('phase','respond'), # # Accept an offer greater than 50 # True: {'if': thresholdRow(stateKey(free.name,'offered'),50), # True: Action({'subject': free.name,'verb': 'accept offer','object': sylv.name}), # False: Action({'subject': free.name,'verb': 'reject offer','object': sylv.name})}, # False: {'if': equalRow('phase','engagement'), # # Attack during engagement phase # True: Action({'subject': free.name,'verb': 'attack','object': sylv.name}), # # Agent decides how what to do otherwise # False: False}})) # Mental models of enemy # Example of creating a model with incorrect reward all at once (a version of Freedonia who cares about reaching agreement as well) # sylv.addModel('false',R={goalSTroops: 10.,goalSTerritory: 1.,goalAgreement: 1.}, # rationality=1.,selection='distribution',parent=True) # Example of creating a model with incorrect beliefs sylv.addModel('false',rationality=10.,selection='distribution',parent=True) key = stateKey(free.name,'position') # Sylvania believes position to be fixed at 3 sylv.setBelief(key,3,'false') # Freedonia is truly unsure about position (50% chance of being 7, 50% of being 3) world.setModel(free.name,True) free.setBelief(key,Distribution({7: 0.5,3: 0.5}),True) # Observations about military position tree = makeTree({'if': thresholdRow(key,1), True: {'if': thresholdRow(key,9), True: {'distribution': [(KeyedVector({key: 1}),0.9), (KeyedVector({key: 1,CONSTANT: -1}),0.1)]}, False: {'distribution': [(KeyedVector({key: 1}),0.8), (KeyedVector({key: 1,CONSTANT: -1}),0.1), (KeyedVector({key: 1,CONSTANT: 1}),0.1)]}}, False: {'distribution': [(KeyedVector({key: 1}),0.9), (KeyedVector({key: 1,CONSTANT: 1}),0.1)]}}) free.defineObservation(key,tree) # Example of setting model parameters separately sylv.addModel('true',parent=True) sylv.setAttribute('rationality',10.,'true') # Override real agent's rationality with this value sylv.setAttribute('selection','distribution','true') world.setMentalModel(free.name,sylv.name,{'false': 0.9,'true': 0.1}) # Goal of fooling Sylvania goalDeception = achieveFeatureValue(modelKey(sylv.name),sylv.model2index('false')) return world
import sys from ConfigParser import SafeConfigParser from optparse import OptionParser from psychsim.pwl import * from psychsim.action import Action, ActionSet from psychsim.world import World, stateKey, actionKey from psychsim.agent import Agent if __name__ == '__main__': # Create scenario maxRounds = 8 world = World() totals = {'scotch': 1, 'tequila': 1} # 1 and 1 stacy = Agent('Stacy') david = Agent('David') agts = [stacy, david] # Player state, actions and parameters common to both players for i in range(2): me = agts[i] other = agts[1 - i] world.addAgent(me) # State world.defineState(me.name, 'scotchOwned', int, lo=0, hi=totals['scotch']) me.setState('scotchOwned', 0)
def __init__(self): self.world = World() stacy = Agent('Stacy') david = Agent('David') agts = [stacy, david] totalAmt = 4 # Player state, actions and parameters common to both players for i in range(2): me = agts[i] other = agts[1 - i] self.world.addAgent(me) self.world.defineState(me.name, 'offered', int, lo=0, hi=totalAmt) self.world.defineState(me.name, 'money', int, lo=0, hi=totalAmt) me.setState('offered', 0) me.setState('money', 0) if (me.name == 'Stacy'): for amt in range(totalAmt + 1): me.addAction({ 'verb': 'offer', 'object': other.name, 'amount': amt }) else: mePass = me.addAction({'verb': 'accept', 'object': other.name}) mePass = me.addAction({'verb': 'reject', 'object': other.name}) # Parameters me.setHorizon(2) me.setParameter('discount', 0.9) # me.setParameter('discount',1.0) # Levels of belief david.setRecursiveLevel(3) stacy.setRecursiveLevel(3) self.world.setOrder(['Stacy', 'David']) # World state self.world.defineState(None, 'gameOver', bool, description='The current round') self.world.setState(None, 'gameOver', False) self.world.addTermination( makeTree({ 'if': trueRow(stateKey(None, 'gameOver')), True: True, False: False })) # offer dynamics atom = Action({'subject': 'Stacy', 'verb': 'offer', 'object': 'David'}) parties = [atom['subject'], atom['object']] for j in range(2): offer = stateKey(parties[j], 'offered') amount = actionKey('amount') if j == 1 else '%d-%s' % ( totalAmt, actionKey('amount')) tree = makeTree(setToConstantMatrix(offer, amount)) self.world.setDynamics(parties[j], 'offered', atom, tree) # accept dynamics atom = Action({ 'subject': 'David', 'verb': 'accept', 'object': 'Stacy' }) parties = [atom['subject'], atom['object']] for j in range(2): offer = stateKey(parties[j], 'offered') money = stateKey(parties[j], 'money') tree = makeTree(setToFeatureMatrix(money, offer)) self.world.setDynamics(parties[j], 'money', atom, tree) tree = makeTree(setTrueMatrix(stateKey(None, 'gameOver'))) self.world.setDynamics(None, 'gameOver', atom, tree) # reject dynamics atom = Action({ 'subject': 'David', 'verb': 'reject', 'object': 'Stacy' }) tree = makeTree(setTrueMatrix(stateKey(None, 'gameOver'))) self.world.setDynamics(None, 'gameOver', atom, tree) # really need to ask david about these levels - if adding modesl with levels, can # the true model point to these but have a different level for agent in self.world.agents.values(): agent.addModel('Christian', R={}, level=2, rationality=25., selection='distribution') agent.addModel('Capitalist', R={}, level=2, rationality=25., selection='distribution')
def __init__(self,turnOrder): self.maxRounds=8 self.world = World() totals = {'apple':1,'pear':2} batna_prePref = totals['apple'] + totals['pear'] stacy = Agent('Stacy') david = Agent('David') agts = [stacy, david] # Player state, actions and parameters common to both players for i in range(2): me = agts[i] other = agts[1-i] self.world.addAgent(me) # State self.world.defineState(me.name,'appleOwned',int,lo=0,hi=totals['apple']) me.setState('appleOwned',0) self.world.defineState(me.name,'appleOffered',int,lo=0,hi=totals['apple']) me.setState('appleOffered',0) self.world.defineState(me.name,'pearOwned',int,lo=0,hi=totals['pear']) me.setState('pearOwned',0) self.world.defineState(me.name,'pearOffered',int,lo=0,hi=totals['pear']) me.setState('pearOffered',0) self.world.defineState(me.name,'Batna',int,lo=0,hi=10) me.setState('Batna', batna_prePref) self.world.defineState(me.name,'BatnaOwned',int,lo=0,hi=10) me.setState('BatnaOwned',0) self.world.defineState(me.name,'agree',bool) me.setState('agree',False) # Actions me.addAction({'verb': 'do nothing'}) for amt in range(totals['apple'] + 1): tmp = me.addAction({'verb': 'offerApple','object': other.name,'amount': amt}) me.setLegal(tmp,makeTree({'if': trueRow(stateKey(None, 'agreement')), False: {'if': trueRow(stateKey(None, 'rejectedNegotiation')), True: False, False: True}, True: False})) for amt in range(totals['pear'] + 1): tmp = me.addAction({'verb': 'offerPear','object': other.name,'amount': amt}) me.setLegal(tmp,makeTree({'if': trueRow(stateKey(None, 'agreement')), False: {'if': trueRow(stateKey(None, 'rejectedNegotiation')), True: False, False: True}, True: False})) meReject = me.addAction({'verb': 'rejectNegotiation','object': other.name}) me.setLegal(meReject,makeTree({'if': trueRow(stateKey(None, 'agreement')), False: {'if': trueRow(stateKey(None, 'rejectedNegotiation')), True: False, False: True}, True: False})) meAccept = me.addAction({'verb': 'accept offer','object': other.name}) me.setLegal(meAccept,makeTree({'if': trueRow(stateKey(None, 'appleOffer')), True: {'if': trueRow(stateKey(None, 'pearOffer')), True: {'if': trueRow(stateKey(None, 'agreement')), False: {'if': trueRow(stateKey(None, 'rejectedNegotiation')), True: False, False: True}, True: False}, False: False}, False: False})) # Parameters me.setHorizon(6) me.setParameter('discount',0.9) # Levels of belief david.setRecursiveLevel(3) stacy.setRecursiveLevel(3) # Turn order: Uncomment the following if you want agents to act in parallel # world.setOrder([{agts[0].name,agts[1].name}]) # Turn order: Uncomment the following if you want agents to act sequentially self.world.setOrder(turnOrder) # World state self.world.defineState(None,'agreement',bool) self.world.setState(None,'agreement',False) self.world.defineState(None,'appleOffer',bool) self.world.setState(None,'appleOffer',False) self.world.defineState(None,'pearOffer',bool) self.world.setState(None,'pearOffer',False) self.world.defineState(None,'round',int,description='The current round of the negotiation') self.world.setState(None,'round',0) self.world.defineState(None,'rejectedNegotiation',bool, description='Have one of the players walked out?') self.world.setState(None, 'rejectedNegotiation', False) # dont terminate so agent sees benefit of early agreement # world.addTermination(makeTree({'if': trueRow(stateKey(None,'agreement')), # True: True, # False: False})) # world.addTermination(makeTree({'if': trueRow(stateKey(None,'rejectedNegotiation')), # True: True, # False: False})) self.world.addTermination(makeTree({'if': thresholdRow(stateKey(None,'round'),self.maxRounds), True: True, False: False})) # Dynamics of offers agents = [david.name,stacy.name] for i in range(2): for fruit in ['apple','pear']: atom = Action({'subject': agents[i],'verb': 'offer%s' % (fruit.capitalize()), 'object': agents[1-i]}) parties = [atom['subject'], atom['object']] for j in range(2): # Set offer amount offer = stateKey(parties[j],'%sOffered' % (fruit)) amount = actionKey('amount') if j == 1 else '%d-%s' % (totals[fruit],actionKey('amount')) tree = makeTree(setToConstantMatrix(offer,amount)) self.world.setDynamics(parties[j],'%sOffered' % (fruit),atom,tree) # reset agree flags whenever an offer is made agreeFlag = stateKey(parties[j],'agree') tree = makeTree(setFalseMatrix(agreeFlag)) self.world.setDynamics(parties[j],'agree',atom,tree) # Offers set offer flag in world state tree = makeTree(setTrueMatrix(stateKey(None,'%sOffer' % (fruit)))) self.world.setDynamics(None,'%sOffer' % (fruit) ,atom,tree) # agents = [david.name,stacy.name] # Dynamics of agreements for i in range(2): atom = Action({'subject': agents[i],'verb': 'accept offer', 'object': agents[1-i]}) # accept offer sets accept tree = makeTree(setTrueMatrix(stateKey(atom['subject'],'agree'))) self.world.setDynamics(atom['subject'],'agree',atom,tree) # accept offer sets agreement if object has accepted tree = makeTree({'if': trueRow(stateKey(atom['object'],'agree')), True: setTrueMatrix(stateKey(None,'agreement')), False: noChangeMatrix(stateKey(None,'agreement'))}) self.world.setDynamics(None,'agreement',atom,tree) # Accepting offer sets ownership parties = [atom['subject'], atom['object']] for fruit in ['apple','pear']: # atom = Action({'subject': agents[i],'verb': 'accept offer', 'object': agents[1-i]}) for j in range(2): offer = stateKey(parties[j],'%sOffered' % (fruit)) owned = stateKey(parties[j],'%sOwned' % (fruit)) tree = makeTree({'if': trueRow(stateKey(atom['object'],'agree')), False: noChangeMatrix(owned), True: setToFeatureMatrix(owned,offer)}) self.world.setDynamics(parties[j],'%sOwned' % (fruit),atom,tree) # rejecting give us batna and ends negotiation atom = Action({'subject': agents[i],'verb': 'rejectNegotiation', 'object': agents[1-i]}) tree = makeTree(setToFeatureMatrix(stateKey(atom['subject'],'BatnaOwned') ,stateKey(atom['subject'], 'Batna'))) self.world.setDynamics(atom['subject'],'BatnaOwned' ,atom,tree) tree = makeTree(setToFeatureMatrix(stateKey(atom['object'],'BatnaOwned') ,stateKey(atom['object'], 'Batna'))) self.world.setDynamics(atom['object'],'BatnaOwned' ,atom,tree) tree = makeTree(setTrueMatrix(stateKey(None,'rejectedNegotiation'))) self.world.setDynamics(None,'rejectedNegotiation' ,atom,tree) for action in stacy.actions | david.actions: tree = makeTree(incrementMatrix(stateKey(None,'round'),1)) self.world.setDynamics(None,'round',action,tree) for agent in self.world.agents.values(): agent.addModel('pearLover',R={},level=2,rationality=0.01) agent.addModel('appleLover',R={},level=2,rationality=0.01)
AGENT1_ID = 'Agent 1' AGENT2_ID = 'Agent 2' if __name__ == '__main__': # turn orders turn_orders = { 'First increment, then copy': [AGENT1_ID, AGENT2_ID], 'First copy, then increment': [AGENT2_ID, AGENT1_ID], 'Simult. increment and copy': [{AGENT1_ID, AGENT2_ID}] } for label, turn_order in turn_orders.items(): agent1 = Agent(AGENT1_ID) agent2 = Agent(AGENT2_ID) # create world and add agents world = World() world.addAgent(agent1) world.addAgent(agent2) # add variables var_counter = world.defineState(agent1.name, 'counter', int, lo=0, hi=3) var_copy = world.defineState(agent2.name, 'counter_copy',
from psychsim.pwl import * from psychsim.action import Action,ActionSet from psychsim.world import World,stateKey,actionKey from psychsim.agent import Agent if __name__ == '__main__': # Create scenario maxRounds=8 world = World() totals = {'apple':1,'pear':2} batna_prePref = totals['apple'] + totals['pear'] stacy = Agent('Stacy') david = Agent('David') agts = [stacy, david] # Player state, actions and parameters common to both players for i in range(2): me = agts[i] other = agts[1-i] world.addAgent(me) # State world.defineState(me.name,'appleOwned',int,lo=0,hi=totals['apple']) me.setState('appleOwned',0) world.defineState(me.name,'appleOffered',int,lo=0,hi=totals['apple']) me.setState('appleOffered',0) world.defineState(me.name,'pearOwned',int,lo=0,hi=totals['pear']) me.setState('pearOwned',0)
from optparse import OptionParser from psychsim.pwl import * from psychsim.action import Action,ActionSet from psychsim.world import World,stateKey,actionKey from psychsim.agent import Agent if __name__ == '__main__': # Create scenario world = World() totals = {'apple':3,'pear':2} # Stacy state stacy = Agent('Stacy') world.addAgent(stacy) world.defineState(stacy.name,'applesOwned',int,lo=0,hi=totals['apple']) stacy.setState('applesOwned',0) world.defineState(stacy.name,'applesOffered',int,lo=0,hi=totals['apple']) stacy.setState('applesOffered',0) world.defineState(stacy.name,'pearsOwned',int,lo=0,hi=totals['pear']) stacy.setState('pearsOwned',0) world.defineState(stacy.name,'pearsOffered',int,lo=0,hi=totals['pear']) stacy.setState('pearsOffered',0) # David state david = Agent('David') world.addAgent(david)
def createWorld(username='******',level=0,ability='good',explanation='none', embodiment='robot',acknowledgment='no',sequence=False, root='.',ext='xml',beliefs=True): """ Creates the initial PsychSim scenario and saves it @param username: name of user ID to use in filenames @param level: robot mission level to use as template @param ability: the level of the robot's ability - good or C{True}: perfect sensors and sensor model - badSensor or C{False}: noisy sensors, but perfect model of noisy sensors - badModel: perfect sensors, but imperfect model of sensors @type ability: bool @param explanation: the type of explanation to use - none: No explanations - ability: Explanation based on robot ability provided. - abilitybenevolence: Explanation based on both robot's ability and benevolence provided. @type explanation: str @param embodiment: the robot's embodiment - robot: The robot looks like a robot - dog: The robot looks like a dog @type embodiment: str @param acknowledgment: the robot's behavior regarding the acknowledgment of errors - no: The robot does not acknowledge its errors - yes: The robot acknowledges its errors @type acknowledgment: str @param root: the root directory to use for files (default is current working directory) @param ext: the file extension for the PsychSim scenario file - xml: Save as uncompressed XML - psy: Save as bzipped XML @type ext: str @param beliefs: if C{True}, store robot's uncertain beliefs in scenario file, rather than compute them on the fly. Storing in scenario file makes the scenario a more complete model, but greatly increases file sixe. Default is C{True} @type beliefs: bool """ print "**************************createWorld***********************" print 'Username:\t%s\nLevel:\t\t%s' % (username,level+1) print 'Ability\t\t%s\nExplanation:\t%s\nEmbodiment:\t%s\nAcknowledge:\t%s' % \ (ability,explanation,embodiment,acknowledgment) # Pre-compute symbols for this level's waypoints for point in WAYPOINTS[level]: if not point.has_key('symbol'): point['symbol'] = point['name'].replace(' ','') world = World() world.defineState(None,'level',int,lo=0,hi=len(WAYPOINTS)-1, description='Static variable indicating what mission level') world.setState(None,'level',level) world.defineState(None,'time',float) world.setState(None,'time',0.) world.defineState(None,'complete',bool) world.setState(None,'complete',False) world.addTermination(makeTree({'if': trueRow('complete'), True: True, False: False})) # Buildings threats = ['none','NBC','armed'] for waypoint in WAYPOINTS[level]: if not waypoint.has_key('symbol'): waypoint['symbol'] = waypoint['name'].replace(' ','') world.addAgent(Agent(waypoint['symbol'])) # Have we visited this waypoint? key = world.defineState(waypoint['symbol'],'visited',bool) world.setFeature(key,False) # Are there dangerous chemicals or armed people here? key = world.defineState(waypoint['symbol'],'danger',list,threats[:]) if waypoint.has_key('NBC') and waypoint['NBC']: world.setFeature(key,'NBC') elif waypoint.has_key('armed') and waypoint['armed']: world.setFeature(key,'armed') else: world.setFeature(key,'none') key = world.defineState(waypoint['symbol'],'recommendation',list, ['none','protected','unprotected']) world.setFeature(key,'none') # Human human = Agent('human') world.addAgent(human) world.defineState(human.name,'alive',bool) human.setState('alive',True) world.defineState(human.name,'deaths',int) human.setState('deaths',0) # Robot robot = Agent('robot') world.addAgent(robot) # Robot states world.defineState(robot.name,'waypoint',list,[point['symbol'] for point in WAYPOINTS[level]]) robot.setState('waypoint',WAYPOINTS[level][getStart(level)]['symbol']) world.defineState(robot.name,'explanation',list,['none','ability','abilitybenevolence','abilityconfidence','confidence']) robot.setState('explanation',explanation) world.defineState(robot.name,'embodiment',list,['robot','dog']) robot.setState('embodiment',embodiment) world.defineState(robot.name,'acknowledgment',list,['no','yes']) robot.setState('acknowledgment',acknowledgment) world.defineState(robot.name,'ability',list,['badSensor','badModel','good']) if ability is True: # Backward compatibility with boolean ability ability = 'good' elif ability is False: ability = 'badSensor' robot.setState('ability',ability) # State of the robot's sensors world.defineState(robot.name,'sensorModel',list,['good','bad']) robot.setState('sensorModel','good') world.defineState(robot.name,'command',list,['none']+[point['symbol'] for point in WAYPOINTS[level]]) robot.setState('command','none') # Actions for end in range(len(WAYPOINTS[level])): symbol = WAYPOINTS[level][end]['symbol'] # Robot movement action = robot.addAction({'verb': 'moveto','object': symbol}) # Legal if no contradictory command tree = makeTree({'if': equalRow(stateKey(robot.name,'command'),'none'), True: True, False: {'if': equalRow(stateKey(robot.name,'command'),symbol), True: True, False: False}}) robot.setLegal(action,tree) # Dynamics of robot's location tree = makeTree(setToConstantMatrix(stateKey(action['subject'],'waypoint'),symbol)) world.setDynamics(stateKey(action['subject'],'waypoint'),action,tree) # Dynamics of visited flag key = stateKey(symbol,'visited') tree = makeTree(setTrueMatrix(key)) world.setDynamics(key,action,tree) # Dynamics of time key = stateKey(None,'time') tree = setToConstantMatrix(key,0.) for start in range(len(WAYPOINTS[level])): if start != end: startsymbol = WAYPOINTS[level][start]['symbol'] if sequence: # Distance is measured by level sequence distance = abs(start-end)*50 else: try: distance = DISTANCES[WAYPOINTS[level][start]['name']][WAYPOINTS[level][end]['name']] except KeyError: try: distance = DISTANCES[WAYPOINTS[level][end]['name']][WAYPOINTS[level][start]['name']] except KeyError: distance = 250 tree = {'if': equalRow(stateKey(action['subject'],'waypoint'),startsymbol), True: setToConstantMatrix(key,float(distance)/1000.), False: tree} world.setDynamics(key,action,makeTree(tree)) # Human entry: Dead or alive if unprotected? key = stateKey(human.name,'alive') action = robot.addAction({'verb': 'recommend unprotected','object': symbol}) tree = makeTree({'if': equalRow(stateKey(symbol,'danger'),'none'), True: setTrueMatrix(key), False: setFalseMatrix(key)}) world.setDynamics(key,action,tree) robot.setLegal(action,makeTree(False)) # Human entry: How much "time" if protected? action = robot.addAction({'verb': 'recommend protected','object': symbol}) key = stateKey(None,'time') world.setDynamics(key,action,makeTree(setToConstantMatrix(key,0.25))) robot.setLegal(action,makeTree(False)) # Robot goals goal = minimizeFeature(stateKey(None,'time')) robot.setReward(goal,2.) goal = maximizeFeature(stateKey(human.name,'alive')) robot.setReward(goal,1.) for point in WAYPOINTS[level]: robot.setReward(maximizeFeature(stateKey(point['symbol'],'visited')),1.) if beliefs: # omega = 'danger' world.defineVariable(robot.name,ActionSet) # Robot beliefs world.setModel(robot.name,True) value = 1./float(len(WAYPOINTS[level])) # tree = KeyedVector({CONSTANT: world.value2float(omega,'none')}) for index in range(len(WAYPOINTS[level])): waypoint = WAYPOINTS[level][index] key = stateKey(waypoint['symbol'],'danger') # if index > 0: # Starting state is safe robot.setBelief(key,psychsim.probability.Distribution({'NBC': value/2., 'armed': value/2.,'none': 1.-value})) # Observation function # tree = {'if': equalRow(stateKey(robot.name,'waypoint'),waypoint['symbol']), # True: generateO(world,key), # False: tree} # robot.defineObservation(omega,makeTree(tree),domain=list,lo=['none','NBC','armed']) robot.defineObservation('microphone',makeTree(None),None,domain=list, lo=['nobody','friendly','suspicious']) robot.defineObservation('NBCsensor',makeTree(None),None,domain=bool) robot.defineObservation('camera',makeTree(None),None,domain=bool) else: robot.defineObservation('microphone',makeTree(None),None,domain=list, lo=['nobody','friendly','suspicious']) robot.defineObservation('NBCsensor',makeTree(None),None,domain=bool) robot.defineObservation('camera',makeTree(None),None,domain=bool) robot.setAttribute('horizon',1) world.setOrder([robot.name]) filename = getFilename(username,level,ext,root) world.save(filename,ext=='psy') WriteLogData('%s user %s, level %d, ability %s, explanation %s' % \ (CREATE_TAG,username,level,ability,explanation),username,level,root=root) return world
# prob = noisyOr(tree[True],.75,.1) # return {'distribution': [(setTrueMatrix(key),prob),(setFalseMatrix(key),1.-prob)]} # # # # # def noisyOr(onCount,onProb,leak=0.): # return 1.- (1.-leak)*pow(1.-onProb,onCount) if __name__ == '__main__': # State world = World() world.diagram = diagram.Diagram() world.diagram.setColor(None, 'ivory') resident = Agent('resident') world.diagram.setColor(resident.name, 'palegreen') world.addAgent(resident) world.defineState(resident.name, 'sea_level_house', list, ['low', 'med', 'hi']) world.defineState(resident.name, 'home_structure', list, ['mobile', 'other']) world.defineState(resident.name, 'storm_category', list, ['1', '2', '3', '4', '5']) world.defineState(resident.name, 'gov_evac', list, ['strong', 'none']) world.defineState(resident.name, 'loc_evac_phone', bool) world.defineState(resident.name, 'peer_evac_info', bool) world.defineState(resident.name, 'expect_prop_risk', bool) world.defineState(resident.name, 'expect_personal_risk', bool) bel_seq = [
__author__ = 'Pedro Sequeira' __email__ = '*****@*****.**' __description__ = 'Example that models one agent navigating left or right along one dimension (one position feature). ' \ 'We set a belief to the agent for an incorrect position, and see the agent act based on that belief, ' \ 'i.e., in its mind the position is changing, but is not aligned with the real/true position.' # parameters HORIZON = 3 DISCOUNT = 1 MAX_STEPS = 3 if __name__ == '__main__': # create world and add agent world = World() agent = Agent('Agent') world.addAgent(agent) # set parameters agent.setAttribute('discount', DISCOUNT) agent.setHorizon(HORIZON) # add position variable pos = world.defineState(agent.name, 'position', int, lo=-100, hi=100) world.setFeature(pos, 0) # define agents' actions (stay 0, left -1 and right +1) action = agent.addAction({'verb': 'move', 'action': 'nowhere'}) tree = makeTree(setToFeatureMatrix(pos, pos)) world.setDynamics(pos, action, tree) action = agent.addAction({'verb': 'move', 'action': 'left'})
} } }) if __name__ == '__main__': random.seed(0) # sets up log to screen logging.basicConfig(format='%(message)s', level=logging.DEBUG if DEBUG else logging.INFO) # create world and add agent world = World() agent1 = Agent('Agent 1') world.addAgent(agent1) agent2 = Agent('Agent 2') world.addAgent(agent2) agents_dec = [] agents = [agent1, agent2] for agent in agents: # set agent's params agent.setAttribute('discount', 1) agent.setAttribute('selection', TIEBREAK) # agent.setRecursiveLevel(1) # add "decision" variable (0 = didn't decide, 1 = Defected, 2 = Cooperated) dec = world.defineState(agent.name, 'decision', list, [NOT_DECIDED, DEFECTED, COOPERATED])
from ConfigParser import SafeConfigParser from optparse import OptionParser from psychsim.pwl import * from psychsim.action import Action,ActionSet from psychsim.world import World,stateKey,actionKey from psychsim.agent import Agent if __name__ == '__main__': # Create scenario world = World() totals = {'scotch':1,'tequila':1} # 1 and 1 stacy = Agent('Stacy') david = Agent('David') agts = [stacy, david] # Player state, actions and parameters common to both players for i in range(2): me = agts[i] other = agts[1-i] world.addAgent(me) # State world.defineState(me.name,'scotchOwned',int,lo=0,hi=totals['scotch']) me.setState('scotchOwned',0) world.defineState(me.name,'scotchOffered',int,lo=0,hi=totals['scotch']) me.setState('scotchOffered',0) world.defineState(me.name,'tequilaOwned',int,lo=0,hi=totals['tequila']) me.setState('tequilaOwned',0)
def scenarioCreationUseCase(enemy='Sylvania', model='powell', web=False, fCollapse=None, sCollapse=None, maxRounds=15): """ An example of how to create a scenario @param enemy: the name of the agent-controlled side, i.e., Freedonia's opponent (default: Sylvania) @type enemy: str @param model: which model do we use (default is "powell") @type model: powell or slantchev @param web: if C{True}, then create the web-based experiment scenario (default: C{False}) @type web: bool @param fCollapse: the probability that Freedonia collapses (under powell, default: 0.1) or loses battle (under slantchev, default: 0.7) @type fCollapse: float @param sCollapse: the probability that Sylvania collapses, under powell (default: 0.1) @type sCollapse: float @param maxRounds: the maximum number of game rounds (default: 15) @type maxRounds: int @return: the scenario created @rtype: L{World} """ # Handle defaults for battle probabilities, under each model posLo = 0 posHi = 10 if fCollapse is None: if model == 'powell': fCollapse = 0.1 elif model == 'slantchev': fCollapse = 0.7 if sCollapse is None: sCollapse = 0.1 # Create scenario world = World() # Agents free = Agent('Freedonia') world.addAgent(free) sylv = Agent(enemy) world.addAgent(sylv) # User state world.defineState(free.name, 'troops', int, lo=0, hi=50000, description='Number of troops you have left') free.setState('troops', 40000) world.defineState( free.name, 'territory', int, lo=0, hi=100, description='Percentage of disputed territory owned by you') free.setState('territory', 15) world.defineState(free.name, 'cost', int, lo=0, hi=50000, description='Number of troops %s loses in an attack' % (free.name)) free.setState('cost', 2000) world.defineState( free.name, 'position', int, lo=posLo, hi=posHi, description='Current status of war (%d=%s is winner, %d=you are winner)' % (posLo, sylv.name, posHi)) free.setState('position', 5) world.defineState( free.name, 'offered', int, lo=0, hi=100, description= 'Percentage of disputed territory that %s last offered to you' % (sylv.name)) free.setState('offered', 0) if model == 'slantchev': # Compute new value for territory only *after* computing new value for position world.addDependency(stateKey(free.name, 'territory'), stateKey(free.name, 'position')) # Agent state world.defineState(sylv.name, 'troops', int, lo=0, hi=500000, description='Number of troops %s has left' % (sylv.name)) sylv.setState('troops', 30000) world.defineState(sylv.name, 'cost', int, lo=0, hi=50000, description='Number of troops %s loses in an attack' % (sylv.name)) sylv.setState('cost', 2000) world.defineState( sylv.name, 'offered', int, lo=0, hi=100, description= 'Percentage of disputed territory that %s last offered to %s' % (free.name, sylv.name)) sylv.setState('offered', 0) # World state world.defineState(None, 'treaty', bool, description='Have the two sides reached an agreement?') world.setState(None, 'treaty', False) # Stage of negotiation, illustrating the use of an enumerated state feature world.defineState( None, 'phase', list, ['offer', 'respond', 'rejection', 'end', 'paused', 'engagement'], description='The current stage of the negotiation game') world.setState(None, 'phase', 'paused') # Game model, static descriptor world.defineState(None, 'model', list, ['powell', 'slantchev'], description='The model underlying the negotiation game') world.setState(None, 'model', model) # Round of negotiation world.defineState(None, 'round', int, description='The current round of the negotiation') world.setState(None, 'round', 0) if not web: # Relationship value key = world.defineRelation(free.name, sylv.name, 'trusts') world.setFeature(key, 0.) # Game over if there is a treaty world.addTermination( makeTree({ 'if': trueRow(stateKey(None, 'treaty')), True: True, False: False })) # Game over if Freedonia has no territory world.addTermination( makeTree({ 'if': thresholdRow(stateKey(free.name, 'territory'), 1), True: False, False: True })) # Game over if Freedonia has all the territory world.addTermination( makeTree({ 'if': thresholdRow(stateKey(free.name, 'territory'), 99), True: True, False: False })) # Game over if number of rounds exceeds limit world.addTermination( makeTree({ 'if': thresholdRow(stateKey(None, 'round'), maxRounds), True: True, False: False })) # Turn order: Uncomment the following if you want agents to act in parallel # world.setOrder([set(world.agents.keys())]) # Turn order: Uncomment the following if you want agents to act sequentially world.setOrder([free.name, sylv.name]) # User actions freeBattle = free.addAction({'verb': 'attack', 'object': sylv.name}) for amount in range(20, 100, 20): free.addAction({ 'verb': 'offer', 'object': sylv.name, 'amount': amount }) if model == 'powell': # Powell has null stages freeNOP = free.addAction({'verb': 'continue'}) elif model == 'slantchev': # Slantchev has both sides receiving offers free.addAction({'verb': 'accept offer', 'object': sylv.name}) free.addAction({'verb': 'reject offer', 'object': sylv.name}) # Agent actions sylvBattle = sylv.addAction({'verb': 'attack', 'object': free.name}) sylvAccept = sylv.addAction({'verb': 'accept offer', 'object': free.name}) sylvReject = sylv.addAction({'verb': 'reject offer', 'object': free.name}) if model == 'powell': # Powell has null stages sylvNOP = sylv.addAction({'verb': 'continue'}) elif model == 'slantchev': # Slantchev has both sides making offers for amount in range(10, 100, 10): sylv.addAction({ 'verb': 'offer', 'object': free.name, 'amount': amount }) # Restrictions on when actions are legal, based on phase of game for action in filterActions({'verb': 'offer'}, free.actions | sylv.actions): agent = world.agents[action['subject']] agent.setLegal( action, makeTree({ 'if': equalRow(stateKey(None, 'phase'), 'offer'), True: True, # Offers are legal in the offer phase False: False })) # Offers are illegal in all other phases if model == 'powell': # Powell has a special rejection phase for action in [freeNOP, freeBattle]: free.setLegal( action, makeTree({ 'if': equalRow(stateKey(None, 'phase'), 'rejection'), True: True, # Attacking and doing nothing are legal only in rejection phase False: False }) ) # Attacking and doing nothing are illegal in all other phases # Once offered, agent can respond if model == 'powell': # Under Powell, only Sylvania has to respond, and it can attack responses = [sylvBattle, sylvAccept, sylvReject] elif model == 'slantchev': # Under Slantchev, only accept/reject responses = filterActions({'verb': 'accept offer'}, free.actions | sylv.actions) responses += filterActions({'verb': 'reject offer'}, free.actions | sylv.actions) for action in responses: agent = world.agents[action['subject']] agent.setLegal( action, makeTree({ 'if': equalRow(stateKey(None, 'phase'), 'respond'), True: True, # Offeree must act in the response phase False: False })) # Offeree cannot act in any other phase if model == 'powell': # NOP is legal in exactly opposite situations to all other actions sylv.setLegal( sylvNOP, makeTree({ 'if': equalRow(stateKey(None, 'phase'), 'end'), True: True, # Sylvania does not do anything in the null phase after Freedonia responds to rejection False: False })) # Sylvania must act in its other phases if model == 'slantchev': # Attacking legal only under engagement phase for action in filterActions({'verb': 'attack'}, free.actions | sylv.actions): agent = world.agents[action['subject']] agent.setLegal( action, makeTree({ 'if': equalRow(stateKey(None, 'phase'), 'engagement'), True: True, # Attacking legal only in engagement False: False })) # Attacking legal every other phase # Goals for Freedonia goalFTroops = maximizeFeature(stateKey(free.name, 'troops')) free.setReward(goalFTroops, 1.) goalFTerritory = maximizeFeature(stateKey(free.name, 'territory')) free.setReward(goalFTerritory, 1.) # Goals for Sylvania goalSTroops = maximizeFeature(stateKey(sylv.name, 'troops')) sylv.setReward(goalSTroops, 1.) goalSTerritory = minimizeFeature(stateKey(free.name, 'territory')) sylv.setReward(goalSTerritory, 1.) # Possible goals applicable to both goalAgreement = maximizeFeature(stateKey(None, 'treaty')) # Silly goal, provided as an example of an achievement goal goalAchieve = achieveFeatureValue(stateKey(None, 'phase'), 'respond') # Horizons if model == 'powell': free.setAttribute('horizon', 4) sylv.setAttribute('horizon', 4) elif model == 'slantchev': free.setAttribute('horizon', 6) sylv.setAttribute('horizon', 6) # Discount factors free.setAttribute('discount', -1) sylv.setAttribute('discount', -1) # Levels of belief free.setRecursiveLevel(2) sylv.setRecursiveLevel(2) # Dynamics of battle freeTroops = stateKey(free.name, 'troops') freeTerr = stateKey(free.name, 'territory') sylvTroops = stateKey(sylv.name, 'troops') # Effect of fighting for action in filterActions({'verb': 'attack'}, free.actions | sylv.actions): # Effect on troops (cost of battle) tree = makeTree( addFeatureMatrix(freeTroops, stateKey(free.name, 'cost'), -1.)) world.setDynamics(freeTroops, action, tree, enforceMin=not web) tree = makeTree( addFeatureMatrix(sylvTroops, stateKey(sylv.name, 'cost'), -1.)) world.setDynamics(sylvTroops, action, tree, enforceMin=not web) if model == 'powell': # Effect on territory (probability of collapse) tree = makeTree({ 'distribution': [ ( { 'distribution': [ (setToConstantMatrix(freeTerr, 100), 1. - fCollapse ), # Sylvania collapses, Freedonia does not (noChangeMatrix(freeTerr), fCollapse) ] }, # Both collapse sCollapse), ( { 'distribution': [ (setToConstantMatrix(freeTerr, 0), fCollapse ), # Freedonia collapses, Sylvania does not (noChangeMatrix(freeTerr), 1. - fCollapse) ] }, # Neither collapses 1. - sCollapse) ] }) world.setDynamics(freeTerr, action, tree) elif model == 'slantchev': # Effect on position pos = stateKey(free.name, 'position') tree = makeTree({ 'distribution': [ (incrementMatrix(pos, 1), 1. - fCollapse), # Freedonia wins battle (incrementMatrix(pos, -1), fCollapse) ] }) # Freedonia loses battle world.setDynamics(pos, action, tree) # Effect on territory tree = makeTree({ 'if': thresholdRow(pos, posHi - .5), True: setToConstantMatrix(freeTerr, 100), # Freedonia won False: { 'if': thresholdRow(pos, posLo + .5), True: noChangeMatrix(freeTerr), False: setToConstantMatrix(freeTerr, 0) } }) # Freedonia lost world.setDynamics(freeTerr, action, tree) # Dynamics of offers for index in range(2): atom = Action({ 'subject': world.agents.keys()[index], 'verb': 'offer', 'object': world.agents.keys()[1 - index] }) if atom['subject'] == free.name or model != 'powell': offer = stateKey(atom['object'], 'offered') amount = actionKey('amount') tree = makeTree({ 'if': trueRow(stateKey(None, 'treaty')), True: noChangeMatrix(offer), False: setToConstantMatrix(offer, amount) }) world.setDynamics(offer, atom, tree, enforceMax=not web) # Dynamics of treaties for action in filterActions({'verb': 'accept offer'}, free.actions | sylv.actions): # Accepting an offer means that there is now a treaty key = stateKey(None, 'treaty') tree = makeTree(setTrueMatrix(key)) world.setDynamics(key, action, tree) # Accepting offer sets territory offer = stateKey(action['subject'], 'offered') territory = stateKey(free.name, 'territory') if action['subject'] == free.name: # Freedonia accepts sets territory to last offer tree = makeTree(setToFeatureMatrix(territory, offer)) world.setDynamics(freeTerr, action, tree) else: # Sylvania accepts sets territory to 1-last offer tree = makeTree( setToFeatureMatrix(territory, offer, pct=-1., shift=100.)) world.setDynamics(freeTerr, action, tree) # Dynamics of phase phase = stateKey(None, 'phase') roundKey = stateKey(None, 'round') # OFFER -> RESPOND for index in range(2): action = Action({ 'subject': world.agents.keys()[index], 'verb': 'offer', 'object': world.agents.keys()[1 - index] }) if action['subject'] == free.name or model != 'powell': tree = makeTree(setToConstantMatrix(phase, 'respond')) world.setDynamics(phase, action, tree) # RESPOND -> REJECTION or ENGAGEMENT for action in filterActions({'verb': 'reject offer'}, free.actions | sylv.actions): if model == 'powell': tree = makeTree(setToConstantMatrix(phase, 'rejection')) elif model == 'slantchev': tree = makeTree(setToConstantMatrix(phase, 'engagement')) world.setDynamics(phase, action, tree) # accepting -> OFFER for action in filterActions({'verb': 'accept offer'}, free.actions | sylv.actions): tree = makeTree(setToConstantMatrix(phase, 'offer')) world.setDynamics(phase, action, tree) # attacking -> OFFER for action in filterActions({'verb': 'attack'}, free.actions | sylv.actions): tree = makeTree(setToConstantMatrix(phase, 'offer')) world.setDynamics(phase, action, tree) if action['subject'] == sylv.name or model == 'slantchev': tree = makeTree(incrementMatrix(roundKey, 1)) world.setDynamics(roundKey, action, tree) if model == 'powell': # REJECTION -> END for atom in [freeNOP, freeBattle]: tree = makeTree(setToConstantMatrix(phase, 'end')) world.setDynamics(phase, atom, tree) # END -> OFFER atom = Action({'subject': sylv.name, 'verb': 'continue'}) tree = makeTree(setToConstantMatrix(phase, 'offer')) world.setDynamics(phase, atom, tree) tree = makeTree(incrementMatrix(roundKey, 1)) world.setDynamics(roundKey, atom, tree) if not web: # Relationship dynamics: attacking is bad for trust atom = Action({ 'subject': sylv.name, 'verb': 'attack', 'object': free.name }) key = binaryKey(free.name, sylv.name, 'trusts') tree = makeTree(approachMatrix(key, 0.1, -1.)) world.setDynamics(key, atom, tree) # Handcrafted policy for Freedonia # free.setPolicy(makeTree({'if': equalRow('phase','respond'), # # Accept an offer greater than 50 # True: {'if': thresholdRow(stateKey(free.name,'offered'),50), # True: Action({'subject': free.name,'verb': 'accept offer','object': sylv.name}), # False: Action({'subject': free.name,'verb': 'reject offer','object': sylv.name})}, # False: {'if': equalRow('phase','engagement'), # # Attack during engagement phase # True: Action({'subject': free.name,'verb': 'attack','object': sylv.name}), # # Agent decides how what to do otherwise # False: False}})) # Mental models of enemy # Example of creating a model with incorrect reward all at once (a version of Freedonia who cares about reaching agreement as well) # sylv.addModel('false',R={goalSTroops: 10.,goalSTerritory: 1.,goalAgreement: 1.}, # rationality=1.,selection='distribution',parent=True) # Example of creating a model with incorrect beliefs sylv.addModel('false', rationality=10., selection='distribution', parent=True) key = stateKey(free.name, 'position') # Sylvania believes position to be fixed at 3 sylv.setBelief(key, 3, 'false') # Freedonia is truly unsure about position (50% chance of being 7, 50% of being 3) world.setModel(free.name, True) free.setBelief(key, Distribution({7: 0.5, 3: 0.5}), True) # Observations about military position tree = makeTree({ 'if': thresholdRow(key, 1), True: { 'if': thresholdRow(key, 9), True: { 'distribution': [(KeyedVector({key: 1}), 0.9), (KeyedVector({ key: 1, CONSTANT: -1 }), 0.1)] }, False: { 'distribution': [(KeyedVector({key: 1}), 0.8), (KeyedVector({ key: 1, CONSTANT: -1 }), 0.1), (KeyedVector({ key: 1, CONSTANT: 1 }), 0.1)] } }, False: { 'distribution': [(KeyedVector({key: 1}), 0.9), (KeyedVector({ key: 1, CONSTANT: 1 }), 0.1)] } }) free.defineObservation(key, tree) # Example of setting model parameters separately sylv.addModel('true', parent=True) sylv.setAttribute( 'rationality', 10., 'true') # Override real agent's rationality with this value sylv.setAttribute('selection', 'distribution', 'true') world.setMentalModel(free.name, sylv.name, {'false': 0.9, 'true': 0.1}) # Goal of fooling Sylvania goalDeception = achieveFeatureValue(modelKey(sylv.name), sylv.model2index('false')) return world
return {'if': tree['if'], True: leaf2matrix(tree[True],key), False: leaf2matrix(tree[False],key)} else: prob = noisyOr(tree[True],.75,.1) return {'distribution': [(setTrueMatrix(key),prob),(setFalseMatrix(key),1.-prob)]} def noisyOr(onCount,onProb,leak=0.): return 1.- (1.-leak)*pow(1.-onProb,onCount) if __name__ == '__main__': world = World() world.diagram = diagram.Diagram() world.diagram.setColor(None,'ivory') resident = Agent('resident') world.diagram.setColor(resident.name,'palegreen') world.addAgent(resident) # family = Agent('family') # world.diagram.setColor(family.name,'mediumseagreen') # world.addAgent(family) gov = Agent('government') world.diagram.setColor(gov.name,'cornflowerblue') world.addAgent(gov) world.setOrder([resident.name]) # Keep track of orthogonal dimensions of decision-making phase = world.defineState(None,'phase',list,['where','how'], description='What is being decided at this stage of the simulation') world.setState(None,'phase','where')
import sys from ConfigParser import SafeConfigParser from optparse import OptionParser from psychsim.pwl import * from psychsim.action import Action, ActionSet from psychsim.world import World, stateKey, actionKey from psychsim.agent import Agent if __name__ == '__main__': # Create scenario world = World() totals = {'apple': 3, 'pear': 2} # Stacy state stacy = Agent('Stacy') world.addAgent(stacy) world.defineState(stacy.name, 'applesOwned', int, lo=0, hi=totals['apple']) stacy.setState('applesOwned', 0) world.defineState(stacy.name, 'applesOffered', int, lo=0, hi=totals['apple']) stacy.setState('applesOffered', 0) world.defineState(stacy.name, 'pearsOwned', int, lo=0, hi=totals['pear']) stacy.setState('pearsOwned', 0) world.defineState(stacy.name, 'pearsOffered', int, lo=0, hi=totals['pear']) stacy.setState('pearsOffered', 0) # David state
if __name__ == '__main__': # Create scenario world = World() totals = {'exiter':3,'follower':4, 'avoider':3} # # there are a mix of agent types that have different reward preferences for heading towards door, # following someone who is closest or avoiding the fire rewardWeights = {'exiter':{'fire':.4,'door':.5,'follow':.1},'follower':{'fire':.2,'door':.2,'follow':.6},'avoider':{'fire':.6,'door':.3,'follow':.1}} # the fire and door are modeled as agents with no actions - they only have a fixed location me = Agent('door') world.addAgent(me) world.defineState(me.name,'x',float) world.setState(me.name,'x',5) world.defineState(me.name,'y',float) world.setState(me.name,'y',5) me.setHorizon(0) me = Agent('fire') world.addAgent(me) world.defineState(me.name,'x',float) world.setState(me.name,'x',1) world.defineState(me.name,'y',float) world.setState(me.name,'y',1) me.setHorizon(0)
def parseGDELT(fname, targets=[]): """ Extracts events from a single GDELT CSV file """ # Parse filename root, ext = os.path.splitext(os.path.basename(fname)) assert ext == '.csv', 'CSV file expected instead of %s' % (fname) if len(root) == 4: year = int(root) month = 0 else: assert len( root) == 6, 'Filename not in YYYY.csv or YYYYMM.csv format: %s' % ( fname) year = int(root[:4]) month = int(root[4:]) # Initialize storage result = { 'month': month, 'year': year, 'agents': {}, 'matrix': {}, 'calendar': {}, } today = None start = time.time() lines = 0 for line in fileinput.input(fname): lines += 1 # Extract the event fields elements = map(lambda x: x.strip(), line.split('\t')) event = {} for index in range(len(elements)): if len(elements[index]) == 0: event[headings[index]] = None elif headings[index] in intHeadings: event[headings[index]] = int(elements[index]) elif headings[index] in floatHeadings: event[headings[index]] = float(elements[index]) else: event[headings[index]] = elements[index].strip() if event['SQLDATE'] != today: today = event['SQLDATE'] events = [] result['calendar'][event['SQLDATE']] = events print >> sys.stderr, today if event['Actor1Code'] is None: # No actor? event['Actor1Code'] = 'Unknown' if lines % 10000 == 0 and events: print >> sys.stderr,'\t%dK (%d events,%d agents)' % \ (lines/1000,len(events),len(result['agents'])) if matchActor(event['Actor1Code'],targets) or \ matchActor(event['Actor2Code'],targets): # Event matching our target events.append(event) if not result['agents'].has_key(event['Actor1Code']): agent = Agent(event['Actor1Code']) result['agents'][agent.name] = agent event['action'] = Action({ 'subject': event['Actor1Code'], 'verb': cameo[event['EventCode']] }) if event['Actor2Code']: if not result['agents'].has_key(event['Actor2Code']): agent = Agent(event['Actor2Code']) result['agents'][agent.name] = agent event['action']['object'] = event['Actor2Code'] # Update relationship matrix if event['Actor1Code'] < event['Actor2Code']: key = '%s,%s' % (event['Actor1Code'], event['Actor2Code']) else: key = '%s,%s' % (event['Actor2Code'], event['Actor1Code']) try: result['matrix'][key].append(event) except KeyError: result['matrix'][key] = [event] return result
def isXML(element): if not Agent.isXML(element): return False return len(element.getAttribute('resource')) > 0
class TestAgents(unittest.TestCase): def setUp(self): # Create world self.world = World() # Create agents self.tom = Agent('Tom') self.world.addAgent(self.tom) self.jerry = Agent('Jerry') self.world.addAgent(self.jerry) def addStates(self): """Create state features""" self.world.defineState(self.tom.name,'health',int,lo=0,hi=100, description='%s\'s wellbeing' % (self.tom.name)) self.world.setState(self.tom.name,'health',50) self.world.defineState(self.jerry.name,'health',int,lo=0,hi=100, description='%s\'s wellbeing' % (self.jerry.name)) self.world.setState(self.jerry.name,'health',50) def addActions(self): """Create actions""" self.chase = self.tom.addAction({'verb': 'chase','object': self.jerry.name}) self.hit = self.tom.addAction({'verb': 'hit','object': self.jerry.name}) self.run = self.jerry.addAction({'verb': 'run away'}) self.trick = self.jerry.addAction({'verb': 'trick','object': self.tom.name}) def addDynamics(self): """Create dynamics""" tree = makeTree(incrementMatrix(stateKey(self.jerry.name,'health'),-10)) self.world.setDynamics(stateKey(self.jerry.name,'health'),self.hit,tree,enforceMin=True) def addModels(self,rationality=1.): self.tom.addModel('friend',rationality=rationality,parent=True) self.tom.setReward(maximizeFeature(stateKey(self.jerry.name,'health')),1.,'friend') self.tom.addModel('foe',rationality=rationality,parent=True) self.tom.setReward(minimizeFeature(stateKey(self.jerry.name,'health')),1.,'foe') def saveload(self): """Write scenario to file and then load from scratch""" self.world.save('/tmp/psychsim_test.psy') self.world = World('/tmp/psychsim_test.psy') self.tom = self.world.agents[self.tom.name] self.jerry = self.world.agents[self.jerry.name] def testEnumeratedState(self): self.addActions() self.world.defineVariable(self.tom.name,ActionSet) self.world.defineState(self.tom.name,'status',list,['dead','injured','healthy']) self.world.setState(self.tom.name,'status','healthy') goal = achieveFeatureValue(stateKey(self.tom.name,'status'),'healthy') self.tom.setReward(goal,1.) goal = achieveFeatureValue(stateKey(self.tom.name,'status'),'injured') self.jerry.setReward(goal,1.) self.saveload() self.assertEqual(len(self.world.state[None]),1) vector = self.world.state[None].domain()[0] tVal = self.tom.reward(vector) self.assertAlmostEqual(tVal,1.,8) jVal = self.jerry.reward(vector) self.assertAlmostEqual(jVal,0.,8) for action in self.tom.actions: encoding = self.world.value2float(self.tom.name,action) self.assertEqual(action,self.world.float2value(self.tom.name,encoding)) def testBeliefModels(self): self.addStates() self.addActions() self.addDynamics() self.world.setOrder([self.tom.name]) self.tom.addModel('optimist') self.tom.setBelief(stateKey(self.jerry.name,'health'),20,'optimist') self.tom.addModel('pessimist') self.world.setModel(self.jerry.name,True) self.world.setMentalModel(self.jerry.name,self.tom.name,{'optimist': 0.5,'pessimist': 0.5}) actions = {self.tom.name: self.hit} self.world.step(actions) vector = self.world.state[None].domain()[0] beliefs = self.jerry.getAttribute('beliefs',self.world.getModel(self.jerry.name,vector)) for belief in beliefs.domain(): model = self.world.getModel(self.tom.name,belief) if self.tom.models[model].has_key('beliefs'): nested = self.tom.models[model]['beliefs'] self.assertEqual(len(nested),1) nested = nested.domain()[0] self.assertEqual(len(nested),1) self.assertAlmostEqual(nested[stateKey(self.jerry.name,'health')],10.,8) def testObservation(self): self.addStates() self.addActions() self.addDynamics() self.world.setOrder([self.tom.name]) self.world.setModel(self.jerry.name,True) key = stateKey(self.jerry.name,'health') self.jerry.setBelief(key,Distribution({20: 0.5, 50: 0.5})) tree = makeTree({'if': thresholdRow(key,40), True: {'distribution': [(KeyedVector({CONSTANT: 50}),.8), (KeyedVector({CONSTANT: 20}),.2)]}, False: {'distribution': [(KeyedVector({CONSTANT: 50}),.2), (KeyedVector({CONSTANT: 20}),.8)]}}) self.jerry.defineObservation(key,tree) actions = {self.tom.name: self.hit} vector = self.world.state[None].domain()[0] omegaDist = self.jerry.observe(vector,actions) for omega in omegaDist.domain(): new = KeyedVector(vector) model = self.jerry.index2model(self.jerry.stateEstimator(vector,new,omega)) beliefs = self.jerry.models[model]['beliefs'] if omega[key] > 30: # We observed a high value, so we should have a stronger belief in the higher value # which is now 40 after the hit for belief in beliefs.domain(): if beliefs[belief] > 0.5: self.assertAlmostEqual(belief[key],40,8) else: self.assertAlmostEqual(belief[key],10,8) else: # We observed a low value, so we should have a stronger belief in the lower value # which is now 10 after the hit for belief in beliefs.domain(): if beliefs[belief] < 0.5: self.assertAlmostEqual(belief[key],40,8) else: self.assertAlmostEqual(belief[key],10,8) def testUnobservedAction(self): self.addStates() self.addActions() self.addDynamics() self.addModels() self.world.setOrder([self.tom.name]) self.world.setModel(self.jerry.name,True) self.jerry.setBelief(stateKey(self.jerry.name,'health'),50) self.world.setMentalModel(self.jerry.name,self.tom.name,{'friend': 0.5,'foe': 0.5}) tree = makeTree(True) self.jerry.defineObservation(self.tom.name,tree,self.hit,domain=ActionSet) tree = makeTree({'distribution': [(True,0.25),(False,0.75)]}) self.jerry.defineObservation(self.tom.name,tree,self.chase,domain=ActionSet) vector = self.world.state[None].domain()[0] self.saveload() self.world.step({self.tom.name: self.hit}) vector = self.world.state[None].domain()[0] def testRewardModels(self): self.addStates() self.addActions() self.addDynamics() self.addModels() self.world.setOrder([self.tom.name]) # Add Jerry's model to the world (so that it gets updated) self.world.setModel(self.jerry.name,True) # Give Jerry uncertainty about Tom self.world.setMentalModel(self.jerry.name,self.tom.name,{'friend': 0.5,'foe': 0.5}) self.saveload() # Hitting should make Jerry think Tom is more of a foe actions = {self.tom.name: self.hit} self.world.step(actions) vector = self.world.state[None].domain()[0] belief01 = self.jerry.getAttribute('beliefs',self.world.getModel(self.jerry.name,vector)) key = modelKey(self.tom.name) for belief in belief01.domain(): if self.tom.index2model(belief[key]) == 'foe': prob01 = belief01[belief] break self.assertGreater(prob01,0.5) # If we think of Tom as even more of an optimizer, then our update should be stronger self.tom.setAttribute('rationality',10.,'foe') self.tom.setAttribute('rationality',10.,'friend') self.world.setMentalModel(self.jerry.name,self.tom.name,{'friend': 0.5,'foe': 0.5}) self.world.step(actions) vector = self.world.state[None].domain()[0] model = self.world.getModel(self.jerry.name,vector) belief10 = self.jerry.getAttribute('beliefs',model) key = modelKey(self.tom.name) for belief in belief10.domain(): if self.tom.index2model(belief[key]) == 'foe': prob10 = belief10[belief] break self.assertGreater(prob10,prob01) # If we keep the same models, but get another observation, we should update even more self.world.step(actions) vector = self.world.state[None].domain()[0] model = self.world.getModel(self.jerry.name,vector) belief1010 = self.jerry.getAttribute('beliefs',model) key = modelKey(self.tom.name) for belief in belief1010.domain(): if self.tom.index2model(belief[key]) == 'foe': prob1010 = belief1010[belief] break self.assertGreater(prob1010,prob10) def testDynamics(self): self.world.setOrder([self.tom.name]) self.addStates() self.addActions() self.addDynamics() key = stateKey(self.jerry.name,'health') self.assertEqual(len(self.world.state[None]),1) vector = self.world.state[None].domain()[0] self.assertTrue(vector.has_key(stateKey(self.tom.name,'health'))) self.assertTrue(vector.has_key(turnKey(self.tom.name))) self.assertTrue(vector.has_key(key)) self.assertTrue(vector.has_key(CONSTANT)) self.assertEqual(len(vector),4) self.assertEqual(vector[stateKey(self.tom.name,'health')],50) self.assertEqual(vector[key],50) outcome = self.world.step({self.tom.name: self.chase}) for i in range(7): self.assertEqual(len(self.world.state[None]),1) vector = self.world.state[None].domain()[0] self.assertTrue(vector.has_key(stateKey(self.tom.name,'health'))) self.assertTrue(vector.has_key(turnKey(self.tom.name))) self.assertTrue(vector.has_key(key)) self.assertTrue(vector.has_key(CONSTANT)) self.assertEqual(len(vector),4) self.assertEqual(vector[stateKey(self.tom.name,'health')],50) self.assertEqual(vector[key],max(50-10*i,0)) outcome = self.world.step({self.tom.name: self.hit}) self.saveload() def testRewardOnOthers(self): self.addStates() self.addActions() self.addDynamics() self.world.setOrder([self.tom.name]) vector = self.world.state[None].domain()[0] # Create Jerry's goals goal = maximizeFeature(stateKey(self.jerry.name,'health')) self.jerry.setReward(goal,1.) jVal = -self.jerry.reward(vector) # Create Tom's goals from scratch minGoal = minimizeFeature(stateKey(self.jerry.name,'health')) self.tom.setReward(minGoal,1.) self.saveload() tRawVal = self.tom.reward(vector) self.assertAlmostEqual(jVal,tRawVal,8) # Create Tom's goals as a function of Jerry's self.tom.models[True]['R'].clear() self.tom.setReward(self.jerry.name,-1.) self.saveload() tFuncVal = self.tom.reward(vector) self.assertAlmostEqual(tRawVal,tFuncVal,8) # Test effect of functional reward on value function self.tom.setHorizon(1) self.saveload() vHit = self.tom.value(vector,self.hit)['V'] vChase = self.tom.value(vector,self.chase)['V'] self.assertAlmostEqual(vHit,vChase+.1,8) def testReward(self): self.addStates() key = stateKey(self.jerry.name,'health') goal = makeTree({'if': thresholdRow(key,5), True: KeyedVector({key: -2}), False: KeyedVector({key: -1})}) goal = goal.desymbolize(self.world.symbols) self.jerry.setReward(goal,1.) R = self.jerry.models[True]['R'] self.assertEqual(len(R),1) newGoal = R.keys()[0] self.assertEqual(newGoal,goal) self.assertAlmostEqual(R[goal],1.,8) self.jerry.setReward(goal,2.) self.assertEqual(len(R),1) self.assertEqual(R.keys()[0],goal) self.assertAlmostEqual(R[goal],2.,8) def testTurnDynamics(self): self.addStates() self.addActions() self.world.setOrder([self.tom.name,self.jerry.name]) self.assertEqual(self.world.maxTurn,1) self.saveload() vector = self.world.state[None].domain()[0] jTurn = turnKey(self.jerry.name) tTurn = turnKey(self.tom.name) self.assertEqual(self.world.next(),[self.tom.name]) self.assertEqual(vector[tTurn],0) self.assertEqual(vector[jTurn],1) self.world.step() vector = self.world.state[None].domain()[0] self.assertEqual(self.world.next(),[self.jerry.name]) self.assertEqual(vector[tTurn],1) self.assertEqual(vector[jTurn],0) self.world.step() vector = self.world.state[None].domain()[0] self.assertEqual(self.world.next(),[self.tom.name]) self.assertEqual(vector[tTurn],0) self.assertEqual(vector[jTurn],1) # Try some custom dynamics self.world.setTurnDynamics(self.tom.name,self.hit,makeTree(noChangeMatrix(tTurn))) self.world.setTurnDynamics(self.jerry.name,self.hit,makeTree(noChangeMatrix(tTurn))) self.world.step() vector = self.world.state[None].domain()[0] self.assertEqual(self.world.next(),[self.tom.name]) self.assertEqual(vector[tTurn],0) self.assertEqual(vector[jTurn],1) self.world.step({self.tom.name: self.chase}) vector = self.world.state[None].domain()[0] self.assertEqual(self.world.next(),[self.jerry.name]) self.assertEqual(vector[tTurn],1) self.assertEqual(vector[jTurn],0) def testStatic(self): self.addStates() self.addActions() self.addDynamics() self.addModels() self.world.setModel(self.jerry.name,True) self.world.setMentalModel(self.jerry.name,self.tom.name,{'friend': 0.5,'foe': 0.5}) self.world.setOrder([self.tom.name]) vector = self.world.state[None].domain()[0] model = self.world.getModel(self.jerry.name,vector) belief0 = self.jerry.models[model]['beliefs'] result = self.world.step({self.tom.name: self.hit}) vector = self.world.state[None].domain()[0] model = self.world.getModel(self.jerry.name,vector) belief1 = self.jerry.models[model]['beliefs'] key = modelKey(self.tom.name) for vector in belief0.domain(): if self.tom.index2model(vector[key]) == 'friend': self.assertGreater(belief0[vector],belief1[vector]) else: self.assertGreater(belief1[vector],belief0[vector]) # Now with the static beliefs self.jerry.setAttribute('static',True,model) self.saveload() self.world.step() vector = self.world.state[None].domain()[0] model = self.world.getModel(self.jerry.name,vector) belief2 = self.jerry.models[model]['beliefs'] for vector in belief1.domain(): self.assertAlmostEqual(belief1[vector],belief2[vector],8)
def __init__(self,turnOrder,maxRounds,payoff): self.maxRounds=maxRounds self.payoff = payoff print self.payoff self.world = World() stacy = Agent('Stacy') david = Agent('David') agts = [stacy, david] # Player state, actions and parameters common to both players for i in range(2): me = agts[i] other = agts[1-i] self.world.addAgent(me) # State self.world.defineState(me.name,'money',int) me.setState('money',0) mePass = me.addAction({'verb': 'pass','object': other.name}) meTake = me.addAction({'verb': 'take','object': other.name}) # Parameters me.setHorizon(6) me.setAttribute('discount',1.) # me.setAttribute('discount',0.9) # Levels of belief david.setRecursiveLevel(3) stacy.setRecursiveLevel(3) self.world.setOrder(turnOrder) # World state self.world.defineState(None,'round',int,description='The current round') self.world.setState(None,'round',0) self.world.defineState(None,'gameOver',bool,description='whether game is over') self.world.setState(None,'gameOver',False) self.world.addTermination(makeTree({'if': thresholdRow(stateKey(None,'round'),self.maxRounds), True: True, False: {'if': trueRow(stateKey(None,'gameOver')), True: True, False: False}})) # Dynamics for action in stacy.actions | david.actions: tree = makeTree(incrementMatrix(stateKey(None,'round'),1)) self.world.setDynamics(stateKey(None,'round'),action,tree) if (action['verb'] == 'take'): tree = makeTree(setTrueMatrix(stateKey(None,'gameOver'))) self.world.setDynamics(stateKey(None,'gameOver'),action,tree) agts = ['Stacy','David'] for i in range(2): key = stateKey(agts[i],'money') tree = makeTree(self.buildPayoff(0, key, self.payoff[agts[i]])) self.world.setDynamics(stateKey(agts[i],'money'),action,tree) elif action['verb'] == 'pass': agts = ['Stacy','David'] for i in range(2): key = stateKey(agts[i],'money') tree = makeTree({'if': equalRow(stateKey(None,'round'),self.maxRounds-1), True: setToConstantMatrix(key,self.payoff[agts[i]][self.maxRounds]), False: noChangeMatrix(key)}) self.world.setDynamics(stateKey(agts[i],'money'),action,tree) # really need to ask david about these levels - if adding modesl with levels, can # the true model point to these but have a different level for agent in self.world.agents.values(): agent.addModel('Christian',R={},level=2,rationality=10.,selection='distribution') agent.addModel('Capitalist',R={},level=2,rationality=10.,selection='distribution')
class TestAgents(unittest.TestCase): def setUp(self): # Create world self.world = World() # Create agents self.tom = Agent('Tom') self.world.addAgent(self.tom) self.jerry = Agent('Jerry') self.world.addAgent(self.jerry) def addStates(self): """Create state features""" self.world.defineState(self.tom.name,'health',int,lo=0,hi=100, description='%s\'s wellbeing' % (self.tom.name)) self.world.setState(self.tom.name,'health',50) self.world.defineState(self.jerry.name,'health',int,lo=0,hi=100, description='%s\'s wellbeing' % (self.jerry.name)) self.world.setState(self.jerry.name,'health',50) def addActions(self): """Create actions""" self.chase = self.tom.addAction({'verb': 'chase','object': self.jerry.name}) self.hit = self.tom.addAction({'verb': 'hit','object': self.jerry.name}) self.run = self.jerry.addAction({'verb': 'run away'}) self.trick = self.jerry.addAction({'verb': 'trick','object': self.tom.name}) def addDynamics(self): """Create dynamics""" tree = makeTree(incrementMatrix(stateKey(self.jerry.name,'health'),-10)) self.world.setDynamics(stateKey(self.jerry.name,'health'),self.hit,tree,enforceMin=True) def addModels(self,rationality=1.): self.tom.addModel('friend',rationality=rationality,parent=True) self.tom.setReward(maximizeFeature(stateKey(self.jerry.name,'health')),1.,'friend') self.tom.addModel('foe',rationality=rationality,parent=True) self.tom.setReward(minimizeFeature(stateKey(self.jerry.name,'health')),1.,'foe') def saveload(self): """Write scenario to file and then load from scratch""" self.world.save('/tmp/psychsim_test.psy') self.world = World('/tmp/psychsim_test.psy') self.tom = self.world.agents[self.tom.name] self.jerry = self.world.agents[self.jerry.name] def testEnumeratedState(self): self.addActions() self.world.defineVariable(self.tom.name,ActionSet) self.world.defineState(self.tom.name,'status',list,['dead','injured','healthy']) self.world.setState(self.tom.name,'status','healthy') goal = achieveFeatureValue(stateKey(self.tom.name,'status'),'healthy') self.tom.setReward(goal,1.) goal = achieveFeatureValue(stateKey(self.tom.name,'status'),'injured') self.jerry.setReward(goal,1.) self.saveload() self.assertEqual(len(self.world.state),1) vector = self.world.state.domain()[0] tVal = self.tom.reward(vector) self.assertAlmostEqual(tVal,1.,8) jVal = self.jerry.reward(vector) self.assertAlmostEqual(jVal,0.,8) for action in self.tom.actions: encoding = self.world.value2float(self.tom.name,action) self.assertEqual(action,self.world.float2value(self.tom.name,encoding)) def testBeliefModels(self): self.addStates() self.addActions() self.addDynamics() self.world.setOrder([self.tom.name]) self.tom.addModel('optimist') self.tom.setBelief(stateKey(self.jerry.name,'health'),20,'optimist') self.tom.addModel('pessimist') self.world.setModel(self.jerry.name,True) self.world.setMentalModel(self.jerry.name,self.tom.name,{'optimist': 0.5,'pessimist': 0.5}) actions = {self.tom.name: self.hit} self.world.step(actions) vector = self.world.state.domain()[0] beliefs = self.jerry.getAttribute('beliefs',self.world.getModel(self.jerry.name,vector)) for belief in beliefs.domain(): model = self.world.getModel(self.tom.name,belief) if self.tom.models[model].has_key('beliefs'): nested = self.tom.models[model]['beliefs'] self.assertEqual(len(nested),1) nested = nested.domain()[0] self.assertEqual(len(nested),1) self.assertAlmostEqual(nested[stateKey(self.jerry.name,'health')],10.,8) def testObservation(self): self.addStates() self.addActions() self.addDynamics() self.world.setOrder([self.tom.name]) self.world.setModel(self.jerry.name,True) key = stateKey(self.jerry.name,'health') self.jerry.setBelief(key,Distribution({20: 0.5, 50: 0.5})) tree = makeTree({'if': thresholdRow(key,40), True: {'distribution': [(KeyedVector({CONSTANT: 50}),.8), (KeyedVector({CONSTANT: 20}),.2)]}, False: {'distribution': [(KeyedVector({CONSTANT: 50}),.2), (KeyedVector({CONSTANT: 20}),.8)]}}) self.jerry.defineObservation(key,tree) actions = {self.tom.name: self.hit} vector = self.world.state.domain()[0] omegaDist = self.jerry.observe(vector,actions) for omega in omegaDist.domain(): new = KeyedVector(vector) model = self.jerry.index2model(self.jerry.stateEstimator(vector,new,omega)) beliefs = self.jerry.models[model]['beliefs'] if omega[key] > 30: # We observed a high value, so we should have a stronger belief in the higher value # which is now 40 after the hit for belief in beliefs.domain(): if beliefs[belief] > 0.5: self.assertAlmostEqual(belief[key],40,8) else: self.assertAlmostEqual(belief[key],10,8) else: # We observed a low value, so we should have a stronger belief in the lower value # which is now 10 after the hit for belief in beliefs.domain(): if beliefs[belief] < 0.5: self.assertAlmostEqual(belief[key],40,8) else: self.assertAlmostEqual(belief[key],10,8) def testUnobservedAction(self): self.addStates() self.addActions() self.addDynamics() self.addModels() self.world.setOrder([self.tom.name]) self.world.setModel(self.jerry.name,True) self.jerry.setBelief(stateKey(self.jerry.name,'health'),50) self.world.setMentalModel(self.jerry.name,self.tom.name,{'friend': 0.5,'foe': 0.5}) tree = makeTree(True) self.jerry.defineObservation(self.tom.name,tree,self.hit,domain=ActionSet) tree = makeTree({'distribution': [(True,0.25),(False,0.75)]}) self.jerry.defineObservation(self.tom.name,tree,self.chase,domain=ActionSet) vector = self.world.state.domain()[0] self.saveload() self.world.step({self.tom.name: self.hit}) vector = self.world.state.domain()[0] def testRewardModels(self): self.addStates() self.addActions() self.addDynamics() self.addModels() self.world.setOrder([self.tom.name]) # Add Jerry's model to the world (so that it gets updated) self.world.setModel(self.jerry.name,True) # Give Jerry uncertainty about Tom self.world.setMentalModel(self.jerry.name,self.tom.name,{'friend': 0.5,'foe': 0.5}) self.saveload() # Hitting should make Jerry think Tom is more of a foe actions = {self.tom.name: self.hit} self.world.step(actions) vector = self.world.state.domain()[0] belief01 = self.jerry.getAttribute('beliefs',self.world.getModel(self.jerry.name,vector)) key = modelKey(self.tom.name) for belief in belief01.domain(): if self.tom.index2model(belief[key]) == 'foe': prob01 = belief01[belief] break self.assertGreater(prob01,0.5) # If we think of Tom as even more of an optimizer, then our update should be stronger self.tom.setAttribute('rationality',10.,'foe') self.tom.setAttribute('rationality',10.,'friend') self.world.setMentalModel(self.jerry.name,self.tom.name,{'friend': 0.5,'foe': 0.5}) self.world.step(actions) vector = self.world.state.domain()[0] model = self.world.getModel(self.jerry.name,vector) belief10 = self.jerry.getAttribute('beliefs',model) key = modelKey(self.tom.name) for belief in belief10.domain(): if self.tom.index2model(belief[key]) == 'foe': prob10 = belief10[belief] break self.assertGreater(prob10,prob01) # If we keep the same models, but get another observation, we should update even more self.world.step(actions) vector = self.world.state.domain()[0] model = self.world.getModel(self.jerry.name,vector) belief1010 = self.jerry.getAttribute('beliefs',model) key = modelKey(self.tom.name) for belief in belief1010.domain(): if self.tom.index2model(belief[key]) == 'foe': prob1010 = belief1010[belief] break self.assertGreater(prob1010,prob10) def testDynamics(self): self.world.setOrder([self.tom.name]) self.addStates() self.addActions() self.addDynamics() key = stateKey(self.jerry.name,'health') self.assertEqual(len(self.world.state),1) vector = self.world.state.domain()[0] self.assertTrue(vector.has_key(stateKey(self.tom.name,'health'))) self.assertTrue(vector.has_key(turnKey(self.tom.name))) self.assertTrue(vector.has_key(key)) self.assertTrue(vector.has_key(CONSTANT)) self.assertEqual(len(vector),4) self.assertEqual(vector[stateKey(self.tom.name,'health')],50) self.assertEqual(vector[key],50) outcome = self.world.step({self.tom.name: self.chase}) for i in range(7): self.assertEqual(len(self.world.state),1) vector = self.world.state.domain()[0] self.assertTrue(vector.has_key(stateKey(self.tom.name,'health'))) self.assertTrue(vector.has_key(turnKey(self.tom.name))) self.assertTrue(vector.has_key(key)) self.assertTrue(vector.has_key(CONSTANT)) self.assertEqual(len(vector),4) self.assertEqual(vector[stateKey(self.tom.name,'health')],50) self.assertEqual(vector[key],max(50-10*i,0)) outcome = self.world.step({self.tom.name: self.hit}) self.saveload() def testRewardOnOthers(self): self.addStates() self.addActions() self.addDynamics() self.world.setOrder([self.tom.name]) vector = self.world.state.domain()[0] # Create Jerry's goals goal = maximizeFeature(stateKey(self.jerry.name,'health')) self.jerry.setReward(goal,1.) jVal = -self.jerry.reward(vector) # Create Tom's goals from scratch minGoal = minimizeFeature(stateKey(self.jerry.name,'health')) self.tom.setReward(minGoal,1.) self.saveload() tRawVal = self.tom.reward(vector) self.assertAlmostEqual(jVal,tRawVal,8) # Create Tom's goals as a function of Jerry's self.tom.models[True]['R'].clear() self.tom.setReward(self.jerry.name,-1.) self.saveload() tFuncVal = self.tom.reward(vector) self.assertAlmostEqual(tRawVal,tFuncVal,8) # Test effect of functional reward on value function self.tom.setHorizon(1) self.saveload() vHit = self.tom.value(vector,self.hit)['V'] vChase = self.tom.value(vector,self.chase)['V'] self.assertAlmostEqual(vHit,vChase+.1,8) def testReward(self): self.addStates() key = stateKey(self.jerry.name,'health') goal = makeTree({'if': thresholdRow(key,5), True: KeyedVector({key: -2}), False: KeyedVector({key: -1})}) self.jerry.setReward(goal,1.) R = self.jerry.models[True]['R'] self.assertEqual(len(R),1) self.assertEqual(R.keys()[0],goal) self.assertAlmostEqual(R[goal],1.,8) self.jerry.setReward(goal,2.) self.assertEqual(len(R),1) self.assertEqual(R.keys()[0],goal) self.assertAlmostEqual(R[goal],2.,8) def testTurnDynamics(self): self.addStates() self.addActions() self.world.setOrder([self.tom.name,self.jerry.name]) self.assertEqual(self.world.maxTurn,1) self.saveload() vector = self.world.state.domain()[0] jTurn = turnKey(self.jerry.name) tTurn = turnKey(self.tom.name) self.assertEqual(self.world.next(),[self.tom.name]) self.assertEqual(vector[tTurn],0) self.assertEqual(vector[jTurn],1) self.world.step() vector = self.world.state.domain()[0] self.assertEqual(self.world.next(),[self.jerry.name]) self.assertEqual(vector[tTurn],1) self.assertEqual(vector[jTurn],0) self.world.step() vector = self.world.state.domain()[0] self.assertEqual(self.world.next(),[self.tom.name]) self.assertEqual(vector[tTurn],0) self.assertEqual(vector[jTurn],1) # Try some custom dynamics self.world.setTurnDynamics(self.tom.name,self.hit,makeTree(noChangeMatrix(tTurn))) self.world.setTurnDynamics(self.jerry.name,self.hit,makeTree(noChangeMatrix(tTurn))) self.world.step() vector = self.world.state.domain()[0] self.assertEqual(self.world.next(),[self.tom.name]) self.assertEqual(vector[tTurn],0) self.assertEqual(vector[jTurn],1) self.world.step({self.tom.name: self.chase}) vector = self.world.state.domain()[0] self.assertEqual(self.world.next(),[self.jerry.name]) self.assertEqual(vector[tTurn],1) self.assertEqual(vector[jTurn],0) def testStatic(self): self.addStates() self.addActions() self.addDynamics() self.addModels() self.world.setModel(self.jerry.name,True) self.world.setMentalModel(self.jerry.name,self.tom.name,{'friend': 0.5,'foe': 0.5}) self.world.setOrder([self.tom.name]) vector = self.world.state.domain()[0] model = self.world.getModel(self.jerry.name,vector) belief0 = self.jerry.models[model]['beliefs'] self.world.step() vector = self.world.state.domain()[0] model = self.world.getModel(self.jerry.name,vector) belief1 = self.jerry.models[model]['beliefs'] key = modelKey(self.tom.name) for vector in belief0.domain(): if self.tom.index2model(vector[key]) == 'friend': self.assertGreater(belief0[vector],belief1[vector]) else: self.assertGreater(belief1[vector],belief0[vector]) # Now with the static beliefs self.jerry.setAttribute('static',True,model) self.saveload() self.world.step() vector = self.world.state.domain()[0] model = self.world.getModel(self.jerry.name,vector) belief2 = self.jerry.models[model]['beliefs'] for vector in belief1.domain(): self.assertAlmostEqual(belief1[vector],belief2[vector],8)
def hasAction(self,atom): if atom['subject'] == self.name and atom['verb'] == self.verbName and \ atom['object'] in self.objects: return True else: return Agent.hasAction(self,atom)
return { 'distribution': [(setTrueMatrix(key), prob), (setFalseMatrix(key), 1. - prob)] } def noisyOr(onCount, onProb, leak=0.): return 1. - (1. - leak) * pow(1. - onProb, onCount) if __name__ == '__main__': world = World() world.diagram = diagram.Diagram() world.diagram.setColor(None, 'ivory') resident = Agent('resident') world.diagram.setColor(resident.name, 'palegreen') world.addAgent(resident) # family = Agent('family') # world.diagram.setColor(family.name,'mediumseagreen') # world.addAgent(family) gov = Agent('government') world.diagram.setColor(gov.name, 'cornflowerblue') world.addAgent(gov) world.setOrder([resident.name]) # Keep track of orthogonal dimensions of decision-making phase = world.defineState( None, 'phase',
DEBUG = False def get_fake_model_name(agent): return 'fake {} model'.format(agent.name) if __name__ == '__main__': # sets up log to screen logging.basicConfig(format='%(message)s', level=logging.DEBUG if DEBUG else logging.INFO) # create world and add agents world = World() ag_producer = Agent('Producer') world.addAgent(ag_producer) ag_consumer = Agent('Consumer') world.addAgent(ag_consumer) agents = [ag_producer, ag_consumer] # agent settings ag_producer.setAttribute('discount', 1) ag_producer.setHorizon(HORIZON) ag_consumer.setAttribute('discount', 1) ag_consumer.setHorizon(HORIZON) # add variables (capacity and asked/received amounts) var_half_cap = world.defineState(ag_producer.name, 'half capacity', bool) world.setFeature(var_half_cap, False) var_ask_amnt = world.defineState(ag_producer.name,
def __init__(self): self.world = World() stacy = Agent('Stacy') david = Agent('David') agts = [stacy, david] totalAmt = 4 # Player state, actions and parameters common to both players for i in range(2): me = agts[i] other = agts[1-i] self.world.addAgent(me) self.world.defineState(me.name,'offered',int,lo=0,hi=totalAmt) self.world.defineState(me.name,'money',int,lo=0,hi=totalAmt) me.setState('offered',0) me.setState('money',0) if (me.name == 'Stacy'): for amt in range(totalAmt + 1): me.addAction({'verb': 'offer','object': other.name,'amount': amt}) else: mePass = me.addAction({'verb': 'accept','object': other.name}) mePass = me.addAction({'verb': 'reject','object': other.name}) # Parameters me.setHorizon(2) me.setParameter('discount',0.9) # me.setParameter('discount',1.0) # Levels of belief david.setRecursiveLevel(3) stacy.setRecursiveLevel(3) self.world.setOrder(['Stacy','David']) # World state self.world.defineState(None,'gameOver',bool,description='The current round') self.world.setState(None,'gameOver',False) self.world.addTermination(makeTree({'if': trueRow(stateKey(None,'gameOver')), True: True, False: False})) # offer dynamics atom = Action({'subject': 'Stacy','verb': 'offer', 'object': 'David'}) parties = [atom['subject'], atom['object']] for j in range(2): offer = stateKey(parties[j],'offered') amount = actionKey('amount') if j == 1 else '%d-%s' % (totalAmt,actionKey('amount')) tree = makeTree(setToConstantMatrix(offer,amount)) self.world.setDynamics(parties[j],'offered',atom,tree) # accept dynamics atom = Action({'subject': 'David','verb': 'accept', 'object': 'Stacy'}) parties = [atom['subject'], atom['object']] for j in range(2): offer = stateKey(parties[j],'offered') money = stateKey(parties[j],'money') tree = makeTree(setToFeatureMatrix(money,offer)) self.world.setDynamics(parties[j],'money',atom,tree) tree=makeTree(setTrueMatrix(stateKey(None,'gameOver'))) self.world.setDynamics(None,'gameOver',atom,tree) # reject dynamics atom = Action({'subject': 'David','verb': 'reject', 'object': 'Stacy'}) tree=makeTree(setTrueMatrix(stateKey(None,'gameOver'))) self.world.setDynamics(None,'gameOver',atom,tree) # really need to ask david about these levels - if adding modesl with levels, can # the true model point to these but have a different level for agent in self.world.agents.values(): agent.addModel('Christian',R={},level=2,rationality=25.,selection='distribution') agent.addModel('Capitalist',R={},level=2,rationality=25.,selection='distribution')
def createWorld(numPlayers,regionTable,starts,generation='additive',maxResources=32): """ @param numPlayers: number of players in the game @type numPlayers: int @param regionTable: a table of regions, indexed by name @param starts: a list of starting regions, one for each player @param maxResources: the maximum number of resources a player may have @type maxResources: int """ world = ResourceWorld(allocateVerb='allocate',allocationState='invaders',winnerState='invader') # Create regions regions = set() for name,table in regionTable.items(): region = Agent(name) world.addAgent(region) regions.add(region) world.defineState(name,'occupants',int,lo=0,hi=maxResources, description='Number of resources in %s' % (region)) region.setState('occupants',table['occupants'] if table.has_key('occupants') else table['value']) world.defineState(name,'value',int,lo=0,hi=maxResources, description='Number of resources generated by %s' % (region)) region.setState('value',table['value']) world.defineState(name,'invaders',int,lo=0,hi=numPlayers*maxResources, description='Number of resources invading %s' % (region)) region.setState('invaders',0) world.dynamics[stateKey(region.name,'invaders')] = True # Create agents for human players players = [] for player in range(numPlayers): players.append(ResourceAgent('Player%d' % (player+1),'resources','allocate', [region.name for region in regions])) world.addAgent(players[player]) players[player].allocateAll = True world.defineState(players[player].name,'resources',int,lo=0,hi=maxResources, description='Number of total resources owned by %s' % (players[player].name), combinator='*') players[player].setState('resources',0) # Create agent for "enemy" enemy = Agent('Enemy') world.addAgent(enemy) owners = world.agents.keys() for region in regions: world.defineState(region.name,'owner',set,set(owners), description='Name of owner of %s' % (region)) region.setState('owner',enemy.name) world.defineState(region.name,'invader',set,set(owners)-{enemy.name}|{world.nullAgent}, description='Name of invader who will own %s if successful' % (region)) try: index = starts.index(region.name) region.setState('invader','Player%d' % (index+1)) except ValueError: region.setState('invader',world.nullAgent) world.dynamics[stateKey(region.name,'invader')] = True # Set players' initial territories for index in range(numPlayers): region = world.agents[starts[index]] region.setState('owner',players[index].name) # Players can invade only if enemy owns it and they (or teammate) own a neighboring country for region in regions: tree = False for neighbor in regionTable[region.name]['neighbors']: tree = {'if': equalRow(stateKey(neighbor,'owner'),enemy.name), True: tree, False: True} tree = makeTree({'if': equalRow(stateKey(region.name,'owner'),enemy.name), True: tree, False: False}) players[index].objectLegality[region.name] = tree.desymbolize(world.symbols) # Create region "action" for region in regions: region.addAction({'verb': 'generate'}) # Set order of play world.setOrder([set([region.name for region in regions]),set([player.name for player in players])]) # Winner determination for region in regions: # Determine the owner after determining who's invading world.addDependency(stateKey(region.name,'owner'),stateKey(region.name,'invader')) # Determine the winner of the invasion owner = stateKey(region.name,'owner') world.dynamics[owner] = True invader = stateKey(region.name,'invader') defenders = stateKey(region.name,'occupants') invaders = stateKey(region.name,'invaders') value = stateKey(region.name,'value') for player in players: resources = stateKey(player.name,'resources') # Determine how many resources lost action = Action({'subject': player.name,'verb': 'allocate','object': region.name}) world.addDependency(resources,invader) if generation == 'additive': # or generation == 'none': # Lose only those resources allocated tree = makeTree(incrementMatrix(resources,'-%s' % (actionKey('amount')))) else: # Lose all resources tree = makeTree(setToConstantMatrix(resources,0)) world.setDynamics(resources,action,tree) # Regain resources from owned territories action = Action({'subject': region.name,'verb': 'generate'}) if generation == 'additive' or generation == 'restorative': tree = makeTree({'if': equalRow(owner,player.name), True: addFeatureMatrix(resources,value), False: None}) elif generation == 'minimal': if region is world.agents[starts[int(player.name[-1])-1]]: # Get resources from home base (repeated) tree = makeTree({'if': equalRow(owner,player.name), True: addFeatureMatrix(resources,value), False: None}) else: # And any new winnings (one-time) tree = makeTree({'if': equalRow(owner,player.name), True: {'if': equalFeatureRow(owner,invader), True: addFeatureMatrix(resources,value), False: None}, False: None}) elif generation is 'none': if region is world.agents[starts[int(player.name[-1])-1]]: # Get resources from home base if below threshold tree = makeTree({'if': greaterThanRow(resources,value), True: None, False: setToFeatureMatrix(resources,value)}) else: tree = makeTree({'if': equalRow(owner,player.name), True: {'if': equalFeatureRow(owner,invader), True: addFeatureMatrix(resources,value), False: None}, False: None}) world.setDynamics(resources,action,tree) # The game has two phases: generating resources and allocating resources world.defineState(None,'phase',list,['generate','allocate'],combinator='*', description='The current phase of the game') world.setState(None,'phase','generate') key = stateKey(None,'phase') # If we generate, then the phase becomes allocate action = Action({'subject': list(regions)[0].name,'verb': 'generate'}) tree = makeTree(setToConstantMatrix(key,'allocate')) world.setDynamics(key,action,tree) # If we allocate, then the phase becomes generate tree = makeTree(setToConstantMatrix(key,'generate')) for region in regions: for player in players: action = Action({'subject': player.name,'verb': 'allocate','object': region.name}) world.setDynamics(key,action,tree) # Game ends when territory is all won tree = {'if': equalRow(key,'allocate'), True: True, False: False} for region in regions: tree = {'if': equalRow(stateKey(region.name,'owner'),enemy.name), True: False, False: tree} world.addTermination(makeTree(tree)) # Or if nobody has any resources vector = KeyedVector() for player in players: vector[stateKey(player.name,'resources')] = 1. tree = {'if': equalRow(stateKey(None,'phase'),'allocate'), True: {'if': KeyedPlane(vector,0.5), True: False, False: True}, False: False} world.addTermination(makeTree(tree)) # Keep track of which round it is world.defineState(None,'round',int,description='The current round of the game') world.setState(None,'round',0) action = Action({'subject': list(regions)[0].name, 'verb': 'generate'}) key = stateKey(None,'round') world.setDynamics(key,action,makeTree(incrementMatrix(key,1))) return world
} } }) if __name__ == '__main__': random.seed(0) # sets up log to screen logging.basicConfig(format='%(message)s', level=logging.DEBUG if DEBUG else logging.INFO) # create world and add agents world = World() agent1 = Agent('Agent 1') world.addAgent(agent1) agent2 = Agent('Agent 2') world.addAgent(agent2) sides = [] rights = [] lefts = [] agents = [agent1, agent2] for agent in agents: # set agent's params agent.setAttribute('discount', 1) agent.setHorizon(1) agent.setAttribute('selection', TIEBREAK)