class VOrientTests(unittest.TestCase): # tests for v structure orientation def setUp(self): self.data = PCAlg.prepare_data('data/asia_1000.data', ' ', True) self.pcalg = PCAlg(self.data, chi) self.fcialg = FCIAlg(self.data, chi) self.directed = nx.DiGraph() self.undirected = nx.Graph() self.directed.add_nodes_from([1, 2, 3, 4]) self.undirected.add_nodes_from(self.directed) self.pag = PAG() self.pag.add_nodes_from(self.undirected) self.sepset = {(x, y): [] for x in [1, 2, 3, 4, 5] for y in [1, 2, 3, 4, 5] if x != y} def test1(self): self.undirected.add_edges_from([(1, 2), (2, 3)]) self.pcalg.orient_V(self.undirected, self.directed, self.sepset) part1 = not self.undirected.has_edge( 1, 2) and not self.undirected.has_edge(3, 2) part2 = self.directed.has_edge(1, 2) and self.directed.has_edge(3, 2) assert (part1 and part2) def test2(self): self.undirected.add_edges_from([(1, 2), (2, 3)]) self.sepset[(1, 3)].append(2) self.sepset[(3, 1)].append(2) self.pcalg.orient_V(self.undirected, self.directed, self.sepset) part1 = not self.undirected.has_edge( 1, 2) and not self.undirected.has_edge(3, 2) part2 = self.directed.has_edge(1, 2) and self.directed.has_edge(3, 2) assert (not (part1 and part2)) def test3(self): self.pag.add_edges_from([(1, 2), (2, 3)]) self.fcialg.orient_V(self.pag, self.sepset) assert (self.pag.has_directed_edge(1, 2) and self.pag.has_directed_edge(3, 2)) def test4(self): self.pag.add_edges_from([(1, 2), (2, 3)]) self.sepset[(1, 3)].append(2) self.sepset[(3, 1)].append(2) self.fcialg.orient_V(self.pag, self.sepset) assert (not self.pag.has_directed_edge(1, 2) and not self.pag.has_directed_edge(3, 2))
def learnSkeleton(self): """ A function to build the skeleton of a causal graph from data Returns ------- PDAG The skeleton of the causal network dict Dicitonary containg separation sets of all pairs of nodes """ skeleton, sepSet = super().learnSkeleton() pag = PAG() pag.add_nodes_from(skeleton) pag.add_edges_from(skeleton.edges) print('finalising skeleton') self.orient_V(pag, sepSet) dseps = self.possible_d_seps( pag) pag.write_to_file('tmp') print(dseps) for x in pag: for y in pag: if y in pag.neighbors(x): indep = False for i in range(1,len(dseps[x])+1): for dsepset in itertools.combinations(dseps[x],i): indep = False dsepset = list(dsepset) if y in dsepset: dsepset.remove(y) if len(dsepset )>= 1: print('testing {} indep {} given {}'.format(x,y,dsepset) ) p, *_ = self.indep_test(self.data, x, y, dsepset) indep = p > self.alpha #stop testing if independence is found and remove edge if indep: print('removing edge {},{}'.format(x,y)) pag.remove_edge(x,y) sepSet[(x,y)] = dsepset sepSet[(y,x)] = dsepset break if indep: break if indep: break return pag, sepSet
class DiscPathTest(unittest.TestCase): # tests for finding discriminating paths on a graph def setUp(self): self.pag = PAG() self.pag.add_nodes_from([1, 2, 3, 4]) def test1(self): self.pag.add_edges_from([[1, 2], [2, 3], [3, 4], [2, 4]]) self.pag.fully_direct_edge(1, 2) self.pag.fully_direct_edge(3, 2) self.pag.fully_direct_edge(2, 4) self.pag.fully_direct_edge(3, 4) assert (self.pag.hasDiscPath(1, 4, 3)) def test2(self): self.pag.add_edges_from([[1, 2], [2, 3], [2, 4]]) self.pag.fully_direct_edge(1, 2) self.pag.fully_direct_edge(3, 2) self.pag.fully_direct_edge(2, 4) assert (not self.pag.hasDiscPath(1, 4, 3)) def test3(self): self.pag.add_edges_from([[1, 2], [2, 3], [3, 4], [2, 4]]) self.pag.fully_direct_edge(1, 2) self.pag.fully_direct_edge(2, 3) self.pag.fully_direct_edge(2, 4) self.pag.fully_direct_edge(3, 4) assert (not self.pag.hasDiscPath(1, 4, 3)) def test4(self): self.pag.add_edges_from([[1, 2], [2, 3], [3, 4], [2, 4]]) self.pag.fully_direct_edge(1, 2) self.pag.fully_direct_edge(3, 2) self.pag.fully_direct_edge(3, 4) assert (not self.pag.hasDiscPath(1, 4, 3)) def test5(self): self.pag.add_edges_from([[1, 2], [2, 3], [3, 4], [2, 4]]) self.pag.fully_direct_edge(1, 2) self.pag.fully_direct_edge(3, 2) self.pag.fully_direct_edge(3, 4) self.pag.fully_direct_edge(1, 4) assert (not self.pag.hasDiscPath(1, 4, 3))
def orientEdges(self, skeleton, sepSet): """ A function to orient the edges of a skeleton using the orientation rules of the FCI algorithm Parameters ---------- skeleton: networkx Graph(), skeleton estimation sepSet: dict Dicitonary containg separation sets of all pairs of nodes Returns ------- PAG containing estimated causal relationships in data """ pag = PAG() pag.add_nodes_from(skeleton) pag.add_edges_from(skeleton.edges) self.orient_V(pag, sepSet) old_pag = nx.DiGraph() while old_pag.edges != pag.edges: old_pag = copy.deepcopy(pag) for i in pag: for j in pag: for k in pag: if k not in [i,j] and j != i: self.rule1(pag,i,j,k) self.rule2(pag,i,j,k) for l in pag: if l not in [i,j,k]: self.rule3(pag,i,j,k,l) self.rule4(pag,i,j,k,l, sepSet) self.rule5(pag,i,j,k,l) self.rule67(pag,i,j,k) self.rule8(pag,i,j,k) self.rule9(pag,i,j,k,l) self.rule10(pag,i,j,k,l) return pag
class RulesTests(unittest.TestCase): # tests for fci algorithm orientation rules def setUp(self): self.pag = PAG() self.pag.add_nodes_from([1, 2, 3, 4, 5]) # Rule 1 Tests def test11(self): self.pag.add_edge(1, 2) self.pag.add_edge(2, 3) self.pag.direct_edge(1, 2) FCIAlg.rule1(self.pag, 1, 2, 3) assert (self.pag.has_fully_directed_edge(2, 3)) def test12(self): self.pag.add_edge(1, 2) self.pag.add_edge(2, 3) FCIAlg.rule1(self.pag, 1, 2, 3) assert (not self.pag.has_fully_directed_edge(2, 3)) # Rule 2 Tests def test21(self): self.pag.add_edge(1, 2) self.pag.add_edge(2, 3) self.pag.add_edge(1, 3) self.pag.direct_edge(1, 2) self.pag.fully_direct_edge(2, 3) FCIAlg.rule2(self.pag, 1, 2, 3) assert (self.pag.has_directed_edge(1, 3)) def test22(self): self.pag.add_edge(1, 2) self.pag.add_edge(2, 3) self.pag.add_edge(1, 3) self.pag.direct_edge(2, 3) self.pag.fully_direct_edge(1, 2) FCIAlg.rule2(self.pag, 1, 2, 3) assert (self.pag.has_directed_edge(1, 3)) def test23(self): self.pag.add_edge(1, 2) self.pag.add_edge(2, 3) self.pag.add_edge(1, 3) self.pag.fully_direct_edge(3, 2) self.pag.fully_direct_edge(1, 2) FCIAlg.rule2(self.pag, 1, 2, 3) assert (not self.pag.has_directed_edge(1, 3)) # Rule 3 Tests def test31(self): self.pag.add_edge(1, 2) self.pag.add_edge(2, 3) self.pag.add_edge(1, 4) self.pag.add_edge(4, 3) self.pag.add_edge(4, 2) self.pag.direct_edge(1, 2) self.pag.direct_edge(3, 2) FCIAlg.rule3(self.pag, 1, 2, 3, 4) assert (self.pag.has_directed_edge(4, 2)) def test32(self): self.pag.add_edge(1, 2) self.pag.add_edge(2, 3) self.pag.add_edge(1, 4) self.pag.add_edge(4, 3) self.pag.add_edge(4, 2) self.pag.direct_edge(1, 2) self.pag.direct_edge(3, 2) self.pag.direct_edge(1, 4) FCIAlg.rule3(self.pag, 1, 2, 3, 4) assert (not self.pag.has_directed_edge(4, 2)) # Rule 4 Tests def test41(self): self.pag.add_edge(1, 2) self.pag.add_edge(2, 3) self.pag.add_edge(3, 4) self.pag.add_edge(4, 5) self.pag.add_edge(2, 5) self.pag.add_edge(3, 5) self.pag.direct_edge(1, 2) self.pag.direct_edge(2, 3) self.pag.direct_edge(2, 5) self.pag.direct_edge(3, 2) self.pag.direct_edge(3, 4) self.pag.direct_edge(3, 5) self.pag.direct_edge(4, 3) self.pag.direct_edge(3, 2) sepset = {(1, 5): [4], (5, 1): [4]} FCIAlg.rule4(self.pag, 3, 4, 5, 1, sepset) assert (self.pag.has_directed_edge(4, 5)) def test42(self): self.pag.add_edge(1, 2) self.pag.add_edge(2, 3) self.pag.add_edge(3, 4) self.pag.add_edge(4, 5) self.pag.add_edge(2, 5) self.pag.add_edge(3, 5) self.pag.direct_edge(1, 2) self.pag.direct_edge(2, 3) self.pag.direct_edge(2, 5) self.pag.direct_edge(3, 2) self.pag.direct_edge(3, 4) self.pag.direct_edge(3, 5) self.pag.direct_edge(4, 3) self.pag.direct_edge(3, 2) sepset = {(1, 5): [2], (5, 1): [2]} FCIAlg.rule4(self.pag, 3, 4, 5, 1, sepset) assert (self.pag.has_directed_edge(4, 5) and self.pag.has_directed_edge(5, 4) and self.pag.has_directed_edge(4, 3) and self.pag.has_directed_edge(3, 4)) # Rule 5 Tests def test51(self): self.pag.add_edge(1, 2) self.pag.add_edge(1, 3) self.pag.add_edge(3, 4) self.pag.add_edge(2, 4) FCIAlg.rule5(self.pag, 1, 2, 3, 4) assert (self.pag.has_fully_undirected_edge(1, 2) and self.pag.has_fully_undirected_edge(1, 3) and self.pag.has_fully_undirected_edge(3, 4) and self.pag.has_fully_undirected_edge(4, 2)) def test52(self): self.pag.add_edge(1, 2) self.pag.add_edge(1, 3) self.pag.add_edge(2, 4) FCIAlg.rule5(self.pag, 1, 2, 3, 4) assert (not (self.pag.has_fully_undirected_edge(1, 2) and self.pag.has_fully_undirected_edge(1, 3) and self.pag.has_fully_undirected_edge(3, 4) and self.pag.has_fully_undirected_edge(4, 2))) def test53(self): self.pag.add_edge(1, 2) self.pag.add_edge(1, 3) self.pag.add_edge(3, 4) FCIAlg.rule5(self.pag, 1, 2, 3, 4) assert (not (self.pag.has_fully_undirected_edge(1, 2) and self.pag.has_fully_undirected_edge(1, 3) and self.pag.has_fully_undirected_edge(3, 4) and self.pag.has_fully_undirected_edge(4, 2))) def test54(self): self.pag.add_edge(1, 5) self.pag.add_edge(1, 2) self.pag.add_edge(1, 3) self.pag.add_edge(3, 4) self.pag.add_edge(2, 4) FCIAlg.rule5(self.pag, 1, 2, 3, 4) assert (self.pag.has_fully_undirected_edge(1, 2) and self.pag.has_fully_undirected_edge(1, 3) and self.pag.has_fully_undirected_edge(3, 4) and self.pag.has_fully_undirected_edge(4, 2)) # Rule 6 Tests def test61(self): self.pag.add_edge(1, 2) self.pag.add_edge(2, 3) self.pag.undirect_edge(1, 2) FCIAlg.rule67(self.pag, 1, 2, 3) assert (self.pag.get_edge_data(2, 3)[2] == '-') def test62(self): self.pag.add_edge(1, 2) self.pag.add_edge(2, 3) FCIAlg.rule67(self.pag, 1, 2, 3) assert (not (self.pag.get_edge_data(2, 3)[2] == '-')) def test63(self): self.pag.add_edge(2, 3) self.pag.undirect_edge(1, 2) FCIAlg.rule67(self.pag, 1, 2, 3) assert (not (self.pag.get_edge_data(2, 3)[2] == '-')) # Rule 7 Tests def test71(self): self.pag.add_edge(1, 2) self.pag.add_edge(2, 3) self.pag.setTag([1, 2], 1, '-') FCIAlg.rule67(self.pag, 1, 2, 3) assert (self.pag.get_edge_data(2, 3)[2] == '-') def test72(self): self.pag.add_edge(1, 2) self.pag.add_edge(2, 3) FCIAlg.rule67(self.pag, 1, 2, 3) assert (not (self.pag.get_edge_data(2, 3)[2] == '-')) # Rule 8 Tests def test81(self): self.pag.add_edge(1, 2) self.pag.add_edge(2, 3) self.pag.add_edge(1, 3) self.pag.direct_edge(1, 3) self.pag.fully_direct_edge(1, 2) self.pag.fully_direct_edge(2, 3) FCIAlg.rule8(self.pag, 1, 2, 3) assert (self.pag.has_fully_directed_edge(1, 3)) def test82(self): self.pag.add_edge(1, 2) self.pag.add_edge(2, 3) self.pag.add_edge(1, 3) self.pag.direct_edge(1, 3) self.pag.setTag([1, 2], 1, '-') self.pag.fully_direct_edge(2, 3) FCIAlg.rule8(self.pag, 1, 2, 3) assert (self.pag.has_fully_directed_edge(1, 3)) # Rule 9 Tests def test91(self): self.pag.add_edge(1, 3) self.pag.add_edge(1, 2) self.pag.add_edge(2, 4) self.pag.add_edge(4, 3) self.pag.direct_edge(1, 3) self.pag.direct_edge(1, 2) FCIAlg.rule9(self.pag, 1, 2, 3, 4) assert (self.pag.has_fully_directed_edge(1, 3)) def test92(self): self.pag.add_edge(1, 3) self.pag.add_edge(1, 2) self.pag.add_edge(2, 4) self.pag.add_edge(4, 3) self.pag.direct_edge(1, 3) self.pag.undirect_edge(1, 2) FCIAlg.rule9(self.pag, 1, 2, 3, 4) assert (not self.pag.has_fully_directed_edge(1, 3)) def test93(self): self.pag.add_edge(1, 3) self.pag.add_edge(1, 2) self.pag.add_edge(2, 4) self.pag.add_edge(4, 3) self.pag.direct_edge(1, 3) self.pag.direct_edge(2, 1) FCIAlg.rule9(self.pag, 1, 2, 3, 4) assert (not self.pag.has_fully_directed_edge(1, 3)) # Rule 10 Tests def test101(self): self.pag.add_edge(1, 3) self.pag.add_edge(1, 2) self.pag.add_edge(2, 3) self.pag.add_edge(4, 3) self.pag.add_edge(1, 5) self.pag.add_edge(5, 4) self.pag.direct_edge(1, 3) self.pag.fully_direct_edge(2, 3) self.pag.direct_edge(1, 5) self.pag.fully_direct_edge(4, 3) FCIAlg.rule10(self.pag, 1, 2, 3, 4) assert (self.pag.has_fully_directed_edge(1, 3)) def test102(self): self.pag.add_edge(1, 3) self.pag.add_edge(1, 2) self.pag.add_edge(2, 3) self.pag.add_edge(4, 3) self.pag.add_edge(1, 5) self.pag.add_edge(5, 4) self.pag.fully_direct_edge(2, 3) self.pag.direct_edge(1, 5) self.pag.fully_direct_edge(4, 3) FCIAlg.rule10(self.pag, 1, 2, 3, 4) assert (not (self.pag.has_fully_directed_edge(1, 3))) def test103(self): self.pag.add_edge(1, 3) self.pag.add_edge(1, 2) self.pag.add_edge(2, 3) self.pag.add_edge(4, 3) self.pag.add_edge(1, 5) self.pag.direct_edge(1, 3) self.pag.direct_edge(1, 5) self.pag.fully_direct_edge(4, 3) FCIAlg.rule10(self.pag, 1, 2, 3, 4) assert (not (self.pag.has_fully_directed_edge(1, 3))) def test104(self): self.pag.add_edge(1, 3) self.pag.add_edge(1, 2) self.pag.add_edge(2, 3) self.pag.add_edge(4, 3) self.pag.add_edge(1, 5) self.pag.direct_edge(1, 3) self.pag.fully_direct_edge(2, 3) self.pag.direct_edge(1, 5) self.pag.fully_direct_edge(4, 3) FCIAlg.rule10(self.pag, 1, 2, 3, 4) assert (not (self.pag.has_fully_directed_edge(1, 3)))
class D_SepTests(unittest.TestCase): #Tests for possible d sep set calculation def setUp(self): self.pag = PAG() self.pag.add_nodes_from([1, 2, 3, 4, 5, 6]) def test1(self): self.pag.add_edge(1, 2) self.pag.add_edge(3, 2) dseps = FCIAlg.possible_d_seps(self.pag) assert (dseps == {1: [2], 2: [1, 3], 3: [2], 4: [], 5: [], 6: []}) def test2(self): self.pag.add_edge(1, 2) self.pag.add_edge(2, 3) self.pag.fully_direct_edge(1, 2) self.pag.fully_direct_edge(3, 2) dseps = FCIAlg.possible_d_seps(self.pag) assert (dseps == { 1: [2, 3], 2: [1, 3], 3: [1, 2], 4: [], 5: [], 6: [] }) def test3(self): self.pag.add_edge(1, 2) self.pag.add_edge(2, 3) self.pag.fully_direct_edge(1, 2) self.pag.fully_direct_edge(3, 2) self.pag.add_edge(2, 4) self.pag.add_edge(3, 4) dseps = FCIAlg.possible_d_seps(self.pag) assert (dseps == { 1: [2, 3, 4], 2: [1, 3, 4], 3: [ 1, 2, 4, ], 4: [1, 2, 3], 5: [], 6: [] }) def test4(self): self.pag.add_edge(1, 2) self.pag.add_edge(3, 2) self.pag.add_edge(3, 1) dseps = FCIAlg.possible_d_seps(self.pag) assert (dseps == { 1: [2, 3], 2: [1, 3], 3: [1, 2], 4: [], 5: [], 6: [] })