def test_get_motif(macid_basic_subgames: MACID) -> None: assert get_motif(macid_basic_subgames, ["D3", "D2", "U2", "D11", "D12", "U3"], 0) == "backward" assert get_motif(macid_basic_subgames, ["D3", "D2", "U2", "D11", "D12", "U3"], 1) == "fork" assert get_motif(macid_basic_subgames, ["D3", "D2", "U2", "D11", "D12", "U3"], 2) == "collider" assert get_motif(macid_basic_subgames, ["D3", "D2", "U2", "D11", "D12", "U3"], 4) == "forward" assert get_motif(macid_basic_subgames, ["D3", "D2", "U2", "D11", "D12", "U3"], 5) == "endpoint"
def _add_sufficient_recall(mb: MACIDBase, d1: str, d2: str, utility_node: str) -> None: """Add edges to a (MA)CID until an agent at `d2` has sufficient recall of `d1` to optimise utility_node. d1, d2 and utility node all belong to the same agent. `d2' has sufficient recall of `d1' if d2 does not strategically rely on d1. This means that d1 is not s-reachable from d2. edges are added from non-collider nodes along an active path from the mechanism of `d1' to somue utilty node descended from d2 until recall is sufficient. """ if d2 in mb._get_ancestors_of(d1): raise ValueError("{} is an ancestor of {}".format(d2, d1)) mg = MechanismGraph(mb) while mg.is_active_trail(d1 + "mec", utility_node, observed=mg.get_parents(d2) + [d2]): path = find_active_path(mg, d1 + "mec", utility_node, {d2, *mg.get_parents(d2)}) if path is None: raise RuntimeError( "couldn't find path even though there should be an active trail" ) while True: idx = random.randrange(1, len(path) - 1) if get_motif(mg, path, idx) != "collider": if d2 not in mg._get_ancestors_of( path[idx]): # to prevent cycles mb.add_edge(path[idx], d2) mg.add_edge(path[idx], d2) break
def test_invalid_target(macid_basic_subgames: MACID) -> None: with pytest.raises(KeyError): get_motif(macid_basic_subgames, ["D3", "_", "U2", "D11", "D12", "U3"], 5)
def test_invalid_index(macid_basic_subgames: MACID) -> None: with pytest.raises(IndexError): get_motif(macid_basic_subgames, ["D3", "D2", "U2", "D11", "D12", "U3"], 6)