graphid.core.mixin_dynamic module

This file handles dynamically updating the graph state based on new feedback. This involves handling lots of different cases, which can get confusing (it confuses me and I wrote it). To better understand the dynamic case a good first step would be to understand the nondynamic case defined by apply_nondynamic_update. This function automatically puts the graph into a state that satisfies the dynamic invariants. Any dynamic operation followed by a call to this function should be a no-op, which you can used to check if a dynamic operation is implemented correctly.

Todo

Negative bookkeeping, needs a small re-organization fix. MOVE FROM neg_redun_metagraph TO neg_metagraph

Instead of maintaining a graph that contains PCCS which are neg redundant to each other, the graph should maintain PCCs that have ANY negative edge between them (aka 1 neg redundant). Then that edge should store a flag indicating the strength / redundancy of that connection. A better idea might be to store both neg_redun_metagraph AND neg_metagraph.

TODO: this (all neg-redun functionality can be easilly consolidated into the neg-metagraph-update. note, we have to allow inconsistent pccs to be in the neg redun graph, we just filter them out afterwords)

class graphid.core.mixin_dynamic.DynamicUpdate[source]

Bases: object

# 12 total possible states

# details of these states. POSITIVE, WITHIN, CONSISTENT

  • pos-within never changes PCC status

  • never introduces inconsistency

  • might add pos-redun

POSITIVE, WITHIN, INCONSISTENT
  • pos-within never changes PCC status

  • might fix inconsistent edge

POSITIVE, BETWEEN, BOTH_CONSISTENT
  • pos-between edge always does merge

POSITIVE, BETWEEN, ANY_INCONSISTENT
  • pos-between edge always does merge

  • pos-between never fixes inconsistency

NEGATIVE, WITHIN, CONSISTENT
  • might split PCC, results will be consistent

  • might causes an inconsistency

NEGATIVE, WITHIN, INCONSISTENT
  • might split PCC, results may be inconsistent

NEGATIVE, BETWEEN, BOTH_CONSISTENT
  • might add neg-redun

NEGATIVE, BETWEEN, ANY_INCONSISTENT
  • might add to incon-neg-external

  • neg-redun not tracked for incon.

UNINFERABLE, WITHIN, CONSISTENT
  • might remove pos-redun

  • might split PCC, results will be consistent

UNINFERABLE, WITHIN, INCONSISTENT
  • might split PCC, results may be inconsistent

UNINFERABLE, BETWEEN, BOTH_CONSISTENT
  • might remove neg-redun

UNINFERABLE, BETWEEN, ANY_INCONSISTENT
  • might remove incon-neg-external

ensure_edges_from(edges)[source]

Finds edges that don’t exist and adds them as unreviwed edges. Returns new edges that were added.

_add_review_edges_from(edges, decision='UNREV')[source]
_add_review_edge(edge, decision)[source]

Adds an edge to the appropriate data structure

_get_current_decision(edge)[source]

Find if any data structure has the edge

on_between(edge, decision, prev_decision, nid1, nid2, merge_nid=None)[source]

Callback when a review is made between two PCCs

on_within(edge, decision, prev_decision, nid, split_nids=None)[source]

Callback when a review is made inside a PCC

Parameters:
  • edge – the edge reviewed

  • decision – the new decision

  • prev_decision – the old decision

  • nid – the old nid the edge is inside of

  • split_nids – the tuple of new nids created if this decision splits a PCC

_update_neg_metagraph(decision, prev_decision, nid1, nid2, merge_nid=None, split_nids=None)[source]

Update the negative metagraph based a new review

Todo

we can likely consolidate lots of neg_redun_metagraph functionality into this function. Just check when the weights are above or under the threshold and update accordingly.

_positive_decision(edge)[source]

Logic for a dynamic positive decision. A positive decision is evidence that two annots should be in the same PCC

Note, this could be an incomparable edge, but with a meta_decision of same.

_negative_decision(edge)[source]

Logic for a dynamic negative decision. A negative decision is evidence that two annots should not be in the same PCC

_uninferable_decision(edge, decision)[source]

Logic for a dynamic uninferable negative decision An uninferrable decision does not provide any evidence about PCC status and is either:

incomparable, unreviewed, or unknown

class graphid.core.mixin_dynamic.Recovery[source]

Bases: object

recovery funcs

is_recovering(edge=None)[source]

Checks to see if the graph is inconsinsistent.

Parameters:

edge (None) – If None, then returns True if the graph contains any inconsistency. Otherwise, returns True if the edge is related to an inconsistent component via a positive or negative connection.

Returns:

flag

Return type:

bool

CommandLine

python -m graphid.core.mixin_dynamic Recovery.is_recovering

Doctest

>>> from graphid import demo
>>> infr = demo.demodata_infr(num_pccs=4, size=4, ignore_pair=True)
>>> infr.ensure_cliques(meta_decision=SAME)
>>> a, b, c, d = map(list, infr.positive_components())
>>> assert infr.is_recovering() is False
>>> infr.add_feedback((a[0], a[1]), NEGTV)
>>> assert infr.is_recovering() is True
>>> assert infr.is_recovering((a[2], a[3])) is True
>>> assert infr.is_recovering((a[3], b[0])) is True
>>> assert infr.is_recovering((b[0], b[1])) is False
>>> infr.add_feedback((a[3], b[2]), NEGTV)
>>> assert infr.is_recovering((b[0], b[1])) is True
>>> assert infr.is_recovering((c[0], d[0])) is False
>>> infr.add_feedback((b[2], c[0]), NEGTV)
>>> assert infr.is_recovering((c[0], d[0])) is False
>>> result = ub.urepr({
>>>     'iccs': list(infr.inconsistent_components()),
>>>     'pccs': sorted([cc for cc in infr.positive_components()], key=min),
>>> }, nobr=1, sorted=True, si=True, itemsep='', sep='', nl=1)
>>> print(result)
iccs: [{1,2,3,4}],
pccs: [{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}],
_purge_error_edges(nid)[source]

Removes all error edges associated with a PCC so they can be recomputed or resolved.

_set_error_edges(nid, new_error_edges)[source]
maybe_error_edges()[source]
_new_inconsistency(nid)[source]
_check_inconsistency(nid, cc=None)[source]

Check if a PCC contains an error

_mincut_edge_weights(edges_)[source]
hypothesis_errors(pos_subgraph, neg_edges)[source]
class graphid.core.mixin_dynamic.NonDynamicUpdate[source]

Bases: object

apply_nondynamic_update(graph=None)[source]

Recomputes all dynamic bookkeeping for a graph in any state. This ensures that subsequent dyanmic inference can be applied.

Example

>>> from graphid import demo
>>> num_pccs = 250
>>> kwargs = dict(num_pccs=100, p_incon=.3)
>>> infr = demo.demodata_infr(infer=False, **kwargs)
>>> graph = None
>>> infr.apply_nondynamic_update()
>>> infr.assert_neg_metagraph()
collapsed_meta_edges(graph=None)[source]

Collapse the grah such that each PCC is a node. Get a list of edges within/between each PCC.

categorize_edges(graph=None, ne_to_edges=None)[source]

Non-dynamically computes the status of each edge in the graph. This is can be used to verify the dynamic computations and update when the dynamic state is lost.

Example

>>> from graphid import demo
>>> num_pccs = 250 if ub.argflag('--profile') else 100
>>> kwargs = dict(num_pccs=100, p_incon=.3)
>>> infr = demo.demodata_infr(infer=False, **kwargs)
>>> graph = None
>>> cat = infr.categorize_edges()