Example #1
0
 def remove_old(self, time=None):
     """Removes old observations from the interpretation."""
     if time is None:
         time = max(self.past_metrics.time,
                    self.focus.earliest_time) - C.FORGET_TIMESPAN
     #A minimum number of observations is kept
     nmin = min(C.MIN_NOBS, len(self.observations))
     if nmin > 0:
         time = max(self.past_metrics.time,
                    min(time, self.observations[-nmin].lateend - 1))
     dummy = EventObservable()
     dummy.end.set(time, time)
     nhyp = abst = abstime = 0.0
     #Old observations are removed from all lists.
     for lstname in ('observations', 'abstracted', 'unintelligible'):
         lst = getattr(self, lstname)
         idx = lst.bisect_right(dummy)
         if (idx > 0 and self.parent is not None
                 and getattr(self.parent, lstname) is lst):
             lst = lst.copy()
             setattr(self, lstname, lst)
         if lstname == 'observations':
             nhyp = idx
         elif lstname == 'abstracted':
             abstime = sum(o.earlyend - o.latestart + 1 for o in lst[:idx]
                           if ap.get_obs_level(type(o)) == 0)
             abst = idx
         del lst[:idx]
     self.past_metrics = PastMetrics(time, self.past_metrics.abst + abst,
                                     self.past_metrics.abstime + abstime,
                                     self.past_metrics.nhyp + nhyp)
Example #2
0
def plot_constraints_network(interpretation, with_labels=False, fig=None):
    """
    Draws the full temporal constraints network of a specific interpretation.
    """
    #List with all the temporal constraints of the network
    lst = []
    for pat in interpretation.patterns:
        for tnet in pat.temporal_constraints:
            lst.extend(tnet.get_constraints())
    G = nx.DiGraph()
    for const in lst:
        G.add_edge(const.va, const.vb)
    #Color assignment
    observations = interpretation.get_observations()
    colors = []
    labels = {}
    pos = {}
    for node in G.nodes_iter():
        for obs in observations:
            if node is obs.start or node is obs.end:
                colors.append(_get_obs_descriptor(obs)[0])
                x = obs.earlystart if node is obs.start else obs.lateend
                y = ap.get_obs_level(type(obs))
                pos[node] = (x, y)
                labels[node] = str(x) if with_labels else ''
                break
    fig = fig or figure()
    fig.clear()
    nx.draw(G, pos, fig.gca(), node_color=colors, labels=labels)
Example #3
0
def valuation(node, time=None):
    """
    Obtains the heuristic evaluation of an interpretation (a smaller value is
    better). Currently this function checks the proportion of abstracted
    observations over the total number of observations that can be abstracted
    until a specific time point. If the time point is not specified, the time
    point of the interpretation is considered. See the *time_point* function
    for details. The function returns a tuple with three values, the first is
    the relation unexplained/total observations, the second is the amount of
    time being abstracted by at least one observation, and the third is the
    number of hypotheses in the interpretation.
    """
    time = time or node.time_point
    tp, abst, abstime, nhyp = node.past_metrics
    assert time >= tp
    if time > tp:
        abstime += sum(o.earlyend - o.latestart + 1 for o in node.abstracted
                       if ap.get_obs_level(type(o)) == 0)
        abst += len(node.abstracted)
        nhyp += len(node.observations) + node.focus.nhyp
    total = IN.BUF.nobs_before(time) + node.nabd
    if total == 0:
        return (0.0, 0.0, 0.0)
    else:
        return (1.0 - abst / float(total), -abstime, nhyp)
Example #4
0
def _get_obs_descriptor(observation):
    """
    Obtains an observation descriptor (color, level) to represent each of
    the observations
    """
    colors = {}
    colors[o.PWave] = ('#66A2A1', 0.2)
    colors[o.TWave] = ('#E5FF00', 0.2)
    colors[o.RPeak] = ('#0000FF', 1.0)
    colors[o.Normal_Cycle] = ('#009C00', 0.2)
    colors[o.Sinus_Rhythm] = ('#66A2A1', 0.2)
    colors[o.Cardiac_Rhythm] = ('#66A2A1', 0.2)
    colors[o.Extrasystole] = ('#897E00', 0.2)
    colors[o.Tachycardia] = ('#6E0000', 0.2)
    colors[o.Bradycardia] = ('#3F3F3F', 0.2)
    colors[o.RhythmBlock] = ('#672E00', 0.2)
    colors[o.Asystole] = ('#000000', 0.2)
    colors[o.Bigeminy] = ('#FFAA00', 0.2)
    colors[o.Trigeminy] = ('#00897E', 0.2)
    colors[o.Ventricular_Flutter] = ('#844089', 0.2)
    colors[o.Atrial_Fibrillation] = ('#404389', 0.2)
    colors[o.Couplet] = ('#D70751', 0.2)
    colors[o.RhythmStart] = ('#004008', 1.0)
    colors[o.Noise] = ('#808080', 1.0)
    colors[o.RDeflection] = ('#008000', 1.0)
    if isinstance(observation, o.QRS):
        col = '#0000FF' if not observation.paced else '#FF0000'
        colors[o.QRS] = (col, 0.2)
    if isinstance(observation, o.Deflection):
        lev = 0 if not observation.level else min(observation.level.values())
        colors[o.Deflection] = ('#800000', max(0.8 - 0.2 * lev, 0.1))
    try:
        clazz = type(observation)
        return colors[clazz] + (ap.get_obs_level(clazz), )
    except KeyError:
        #Por defecto, devolvemos gris semitransparente
        return ('#000000', 0.2, ap.get_obs_level(type(observation)))
