def perception(self, tx, perc): """ Patient perception function. Filters based on agent having sufficient energy for edge and end node. :param tx: neo4j write transaction :param perc: perception recieved from the node :return: None """ super(Patient, self).perception(tx, perc) if type(self.view) == list: edges = self.view else: edges = [self.view] # filter out options requiring too much energy valid_edges = [] self.mobility = intf.getnodevalue(tx, self.id, "mob", "Patient") self.energy = intf.getnodevalue(tx, self.id, "energy", "Patient") self.current_energy = self.energy if len(self.view) > 1: for edge in edges: if not edge.end_node["name"] in ["Care", "GP", "Hos"]: cost = 0 if edge.end_node["energy"]: cost = cost + edge.end_node["energy"] if self.energy > -cost: valid_edges = valid_edges + [edge] else: valid_edges = self.view self.view = valid_edges
def choose(self, tx, perc): """ Patients conscious choice from possible edges. This is based on the patients mood exceeds the current threshold for that edge. If the agent has the mood for multiple choices the final choice is made as a weighted sampling of all possible choices with weights based on the Patients inclination applied to the types of edges. :param tx: neo4j database write transaction :param perc: perception from node perception function. :return: single edge as final choice """ super(Patient, self).choose(tx, perc) # filter out options where the agent does not reach the mood threshold options = [] self.mood = intf.getnodevalue(tx, self.id, "mood", "Patient") self.inclination = intf.getnodevalue(tx, self.id, "inclination", "Patient") self.log = intf.getnodevalue(tx, self.id, "log", "Patient") self.wellbeing = intf.getnodevalue(tx, self.id, "wellbeing", "Patient") self.referral = intf.getnodevalue(tx, self.id, "referral", "Patient") if len(self.view) < 2: if type(self.view) == list and self.view: choice = self.view[0] else: choice = self.view else: for edge in self.view: if edge["mood"] <= self.mood: options = options + [edge] # choose based on random sample bias by patients inclination if not options: return None types = [edge["type"] for edge in options] edge_types = ["social", "fall", "medical", "inactive"] types = [edge_types.index(lable) for lable in types] weights = [ self.positive(self.inclination[label]) for label in types ] if sum(weights): weights = [w / sum(weights) for w in weights] sample = npr.choice(range(len(options)), 1, p=weights) else: sample = npr.choice(range(len(options)), 1) choice = options[sample[0]] return choice
def logging(self, tx, entry): """ Utility function for adding information to the agents log of its activities :param tx: neo4j database write transaction :param entry: String to be added to the log :return: None """ self.log = intf.getnodevalue(tx, self.id, "log", "Agent") self.log = self.log + ", (" + entry + ")" intf.updateagent(tx, self.id, "log", str(self.log))
def look(self, tx): """ If not at home, find co-located agents :param tx: neo4j database write transaction :return: None """ super(Patient, self).look(tx) self.id = self.id[0] # If not at home, find co-located agents if intf.locateagent(tx, self.id)["name"] != "Home": self.colocated = intf.colocated(tx, self.id) self.social = intf.getnodevalue(tx, self.id, "social", "Agent")
def choose(self, tx, perc): """ Agents conscious choice from possible edges. This is based on the effort of the agent calculated from the combination of agent and edge values. If the agent has the effort for multiple choices the worth of the edge is used as a deciding factor. :param tx: neo4j database write transaction :param perc: perception from node perception function. :return: single edge as final choice """ super(FallAgent, self).choose(tx, perc) # filter out options where the agent does not reach the effort threshold options = [] self.confidence = intf.getnodevalue(tx, self.id, "conf", "Agent") self.mobility_resources = intf.getnodevalue(tx, self.id, "mob_res", "Agent") self.confidence_resources = intf.getnodevalue(tx, self.id, "conf_res", "Agent") self.log = intf.getnodevalue(tx, self.id, "log", "Agent") self.wellbeing = intf.getnodevalue(tx, self.id, "wellbeing", "Agent") self.referral = intf.getnodevalue(tx, self.id, "referral", "Agent") if len(self.view) < 2: if type(self.view) == list and self.view: choice = self.view[0] else: choice = self.view else: for edge in self.view: if edge["effort"] <= edge["mobility"] * (self.mobility + self.confidence * self.mobility_resources) + \ edge["confidence"] * (self.confidence + self.mobility * self.confidence_resources): options = options + [edge] # choose based on current highest worth edge ignores edges with no worth score, these are not choosable # edges, they are primarily edges indicating a fall if not options: return None choice = options[0] for edge in options: if "worth" in edge and "worth" in choice: if edge["worth"] > choice["worth"]: choice = edge elif "worth" in edge: choice = edge return choice
def snapshot(self, txl, ctime): """ Captures the current statistics of the system and updates graph grid, including average system interval, intervention interval, average number of falls at end of system interval and proportions of population in each population category. :param txl: neo4j database write transaction :param ctime: current timestep :return: None """ look = txl.run("MATCH (n:Node) " "WHERE n.name = {node} " "RETURN n", node="Intervention") self.nrecord = look.values() if super(Monitor, self).snapshot(txl, ctime): # Update plot 1 - Int Cap # Update to track average number of each type of fall for people in care. [mild, moderate, severe, agents_n] = txl.run( "MATCH (n:Node) " "WHERE n.name={node} " "RETURN n.mild, n.moderate, n.severe, n.agents", node="Care").values()[0] if agents_n: self.y11 = pylab.append(self.y11, mild / agents_n) self.p11.set_data(self.t, self.y11) self.y12 = pylab.append(self.y12, moderate / agents_n) self.p12.set_data(self.t, self.y12) self.y13 = pylab.append(self.y13, severe / agents_n) self.p13.set_data(self.t, self.y13) if max([ mild / agents_n, moderate / agents_n, severe / agents_n ]) > self.y1: self.y1 = max([ mild / agents_n, moderate / agents_n, severe / agents_n ]) self.p11.axes.set_ylim(0.0, self.y1 + 1.0) self.p12.axes.set_ylim(0.0, self.y1 + 1.0) self.p13.axes.set_ylim(0.0, self.y1 + 1.0) else: self.y11 = pylab.append(self.y11, 0) self.p11.set_data(self.t, self.y11) self.y12 = pylab.append(self.y12, 0) self.p12.set_data(self.t, self.y12) self.y13 = pylab.append(self.y13, 0) self.p13.set_data(self.t, self.y13) # Update plot 2 - Hos to Int gaps = timesincedischarge(txl) if gaps: hiint = mean(timesincedischarge(txl)) self.y3storage = self.y3storage + [hiint] if len(self.y3storage) >= 10: self.y3storage = self.y3storage[-10:] if self.y3storage: self.y2 = pylab.append(self.y2, mean(self.y3storage)) if self.y < mean(self.y3storage): self.y = mean(self.y3storage) self.p2.set_data(self.t, self.y2) # Update plot 3 - Start to Care careint = intf.getnodevalue(txl, "Care", "interval", uid="name") if careint: scint = careint else: scint = 0 self.y3 = pylab.append(self.y3, scint) if self.y < scint: self.y = scint self.p3.set_data(self.t, self.y3) # Update plot 4 # Update plot showing distribution of well being in the general population. wb = txl.run( "MATCH (a:Agent)-[r:LOCATED]->(n:Node) " "WHERE NOT n.name={node} " "RETURN a.wellbeing", node="Care").values() wb = [val[0] for val in wb] healthy = wb.count("Healthy") / len(wb) at_risk = wb.count("At risk") / len(wb) fallen = wb.count("Fallen") / len(wb) self.y41 = pylab.append(self.y41, healthy) self.p41.set_data(self.t, self.y41) self.y42 = pylab.append(self.y42, at_risk) self.p42.set_data(self.t, self.y42) self.y43 = pylab.append(self.y43, fallen) self.p43.set_data(self.t, self.y43) if max([healthy, at_risk, fallen]) / len(wb) > self.y4: self.y4 = max([healthy, at_risk, fallen]) self.p41.axes.set_ylim(0.0, self.y4 + 1.0) self.p42.axes.set_ylim(0.0, self.y4 + 1.0) self.p43.axes.set_ylim(0.0, self.y4 + 1.0) # Update plot axes if self.x >= self.xmax - 1.00: self.p11.axes.set_xlim(0.0, self.x + 1.0) self.p12.axes.set_xlim(0.0, self.x + 1.0) self.p13.axes.set_xlim(0.0, self.x + 1.0) self.p2.axes.set_xlim(0.0, self.x + 1.0) self.p3.axes.set_xlim(0.0, self.x + 1.0) self.p41.axes.set_xlim(0.0, self.x + 1.0) self.p42.axes.set_xlim(0.0, self.x + 1.0) self.p43.axes.set_xlim(0.0, self.x + 1.0) self.xmax = self.x if self.y > self.ymax1 - 1.0: self.p2.axes.set_ylim(0.0, self.y + 1.0) self.p3.axes.set_ylim(0.0, self.y + 1.0) if self.show: plt.pause(0.0005)
def adjustcapasity(txl, history, dynamic=True): """ Rule function that applies the capacity change algorithm in the case of two intervention node systems. This is uses a history variable that is cleared when the capacity is adjusted so that another five timesteps must pass before the capacity can be changed again. This only modifies OpenIntervention if dynamic is true else only intervention is modified. :param txl: neo4j database write transaction :param history: List of previous average times since discharge :param dynamic: indicates if adjustment to OpenIntervention is needed :return: history """ currenttimes = timesincedischarge(txl) if not currenttimes and history: currentav = history[-1] elif not currenttimes: currentav = 14 else: currentav = mean(currenttimes) history = history + [currentav] # If it has been less than 20 time steps since last change do nothing if len(history) < 20: return history else: if history[-5] - history[-1] < -1 and history[-1] > 5: if dynamic: if intf.getnodevalue( txl, "InterventionOpen", "cap", uid="name") > 0 and dynamic: intf.updatenode( txl, "Intervention", "cap", intf.getnodevalue( txl, "Intervention", "cap", uid="name") + 1, "name") intf.updatenode( txl, "InterventionOpen", "cap", intf.getnodevalue( txl, "InterventionOpen", "cap", uid="name") - 1, "name") else: intf.updatenode( txl, "Intervention", "cap", intf.getnodevalue(txl, "Intervention", "cap", uid="name") + 1, "name") return [] elif history[-5] - history[-1] > 0 and history[-1] < 5: if intf.getnodevalue(txl, "Intervention", "cap", uid="name") > 0: intf.updatenode( txl, "Intervention", "cap", intf.getnodevalue(txl, "Intervention", "cap", uid="name") - 1, "name") if dynamic: intf.updatenode( txl, "InterventionOpen", "cap", intf.getnodevalue( txl, "InterventionOpen", "cap", uid="name") + 1, "name") return [] else: return history