Permalink
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
166 lines (126 sloc) 5.45 KB
import pyparsing as pp
from utils import unweave, areinstances
from agent import Agent, Budgeter, BudgetedAgent
from amplify.message import Message, Pointer, Channel, Referent, addressed_message
def HCH(H, n=int(1e8)):
return Budgeter(BudgetedHCH(H), n)
class BudgetedHCH(BudgetedAgent):
"""
HCH transforms an Agent that operates on text
into a better-resourced BudgetedAgent that operates on messages.
The total bandwidth of HCH(H) is limited by the bandwidth of H.
"""
def __init__(self, H, child_base=None, args=()):
self.H = H
self.args = args
#by default, children are copies of self
self.child_base = self if child_base is None else child_base
assert self.well_formed()
def child(self):
return self.child_base
def well_formed(self):
return (
isinstance(self.H, Agent) and
isinstance(self.child_base, BudgetedHCH) and
areinstances(self.args, Referent)
)
def act(self, obs, budget):
state = self
while True:
message = state.view_message(obs)
if budget < 0:
raise Exception("It really shouldn't be possible to get to < 0 budget.")
elif budget == 0:
message += "\n[You have no budget, type a message to reply]"
else:
message += "\n[Remaining budget is {}]".format(budget)
response, new_H = state.H.act(message)
state = BudgetedHCH(new_H, state.child_base, state.args + obs.args)
if budget <= 0:
return parse_message(response), state, 0
command = parse_command(response)
obs, done, return_value, spending = command.execute(state, budget)
budget -= spending
if done: return return_value, state, budget
def view_message(self, message):
n = len(self.args)
k = message.size
return message.format_with_indices(range(n, n+k))
#----commands
class Command(object):
def execute(self, env):
raise NotImplemented()
class Ask(Command):
def __init__(self, message, budget=None, recipient=None):
self.message = message
self.recipient_channel = recipient
self.budget = budget
def execute(self, env, budget):
default_budget = budget / 10
max_budget = budget - 1
sub_budget = min(max_budget, self.budget if self.budget is not None else default_budget)
message = addressed_message(env, self.message.instantiate(env.args))
if self.recipient_channel is None:
recipient = env.child()
else:
recipient = self.recipient_channel.instantiate(env.args).agent
response, recipient, remaining = recipient.act(message, sub_budget)
return addressed_message(recipient, response), False, None, sub_budget-remaining + 1
class View(Command):
def __init__(self, message):
self.message = message
def execute(self, env, budget):
return self.message.instantiate(env.args), False, None, 1
class Return(Command):
def __init__(self, message):
self.message = message
def execute(self, env, budget):
return None, True, self.message.instantiate(env.args), 1
class Reflect(Command):
def execute(self, env, budget):
return Message("you are []", Channel(env)), False, None, 1
class MalformedCommand(Command):
def execute(self, env, budget):
return Message("the valid commands are 'reply', 'ask', 'reflect', 'view', and 'ask@N'"), False, None, 1
#----parsing
def parse_command(s):
try:
return command.parseString(s, parseAll=True)[0]
except pp.ParseException:
return MalformedCommand()
def parse_message(s):
try:
return message.parseString(s, parseAll=True)[0]
except pp.ParseException:
return Message("<<malformed message>>")
def raw(s):
return pp.Literal(s).suppress()
number = pp.Word("0123456789").setParseAction(lambda t : int(t[0]))
prose = pp.Word(" ,!?+-/*.;:_<>=&%{}[]\'\"" + pp.alphas).leaveWhitespace()
agent_referent = (raw("@")+ number).leaveWhitespace()
agent_referent.setParseAction(lambda x : Pointer(x[0], Channel))
message_referent = (raw("#") + number).leaveWhitespace()
message_referent.setParseAction(lambda x : Pointer(x[0], Message))
message = pp.Forward()
submessage = raw("(") + message + raw(")")
argument = submessage | agent_referent | message_referent
literal_message = (
pp.Optional(prose, default="") +
pp.ZeroOrMore(argument + pp.Optional(prose, default=""))
).setParseAction(lambda xs : Message(tuple(unweave(xs)[0]), *unweave(xs)[1]))
message << (message_referent ^ literal_message)
target_modifier = raw("@")+number
target_modifier.setParseAction(lambda xs : ("recipient", Pointer(xs[0], type=Channel)))
budget_modifier = raw("$")+number
budget_modifier.setParseAction(lambda xs : ("budget", xs[0]))
ask_modifiers = pp.ZeroOrMore(target_modifier ^ budget_modifier)
ask_modifiers.setParseAction(lambda xs : dict(list(xs)))
ask_command = (raw("ask")) + ask_modifiers + message
ask_command.setParseAction(lambda xs : Ask(xs[1], **xs[0]))
reply_command = (raw("reply") | raw("return")) + message
reply_command.setParseAction(lambda xs : Return(xs[0]))
reflect_command = raw("reflect")
reflect_command.setParseAction(lambda xs : Reflect())
view_command = raw("view") + message
view_command.setParseAction(lambda xs : View(xs[0]))
command = ask_command | reply_command | reflect_command | view_command