Example #5
0
def constraints_network_graphviz(interpretation, outfile):
    """
    Draws the constraints network of an interpretation using graphviz.

    Parameters
    ----------
    interpretation:
        Interpretation containing the related observations.
    outfile:
        File where the figure will be saved
    """
    lst = []
    pats = sorted(interpretation.patterns,
                  key=lambda p: -ap.get_obs_level(p.automata.Hypothesis))
    for pat in pats:
        for tnet in pat.temporal_constraints:
            lst.extend(tnet.get_constraints())
    G = pgv.AGraph(directed=True)
    G.graph_attr['fontsize'] = '7'
    G.node_attr['style'] = 'filled'
    G.node_attr['fixedsize'] = 'true'
    G.node_attr['width'] = '.85'
    G.node_attr['ordering'] = 'in'
    for const in lst:
        G.add_edge(id(const.va), id(const.vb))
    #Color assignment
    observations = interpretation.get_observations()
    for node in G.nodes_iter():
        for obs in observations:
            if node == str(id(obs.start)) or node == str(id(obs.end)):
                descriptor = _get_obs_descriptor(obs)
                node.attr['group'] = type(obs).__name__
                #We set some transparency to the color
                node.attr['color'] = descriptor[0] + 'C0'
                node.attr['label'] = (str(obs.earlystart) if node == str(
                    id(obs.start)) else str(obs.lateend))
                break
    G.layout(prog='dot', args='-Grankdir=LR')
    G.draw(outfile)
Example #6
0
def advance(interp, focus, pattern):
    """
    Continues the inference by recovering the previous focus of attention, or
    by going to the next unexplained observation. It also resolves all the
    postponed matchings.
    """
    max_ap_level = ap.get_max_level()
    #We can not advance if the focus is an hypothesis of a pattern with
    #insufficient evidence.
    newint = None
    if pattern is not None:
        if not pattern.sufficient_evidence:
            return
        #If there is an observation procedure for the focused hypothesis, the
        #execution takes place now.
        elif pattern.automata.obs_proc is not NULL_PROC:
            patcp = copy.copy(pattern)
            try:
                patcp.finish()
                newint = Interpretation(interp)
                if (focus.end.value != patcp.hypothesis.end.value
                        or focus.start.value != patcp.hypothesis.start.value):
                    newint.verify_consecutivity_violation(patcp.hypothesis)
                    newint.verify_exclusion(patcp.hypothesis)
                focus = patcp.hypothesis
            except InconsistencyError:
                return
    #If the new focus is a delayed matching, we solve it at this point.
    finding = interp.focus.get_delayed_finding(interp.focus.top[0])
    if finding is not None:
        newint = newint or Interpretation(interp)
        try:
            newint.focus.pop()
            pattern = newint.focus.top[1]
            pred, succ = pattern.get_consecutive(finding)
            _finding_match(newint, finding, focus,
                           pattern.hypothesis.start.value,
                           pattern.hypothesis.end.value, pred, succ,
                           pattern.abstracts(finding))
            #The matched hypothesis is included in the observations list
            newint.observations = newint.observations.copy()
            newint.observations.add(focus)
        except InconsistencyError as error:
            newint.discard(str(error))
            return
    else:
        #HINT with the current knowledge base, we restrict the advancement to
        #observations of the first or the last level, not allowing partial
        #interpretations in the abstraction level.
        if (len(interp.focus) == 1
                and 0 < ap.get_obs_level(type(focus)) < max_ap_level):
            return
        #We just move on the focus.
        newint = newint or Interpretation(interp)
        if ap.get_obs_level(type(focus)) == 0:
            newint.unintelligible = newint.unintelligible.copy()
            newint.unintelligible.add(focus)
        #If the focus is a hypothesis, it is added to the observations list
        if pattern is not None:
            newint.observations = newint.observations.copy()
            newint.observations.add(focus)
        newint.focus.pop()
    #If we have reached the top of the stack, we go ahead to the next
    #unexplained observation.
    if not newint.focus:
        try:
            unexp = newint.get_observations(
                start=focus.earlystart + 1,
                filt=lambda ev: ev not in newint.unintelligible and ev not in
                newint.abstracted and ap.is_abducible(type(ev))).next()
            newint.focus.push(unexp, None)
        except StopIteration:
            newint.discard('No unexplained evidence after the current point')
            return
    #Finally, we remove old observations from the interpretation, since they
    #won't be used in following reasoning steps, and they affect the
    #performance of the searching procedure.
    oldtime = max(newint.past_metrics.time,
                  newint.focus.earliest_time) - C.FORGET_TIMESPAN
    newint.remove_old(oldtime)
    yield newint