def _validate_message_usage(self): msgs = set(self.messages) msg_reads = set() msg_posts = set() for agent_name, agent_def in self.agents.iteritems(): for st_name, st_class in agent_def.st_classes.iteritems(): label = "%s.%s" % (agent_name, st_name) mr = set(st_class.msg_reads) mp = set(st_class.msg_posts) msg_reads.update(mr) msg_posts.update(mp) undef = mr - msgs validate(not undef, "Undefined message in %s.msg_reads: %s" \ % (label, ", ".join(undef))) undef = mp - msgs validate(not undef, "Undefined message in %s.msg_posts: %s" \ % (label, ", ".join(undef))) for msg in msg_posts - msg_reads: warn("'%s' message is posted but never read." % msg) for msg in msg_reads - msg_posts: warn("'%s' message is read but never posted." % msg) for msg in msgs - msg_posts - msg_reads: warn("'%s' message is defined but never used." % msg)
def check_mem_access_declarations(self): # keep track of mem vars that have been read/written to mem_read = set() mem_written = set() # validate read/write declarations for each state transition function for name, inst in self.st_classes.iteritems(): fname = "%s.%s." % (self.name, name) self._val_rw_list(inst.reads, fname + "reads") self._val_rw_list(inst.writes, fname + "writes") self._val_rw_list(inst.msg_posts, fname + "msg_posts", "MSG") self._val_rw_list(inst.msg_reads, fname + "msg_reads", "MSG") mem_read.update(inst.reads) mem_written.update(inst.writes) msg_conflicts = set(inst.msg_posts).intersection(inst.msg_reads) validate(not msg_conflicts, "access conflict (read AND post) to mesage board - " "%s (%s.%s)" % (", ".join(msg_conflicts), self.name, name)) # validate read/write declarations for each state branch routine for name, inst in self.branches.iteritems(): fname = "%s.%s." % (self.branches, name) self._val_rw_list(inst.reads, fname + "reads") self._val_rw_list(inst.writes, fname + "writes") mem_read.update(inst.reads) mem_written.update(inst.writes) # ---- Check if all declared agent mem are actually used -- mem_all = set(self.memory.keys()) # check for unaccessed memory variables unused = mem_all - mem_read - mem_written for v in unused: warn("%s.%s is never accessed." % (self.name, v)) # written but never read unread = mem_written - mem_read for v in unread: warn("%s.%s is written to but never read." % (self.name, v)) # read but never written and not a constant unchanged = mem_read - mem_written for v in unchanged: if not self.memory[v]._constant: warn("%s.%s is never updated. " "Consider setting constant=True." % (self.name, v))
def __init__(self, agent_class): self.klass = agent_class self.name = agent_class.__name__ self.st_classes = None self.branches = None #self.state_graph = None # set by self.load_states() validate(issubclass(agent_class, Agent), "%s not a subclass of papaya.core.agent.Agent" % self.name) validate(not agent_class.abstract, "%s is an abstract agent class" % self.name) # load agent memory variables self.memory = dict((name, inst) for name, inst in inspect.getmembers(agent_class) if isinstance(inst, Variable)) if not self.memory: warn("No memory variables defined for %s" % self.name) self.load_st_and_branch_classes() self.check_mem_access_declarations() self.check_state_transitions_declarations()
def _val_rw_list(self, rw_list, label, dep_type="MEM"): validate(type(rw_list) in (list, tuple), "expecting %s to be a list or a tuple" % label) for v in rw_list: validate(type(v) == str, "%s should contain only strings" % label) if dep_type == "MEM": validate(v in self.memory, "invalid memory var %s declared in %s" % (v, label))
def __init__(self, msg_class): self.klass = msg_class self.name = msg_class.__name__ validate(issubclass(msg_class, Message), "%s is not a subclass of papaya.core.message.Message" % self.name) validate(not msg_class.abstract, "%s is an abstract message class" % self.name) self.params = dict((name, inst) for name, inst in inspect.getmembers(msg_class) if isinstance(inst, Variable)) validate(self.params, "No memory variables defined for message '%s'" % self.name)
return '\033[93m !! %s\033[0m\n' % (message,) warnings.formatwarning = warning_format try: # load settings.py from current directory try: import settings except ImportError: raise SetupError("settings.py not found") # initialise model loader model = ModelLoader() # load list of message modules msg_mod_list = getattr(settings, "message_modules", None) validate(msg_mod_list != None, "settings.message_modules not defined") # from each message module, load agents for m in msg_mod_list: model.load_messages(m) # load list of agent modules agent_mod_list = getattr(settings, "agent_modules", None) validate(agent_mod_list != None, "settings.agent_modules not defined") validate(type(agent_mod_list) in (list, tuple), "settings.agent_modules should be a tuple") validate(len(agent_mod_list) > 0, "settings.agent_modules is empty")
def check_state_transitions_declarations(self): conditions = set() st_used = set() br_used = set() validate(type(self.klass.state_transitions) == list, "%s.state_transitions must be a valid list" % self.name) for idx, st in enumerate(self.klass.state_transitions): validate(type(st) in (list, tuple), "%s.state_transitions[%d] should be a tuple" % (st, idx)) validate(len(st) == 3, "%s.state_transitions[%d] has %d entries, expecting 3" \ % (st, idx, len(st))) st_from, tf, st_to = st validate(type(st_from) == str and type(tf) == str and type(st_to) in (str, list, tuple), "%s.state_transitions[%d] contains non-string entries") if type(st_to) == str: validate(tf in self.st_classes, "%s.state_transitions[%d]: " "invalid transition function %s" % (self.name, idx, tf)) st_used.add(tf) else: validate(tf in self.branches, "%s.state_transitions[%d]: " "invalid branch function %s" % (self.name, idx, tf)) br_used.add(tf) for f, s, c in st_to: validate(f in self.st_classes, "%s.state_transitions[%d]: " "invalid transition function %s" % (self.name, idx, tf)) st_used.add(f) validate(c not in conditions, "%s.state_transitions[%d]: " "condition labels must be unique. " "Duplicate entry found - %s." % (self.name, idx, c)) conditions.add(c) for u in set(self.st_classes).difference(st_used): warn("Transition function %s.%s is not used." % (self.name, u)) for u in set(self.branches).difference(br_used): warn("Branch function %s.%s is not used." % (self.name, u))