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.
- 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.
- 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:
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}],
- 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()