Exemple #1
0
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
Exemple #2
0
 def test_no_path(macid_taxi_comp: MACID) -> None:
     with pytest.raises(ValueError):
         find_active_path(macid_taxi_comp, "D1", "U1", {"D2", "U1"})
Exemple #3
0
 def test_invalid_target_end(macid_taxi_comp: MACID) -> None:
     with pytest.raises(KeyError):
         find_active_path(macid_taxi_comp, "D1", "U3", {"D2"})
Exemple #4
0
 def test_find_active_path(macid_taxi_comp: MACID) -> None:
     assert find_active_path(macid_taxi_comp, "D1", "U1",
                             {"D2"}) == ["D1", "U1"]