def main(rl): """ Runs the monitor snapshot until clock reaches or exceeds run length. Then closes monitor. :param rl: run length :return: None """ monitor = specification.Monitor() clock = 0 while clock < rl: driver = GraphDatabase.driver(specification.database_uri, auth=specification.Monitor_auth, max_connection_lifetime=20000) with driver.session() as session: # modifying and redrawing plot over time and saving plot rather than an animation session.write_transaction(monitor.snapshot, clock) tx = session.begin_transaction() current_time = intf.gettime(tx) while clock == current_time: current_time = intf.gettime(tx) clock = current_time driver.close() print("Monitor Capture complete") driver = GraphDatabase.driver(specification.database_uri, auth=specification.Monitor_auth, max_connection_lifetime=2000) with driver.session() as session: session.write_transaction(monitor.close) driver.close() print("Monitor closed")
def main(rl, ps): """ Checks population levels meet requirements and adds additional agents if needed until clock reaches or exceeds run length :param rl: run length :param ps: population size :return: None """ clock = 0 agent = specification.Agents(None) while clock < rl: dri = GraphDatabase.driver(specification.database_uri, auth=specification.Population_auth, max_connection_lifetime=2000) with dri.session() as ses: populationdeficite = specification.Population.check(ses, ps) if populationdeficite: for i in range(populationdeficite): ses.write_transaction(agent.generator, specification.Population.params) tx = ses.begin_transaction() time = intf.gettime(tx) while clock == time: time = intf.gettime(tx) clock = time dri.close() print("Population closed")
def talk(self, tx): """ Determine if agent forms a new social link with random co-located agent based on their social values and shortest social path :param tx: neo4j write transaction :return: None """ super(Patient, self).talk(tx) if self.colocated: newcontacts = [ nc for nc in self.colocated if nc not in self.contacts ] if newcontacts: if len(newcontacts) > 1: newfriend = npr.sample(newcontacts) else: newfriend = newcontacts # Based on relative social values and length of shortest path set probability for forming link with a # randomly sampled co-located unknown agent. social from 2-8 per agent, combined from 4-16. So combined -4 # over 24 gives value between 0 and 0.5 plus the if minimum path greater than 6 nothing, else from m=2-6 # then 1/(2m-2) gives 0.1-0.5 (m=1 or 0 means itself or already connected). prob1 = (newfriend.end_node["social"] + self.social - 4) / 24 sp = intf.shortestpath(tx, self.id, newfriend.end_node["id"], 'Agent', 'Social') if sp < 2: prob2 = 0 elif sp > 6: prob2 = 0 else: prob2 = 1 / (2 * sp - 2) if npr.random(1) <= (prob1 + prob2): # form friend link intf.createedge( self.id, newfriend.end_node["id"], 'Agent', 'Agent', 'SOCIAL:FRIEND', 'created: ' + intf.gettime() + ', usage: ' + intf.gettime() + ', carer: False') self.contacts = newfriend else: self.contacts = None else: self.contacts = None else: self.contacts = None
def react(self, tx): """ If the agent now has more social bonds than they can manage we drop new non carer friends then those not used recently and finally reduce the carers from most recent. :param tx: neo4j write transaction :return: None """ super(Patient, self).react(tx) self.contacts = intf.agentcontacts(tx, self.id, "Agent") carers = self.contacts + intf.agentcontacts(tx, self.id, "Agent", "Carer") if len(self.contacts) > self.social: while len(carers) > self.social: carer_drop = None latest_time = 0 for carer in carers: if carer["created"] > latest_time: carer_drop = carer latest_time = carer["created"] intf.deletecontact(tx, self.id, carer_drop.end_node["id"], "Agent", "Carer") if len(carers) == self.social: for contact in contacts: intf.deletecontact(tx, self.id, contact.end_node["id"], "Agent", "Agent") if len(carers) + len(contacts) > self.social: for contact in contacts: if len(carers) + len(contacts) > self.social: if intf.gettime() - contact['created'] < 5: intf.deletecontact(tx, self.id, contact.end_node["id"], "Agent", "Agent") oldest_usage = 0 contact_drop = None while len(carers) + len(contacts) > self.social: for contact in contacts: if intf.gettime() - contact["usage"] > oldest_usage: contact_drop = contact oldest_usage = intf.gettime() - contact["usage"] intf.deletecontact(tx, self.id, contact_drop.end_node["id"], "Agent", "Agent")
def listen(self, tx): """ If the agent has a new social link check if the new friend has a link to a carer if they do for a random carer they form a link with a .5 chance. :param tx: neo4j write transaction :return: None """ super(Patient, self).listen(tx) if self.contacts: carers = intf.agentcontacts(tx, self.contacts.end_node["id"], "Agent", "Carer") carers = [carer for carer in carers if carer["carer"]] carer = npr.sample(carers) if npr.random(1) < 0.5: intf.createedge( self.id, carer.end_node["id"], 'Patient', 'Carer', 'SOCIAL:FRIEND', 'created: ' + intf.gettime() + ', usage: ' + intf.gettime() + ', carer: True')
def generate_population(tx, ps): """ Generates the required number of agents and starts them at the Home node. Builds social connections between agents. :param tx: neo4j database write transaction :param ps: population size :return: None """ fa = Patient(None) for j in range(ps // 4): tx.run("CREATE (a:Carer {id:{j_id}, energy:20})", j_id=j) for i in range(ps): fa.generator(tx, [0.8, 0.9, 1, [2, 0, 1, 2], 2, 8]) if npr.random(1) < 0.5: if npr.random(1) < 0.5: samplesize = 2 else: samplesize = 1 newfriends = npr.choice(range(ps // 4), size=samplesize, replace=False) for nf in newfriends: intf.createedge( tx, i, nf, 'Agent', 'Carer', 'SOCIAL', 'created: ' + str(intf.gettime(tx)) + ', usage: ' + str(intf.gettime(tx)) + ', carer: True') intf.createedge(tx, i, nf, 'Agent', 'Carer', 'FRIEND') for i in range(ps): newfriends = npr.choice(range(ps), size=npr.choice(range(3)), replace=False) for nf in newfriends: if not nf == i: intf.createedge( tx, i, nf, 'Agent', 'Agent', 'SOCIAL', 'created: ' + str(intf.gettime(tx)) + ', usage: ' + str(intf.gettime(tx)) + ', carer: False') intf.createedge(tx, i, nf, 'Agent', 'Agent', 'FRIEND')
def main(rl): """ Implements a FlowReaction repeatedly until the clock in the database reaches the run length. :param rl: run length :return: None """ flowreaction = specification.Balancer.FlowReaction() clock = 0 while clock < rl: dri = GraphDatabase.driver(specification.database_uri, auth=specification.Balancer_auth, max_connection_lifetime=2000) with dri.session() as ses: ses.write_transaction(flowreaction.applyrules) tx = ses.begin_transaction() time = intf.gettime(tx) while clock == time: time = intf.gettime(tx) clock = time dri.close() print("Balancer closed")
def timesincedischarge(txl): """ Utility function reports the time between any hospital discharge and attending an intervention. Only recorded if both events occur. :param txl: neo4j database write transaction :return: list of times in integer timesteps """ times = [] agents = intf.getnodeagents(txl, "Intervention", "name") for agent in agents: log = parselog(agent["log"]) log.reverse() lasthosdis = [entry for entry in log if entry[0] == "Hos discharge"] if lasthosdis: lasthosdis = lasthosdis[0] times = times + [intf.gettime(txl) - lasthosdis[1]] return times
def update(self, tx): """ Check agent contacts compare list with co-located agents and update co-located contacts with new last usage :param tx: neo4j database write transaction :return: None """ super(Patient, self).update(tx) # Update existing com links with latest co-location self.contacts = intf.agentcontacts(tx, self.id, "Patient") if self.contacts and self.colocated: update = [ contact for contact in self.contacts if contact in self.colocated ] for contact in update: intf.updatecontactedge(tx, contact.end_node["id"], self.id, "last_usage", intf.gettime())
def agentsready(self, tx): """ Identifies the set of current agents for processing, either the correct set in the queue or all the agents at the node. It checks for unqueued agents in nodes with queue and runs the nodes prediction function to add them to the queue. It then gathers the agents local environment perception and passes that to the agent when calling the move function. We then delete the part of the queue that has been processed to save space. Subclass must implement this function for any aspects unique to model. :param tx: neo4j write transaction :return: None """ agents = intf.getnodeagents(tx, self.name, "name") clock = intf.gettime(tx) if self.queue or self.queue == {}: queueagents = [ key for time in self.queue.keys() for key in self.queue[time].keys() ] newagents = [ag for ag in agents if ag["id"] not in queueagents] # run prediction on each unqueued agent for ag in newagents: self.agentprediction(tx, ag) for ag in agents: if self.queue: if clock in self.queue.keys(): if ag["id"] in self.queue[clock].keys(): agper = self.agentperception( tx, ag, self.queue[clock][ag["id"]][0], self.queue[clock][ag["id"]]) specification.Agent(ag["id"]).move(tx, agper) else: agper = self.agentperception(tx, ag) specification.Agent(ag["id"]).move(tx, agper) if self.queue and clock in self.queue.keys(): del self.queue[clock]
def payment(self, tx): """ Modifies chosen edge and agent. These include mobility, confidence and energy modifications. :param tx: neo4j database write transaction :return: None """ super(Patient, self).payment(tx) # Deduct energy used on edge if "energy" in self.choice.keys(): if "energy" in self.choice.end_node.keys(): if self.choice["energy"] + self.choice.end_node[ "energy"] > self.current_energy: # Check for carers carers = intf.agentcontacts(tx, self.id, "Agent", "Carer") # Check for sufficient energy for carer in carers: print(carer) if carer.end_node["energy"] >= self.choice["energy"]: intf.updatenode(tx, carer.end_node["id"], "energy", carer.end_node["energy"] - self.choice["energy"], label='Carer') self.current_energy = self.current_energy + self.choice[ "energy"] intf.updateagent(tx, self.id, "energy", self.current_energy) intf.updatecontactedge(tx, self.id, carer.end_node["id"], "usage", intf.gettime(tx), "Agent", "Carer") break else: return False self.current_energy = npr.normal(self.choice["energy"], 0.05) + self.current_energy intf.updateagent(tx, self.id, "energy", self.current_energy) # mod variables based on edges if "modm" in self.choice: self.mobility = self.positive( npr.normal(self.choice["modm"], 0.05) + self.mobility) intf.updateagent(tx, self.id, "mob", self.mobility) if self.mobility == 0: if self.wellbeing != "Fallen": self.wellbeing = "Fallen" intf.updateagent(tx, self.id, "wellbeing", self.wellbeing) clock = tx.run("MATCH (a:Clock) " "RETURN a.time").values()[0][0] self.log = self.log + ", (Fallen, " + str(clock) + ")" elif self.mobility > 1: if self.wellbeing != "Healthy": self.wellbeing = "Healthy" intf.updateagent(tx, self.id, "wellbeing", self.wellbeing) clock = tx.run("MATCH (a:Clock) " "RETURN a.time").values()[0][0] self.log = self.log + ", (Healthy, " + str(clock) + ")" elif self.mobility <= 1: if self.wellbeing == "Healthy": self.wellbeing = "At risk" intf.updateagent(tx, self.id, "wellbeing", self.wellbeing) clock = tx.run("MATCH (a:Clock) " "RETURN a.time").values()[0][0] self.log = self.log + ", (At risk, " + str(clock) + ")" if "modmood" in self.choice: self.mood = self.positive( npr.normal(self.choice["modmood"], 0.05) + self.mood) intf.updateagent(tx, self.id, "mood", self.mood) return True