nodes) {
* @return a boolean
*/
public boolean isDescendentOf(Node node1, Node node2) {
- return node1 == node2 || existsDirectedPathFromTo(node2, node1);
+ return node1 == node2 || existsDirectedPath(node2, node1);
}
/**
@@ -2106,6 +2130,8 @@ public boolean definiteNonDescendent(Node node1, Node node2) {
* every collider on U is an ancestor of some element in Z and every non-collider on U is not in Z. Two elements are
* d-separated just in case they are not d-connected. A collider is a node which two edges hold in common for which
* the endpoints leading into the node are both arrow endpoints.
+ *
+ * Precondition: This graph is a DAG. Please don't violate this constraint; weird things can happen!
*
* @param node1 the first node.
* @param node2 the second node.
@@ -2118,20 +2144,25 @@ public boolean isMSeparatedFrom(Node node1, Node node2, Set z) {
}
/**
- * isMSeparatedFrom.
+ * Checks if two nodes are M-separated.
*
- * @param node1 a {@link edu.cmu.tetrad.graph.Node} object
- * @param node2 a {@link edu.cmu.tetrad.graph.Node} object
- * @param z a {@link java.util.Set} object
- * @param ancestors a {@link java.util.Map} object
- * @return a boolean
+ * @param node1 The first node.
+ * @param node2 The second node.
+ * @param z The set of nodes to be excluded from the path.
+ * @param ancestors A map containing the ancestors of each node.
+ * @return {@code true} if the two nodes are M-separated, {@code false} otherwise.
*/
public boolean isMSeparatedFrom(Node node1, Node node2, Set z, Map> ancestors) {
return !isMConnectedTo(node1, node2, z, ancestors);
}
/**
- * @return true iff there is a semi-directed path from node1 to node2
+ * Checks if a semi-directed path exists between the given node and any of the nodes in the provided set.
+ *
+ * @param node1 The starting node for the path.
+ * @param nodes2 The set of nodes to check for a path.
+ * @param path The current path (used for cycle detection).
+ * @return {@code true} if a semi-directed path exists, {@code false} otherwise.
*/
private boolean existsSemiDirectedPathVisit(Node node1, Set nodes2, LinkedList path) {
path.addLast(node1);
@@ -2161,13 +2192,13 @@ private boolean existsSemiDirectedPathVisit(Node node1, Set nodes2, Linked
}
/**
- * isDirectedFromTo.
+ * Checks if there is a directed edge from node1 to node2 in the graph.
*
- * @param node1 a {@link edu.cmu.tetrad.graph.Node} object
- * @param node2 a {@link edu.cmu.tetrad.graph.Node} object
- * @return a boolean
+ * @param node1 the source node
+ * @param node2 the destination node
+ * @return true if there is a directed edge from node1 to node2, false otherwise
*/
- public boolean isDirectedFromTo(Node node1, Node node2) {
+ public boolean isDirected(Node node1, Node node2) {
List edges = graph.getEdges(node1, node2);
if (edges.size() != 1) {
return false;
@@ -2177,13 +2208,13 @@ public boolean isDirectedFromTo(Node node1, Node node2) {
}
/**
- * isUndirectedFromTo.
+ * Checks if the edge between two nodes in the graph is undirected.
*
- * @param node1 a {@link edu.cmu.tetrad.graph.Node} object
- * @param node2 a {@link edu.cmu.tetrad.graph.Node} object
- * @return a boolean
+ * @param node1 the first node
+ * @param node2 the second node
+ * @return true if the edge is undirected, false otherwise
*/
- public boolean isUndirectedFromTo(Node node1, Node node2) {
+ public boolean isUndirected(Node node1, Node node2) {
Edge edge = graph.getEdge(node1, node2);
return edge != null && edge.getEndpoint1() == Endpoint.TAIL && edge.getEndpoint2() == Endpoint.TAIL;
}
@@ -2212,25 +2243,26 @@ public Set> adjustmentSets1(Node x, Node y) {
}
/**
- * Returns the adjustment sets, calculated based on anteriority minus descendants subsets, between two nodes in a graph.
+ * Returns a set of sets of nodes representing adjustment sets between nodes {@code x} and {@code y} in the graph
+ * that are subsets of the anteriority of x and y with the n smallest sizes.
*
* @param x the starting node
* @param y the ending node
- * @return a set of sets of nodes representing the adjustment sets
+ * @param n the number of smallest sizes for adjustment sets to return
+ * @return a set of sets of nodes representing adjustment sets
*/
- public Set> adjustmentSets2(Node x, Node y, int maxSize) {
- return GraphUtils.adjustmentSets2(graph, x, y, maxSize);
+ public Set> adjustmentSets2(Node x, Node y, int n) {
+ return GraphUtils.adjustmentSets2(graph, x, y, n);
}
/**
- * Returns the set of nodes preceding node y in the graph, based on the given node x.
+ * Returns the set of nodes preceding node y in the graph, based on the given node X.
*
- * @param x the starting node
- * @param y the target node
- * @return a set of nodes preceding node y
+ * @param X a list of nodes
+ * @return a set of nodes preceding all the nodes in X
*/
- public Set anteriority(Node x, Node y) {
- return GraphUtils.anteriority(graph, x, y);
+ public Set anteriority(Node... X) {
+ return GraphUtils.anteriority(graph, X);
}
/**
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/IcaLingam.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/IcaLingam.java
index a170d4b26f..c7ca3c4fde 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/IcaLingam.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/IcaLingam.java
@@ -188,7 +188,7 @@ public boolean isAcyclic(Matrix scaledBHat) {
private boolean existsDirectedCycle() {
for (Node node : new HashSet<>(dummyCyclicNodes)) {
- if (dummyGraph.paths().existsDirectedPathFromTo(node, node)) {
+ if (dummyGraph.paths().existsDirectedPath(node, node)) {
return true;
} else {
dummyCyclicNodes.remove(node);
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/GraphSearchUtils.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/GraphSearchUtils.java
index 9f387b236e..2270e14ca1 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/GraphSearchUtils.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/GraphSearchUtils.java
@@ -491,7 +491,7 @@ public static LegalMagRet isLegalMag(Graph mag) {
}
for (Node n : mag.getNodes()) {
- if (mag.paths().existsDirectedPathFromTo(n, n))
+ if (mag.paths().existsDirectedPath(n, n))
return new LegalMagRet(false,
"Acyclicity violated: There is a directed cyclic path from from " + n + " to itself");
}
@@ -501,14 +501,14 @@ public static LegalMagRet isLegalMag(Graph mag) {
Node y = e.getNode2();
if (Edges.isBidirectedEdge(e)) {
- if (mag.paths().existsDirectedPathFromTo(x, y)) {
- List path = mag.paths().directedPathsFromTo(x, y, 100).get(0);
+ if (mag.paths().existsDirectedPath(x, y)) {
+ List path = mag.paths().directedPaths(x, y, 100).get(0);
return new LegalMagRet(false,
"Bidirected edge semantics is violated: there is a directed path for " + e + " from " + x + " to " + y
+ ". This is \"almost cyclic\"; for <-> edges there should not be a path from either endpoint to the other. "
+ "An example path is " + GraphUtils.pathString(mag, path));
- } else if (mag.paths().existsDirectedPathFromTo(y, x)) {
- List path = mag.paths().directedPathsFromTo(y, x, 100).get(0);
+ } else if (mag.paths().existsDirectedPath(y, x)) {
+ List path = mag.paths().directedPaths(y, x, 100).get(0);
return new LegalMagRet(false,
"Bidirected edge semantics is violated: There is an a directed path for " + e + " from " + y + " to " + x +
". This is \"almost cyclic\"; for <-> edges there should not be a path from either endpoint to the other. "
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/MbUtils.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/MbUtils.java
index 99284331d2..94acea2d06 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/MbUtils.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/MbUtils.java
@@ -73,7 +73,7 @@ public static void trimToMbNodes(Graph graph, Node target,
if (graph.isDefCollider(target, v, w)) {
parentsOfChildren.add(w);
} else if (graph.getNodesInTo(v, Endpoint.ARROW).contains(target)
- && graph.paths().isUndirectedFromTo(v, w)) {
+ && graph.paths().isUndirected(v, w)) {
parentsOfChildren.add(w);
}
}
@@ -92,9 +92,9 @@ public static void trimToMbNodes(Graph graph, Node target,
List pc = new LinkedList<>();
for (Node node : graph.getAdjacentNodes(target)) {
- if (graph.paths().isDirectedFromTo(target, node) ||
- graph.paths().isDirectedFromTo(node, target) ||
- graph.paths().isUndirectedFromTo(node, target)) {
+ if (graph.paths().isDirected(target, node) ||
+ graph.paths().isDirected(node, target) ||
+ graph.paths().isUndirected(node, target)) {
pc.add(node);
}
}
@@ -106,7 +106,7 @@ public static void trimToMbNodes(Graph graph, Node target,
continue;
}
- if (graph.paths().isDirectedFromTo(target, v)) {
+ if (graph.paths().isDirected(target, v)) {
children.add(v);
}
}
@@ -125,8 +125,8 @@ public static void trimToMbNodes(Graph graph, Node target,
continue;
}
- if (graph.paths().isDirectedFromTo(target, v) &&
- graph.paths().isDirectedFromTo(w, v)) {
+ if (graph.paths().isDirected(target, v) &&
+ graph.paths().isDirected(w, v)) {
parentsOfChildren.add(w);
}
}
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/MeekRules.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/MeekRules.java
index ef73c81660..cec282c1aa 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/MeekRules.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/MeekRules.java
@@ -176,16 +176,8 @@ public void setRevertToUnshieldedColliders(boolean revertToUnshieldedColliders)
* @param visited The set of nodes visited.
*/
private void revertToUnshieldedColliders(List nodes, Graph graph, Set visited) {
- boolean reverted = true;
-
- while (reverted) {
- reverted = false;
-
- for (Node node : nodes) {
- if (revertToUnshieldedColliders(node, graph, visited)) {
- reverted = true;
- }
- }
+ for (Node node : nodes) {
+ revertToUnshieldedColliders(node, graph, visited);
}
}
@@ -213,29 +205,32 @@ private boolean meekR2(Node a, Node c, Graph graph, Set visited) {
adjacentNodes.remove(a);
Set common = getCommonAdjacents(a, c, graph);
+ boolean oriented = false;
for (Node b : common) {
- if (graph.paths().isDirectedFromTo(a, b) && graph.paths().isDirectedFromTo(b, c)) {
+ if (graph.paths().isDirected(a, b) && graph.paths().isDirected(b, c)) {
if (r2Helper(a, b, c, graph, visited)) {
- return true;
+ oriented = true;
}
}
- if (graph.paths().isDirectedFromTo(c, b) && graph.paths().isDirectedFromTo(b, a)) {
+ if (graph.paths().isDirected(c, b) && graph.paths().isDirected(b, a)) {
if (r2Helper(c, b, a, graph, visited)) {
- return true;
+ oriented = true;
}
}
}
- return false;
+ return oriented;
}
private boolean r2Helper(Node a, Node b, Node c, Graph graph, Set visited) {
- boolean directed = direct(a, c, graph, visited);
- log(LogUtilsSearch.edgeOrientedMsg(
- "Meek R2 triangle (" + a + "-->" + b + "-->" + c + ", " + a + "---" + c + ")", graph.getEdge(a, c)));
- return directed;
+ if (direct(a, c, graph, visited)) {
+ log(LogUtilsSearch.edgeOrientedMsg(
+ "Meek R2 triangle (" + a + "-->" + b + "-->" + c + ", " + a + "--" + c + ")", graph.getEdge(a, c)));
+ return true;
+ }
+ return false;
}
/**
@@ -248,6 +243,8 @@ private boolean meekR3(Node d, Node a, Graph graph, Set visited) {
return false;
}
+ boolean oriented = false;
+
for (int i = 0; i < adjacentNodes.size(); i++) {
for (int j = i + 1; j < adjacentNodes.size(); j++) {
Node b = adjacentNodes.get(i);
@@ -255,31 +252,31 @@ private boolean meekR3(Node d, Node a, Graph graph, Set visited) {
if (!graph.isAdjacentTo(b, c)) {
if (r3Helper(a, d, b, c, graph, visited)) {
- return true;
+ oriented = true;
}
}
}
}
- return false;
+ return oriented;
}
private boolean r3Helper(Node a, Node d, Node b, Node c, Graph graph, Set visited) {
- boolean oriented = false;
-
- boolean b4 = graph.paths().isUndirectedFromTo(d, a);
- boolean b5 = graph.paths().isUndirectedFromTo(d, b);
- boolean b6 = graph.paths().isUndirectedFromTo(d, c);
- boolean b7 = graph.paths().isDirectedFromTo(b, a);
- boolean b8 = graph.paths().isDirectedFromTo(c, a);
+ boolean b4 = graph.paths().isUndirected(d, a);
+ boolean b5 = graph.paths().isUndirected(d, b);
+ boolean b6 = graph.paths().isUndirected(d, c);
+ boolean b7 = graph.paths().isDirected(b, a);
+ boolean b8 = graph.paths().isDirected(c, a);
if (b4 && b5 && b6 && b7 && b8) {
- oriented = direct(d, a, graph, visited);
- log(LogUtilsSearch.edgeOrientedMsg("Meek R3 " + d + "--" + a + ", " + b + ", "
- + c, graph.getEdge(d, a)));
+ if (direct(d, a, graph, visited)) {
+ log(LogUtilsSearch.edgeOrientedMsg("Meek R3 " + d + "--" + a + ", " + b + ", "
+ + c, graph.getEdge(d, a)));
+ return true;
+ }
}
- return oriented;
+ return false;
}
private boolean meekR4(Node a, Node b, Graph graph, Set visited) {
@@ -287,6 +284,8 @@ private boolean meekR4(Node a, Node b, Graph graph, Set visited) {
return false;
}
+ boolean oriented = false;
+
for (Node c : graph.getParents(b)) {
Set adj = getCommonAdjacents(a, c, graph);
adj.remove(b);
@@ -298,12 +297,12 @@ private boolean meekR4(Node a, Node b, Graph graph, Set visited) {
if (graph.getEdge(a, d).isDirected()) continue;
if (direct(a, b, graph, visited)) {
log(LogUtilsSearch.edgeOrientedMsg("Meek R4 using " + c + ", " + d, graph.getEdge(a, b)));
- return true;
+ oriented = true;
}
}
}
- return false;
+ return oriented;
}
private boolean direct(Node a, Node c, Graph graph, Set visited) {
@@ -313,7 +312,7 @@ private boolean direct(Node a, Node c, Graph graph, Set visited) {
Edge before = graph.getEdge(a, c);
graph.removeEdge(before);
- if (meekPreventCycles && graph.paths().existsDirectedPathFromTo(c, a)) {
+ if (meekPreventCycles && graph.paths().existsDirectedPath(c, a)) {
graph.addEdge(before);
return false;
}
@@ -329,9 +328,7 @@ private boolean direct(Node a, Node c, Graph graph, Set visited) {
return true;
}
- private boolean revertToUnshieldedColliders(Node y, Graph graph, Set visited) {
- boolean did = false;
-
+ private void revertToUnshieldedColliders(Node y, Graph graph, Set visited) {
List parents = graph.getParents(y);
P:
@@ -350,11 +347,7 @@ private boolean revertToUnshieldedColliders(Node y, Graph graph, Set visit
visited.add(p);
visited.add(y);
-
- did = true;
}
-
- return did;
}
private void log(String message) {
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/Dci.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/Dci.java
index fbf672b460..1b380c475a 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/Dci.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/Dci.java
@@ -710,7 +710,7 @@ private void awayFromCycle(Graph graph, Node a, Node b, Node c) {
if ((graph.isAdjacentTo(a, c)) &&
(graph.getEndpoint(a, c) == Endpoint.ARROW) &&
(graph.getEndpoint(c, a) == Endpoint.CIRCLE)) {
- if (graph.paths().isDirectedFromTo(a, b) && graph.paths().isDirectedFromTo(b, c)) {
+ if (graph.paths().isDirected(a, b) && graph.paths().isDirected(b, c)) {
graph.setEndpoint(c, a, Endpoint.TAIL);
this.changeFlag = true;
}
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/Ion.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/Ion.java
index a6f73eb78a..3aec16d906 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/Ion.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/Ion.java
@@ -1355,7 +1355,7 @@ private void awayFromCycle(Graph graph, Node a, Node b, Node c) {
if ((graph.isAdjacentTo(a, c)) &&
(graph.getEndpoint(a, c) == Endpoint.ARROW) &&
(graph.getEndpoint(c, a) == Endpoint.CIRCLE)) {
- if (graph.paths().isDirectedFromTo(a, b) && graph.paths().isDirectedFromTo(b, c)) {
+ if (graph.paths().isDirected(a, b) && graph.paths().isDirected(b, c)) {
graph.setEndpoint(c, a, Endpoint.TAIL);
this.changeFlag = true;
}
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/study/performance/PerformanceTests.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/study/performance/PerformanceTests.java
index 66d4e42b74..65aa2abdcc 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/study/performance/PerformanceTests.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/study/performance/PerformanceTests.java
@@ -1813,8 +1813,8 @@ private void bidirectedComparison(Graph dag, Graph truePag, Graph estGraph, Set<
boolean existsCommonCause = false;
for (Node latent : missingNodes) {
- if (dag.paths().existsDirectedPathFromTo(latent, edge.getNode1())
- && dag.paths().existsDirectedPathFromTo(latent, edge.getNode2())) {
+ if (dag.paths().existsDirectedPath(latent, edge.getNode1())
+ && dag.paths().existsDirectedPath(latent, edge.getNode2())) {
existsCommonCause = true;
break;
}
diff --git a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestDM.java b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestDM.java
index 0bc3e86f8c..9f5a35cb80 100644
--- a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestDM.java
+++ b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestDM.java
@@ -743,8 +743,8 @@ public void rtest11() {
graph.addDirectedEdge(X3, X0);
- System.out.print(graph.paths().existsDirectedPathFromTo(X0, X3));
- System.out.print(graph.paths().existsDirectedPathFromTo(X3, X0));
+ System.out.print(graph.paths().existsDirectedPath(X0, X3));
+ System.out.print(graph.paths().existsDirectedPath(X3, X0));
for (Node node : graph.getNodes()) {
System.out.println("Nodes adjacent to " + node + ": " + graph.getAdjacentNodes(node) + "\n");
diff --git a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestDag.java b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestDag.java
index 4f8384645d..ae993a09ca 100644
--- a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestDag.java
+++ b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestDag.java
@@ -76,8 +76,8 @@ private void checkAddRemoveNodes(Dag graph) {
assertTrue(graph.paths().isMConnectedTo(x1, x3, Collections.EMPTY_SET));
- assertTrue(graph.paths().existsDirectedPathFromTo(x1, x4));
- assertFalse(graph.paths().existsDirectedPathFromTo(x1, x5));
+ assertTrue(graph.paths().existsDirectedPath(x1, x4));
+ assertFalse(graph.paths().existsDirectedPath(x1, x5));
assertTrue(graph.paths().isAncestorOf(x2, x4));
assertFalse(graph.paths().isAncestorOf(x4, x2));
diff --git a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGraphUtils.java b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGraphUtils.java
index 4e696c1557..5f58dfbdd8 100644
--- a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGraphUtils.java
+++ b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGraphUtils.java
@@ -67,7 +67,7 @@ public void testDirectedPaths() {
Node node1 = graph.getNodes().get(i);
Node node2 = graph.getNodes().get(j);
- List> directedPaths = graph.paths().directedPathsFromTo(node1, node2, -1);
+ List> directedPaths = graph.paths().directedPaths(node1, node2, -1);
for (List path : directedPaths) {
assertTrue(graph.paths().isAncestorOf(path.get(0), path.get(path.size() - 1)));
@@ -275,41 +275,92 @@ public void test8() {
@Test
public void test9() {
- // Make a random graph.
Graph graph = RandomGraph.randomGraphRandomForwardEdges(20, 0, 50,
10, 10, 10, false);
graph = GraphTransforms.cpdagForDag(graph);
+ int numSmnallestSizes = 2;
+
+ if (!graph.paths().isLegalCpdag()) {
+ throw new IllegalArgumentException("Not legal CPDAG.");
+ }
+
System.out.println(graph);
- // List the nodes in graph.
+ System.out.println("Number of smallest sizes printed = " + numSmnallestSizes);
+
List nodes = graph.getNodes();
- // For each pair x, y of nodes in the graph, list the sets of nodes that are returned by graph.paths().adjustmentSetsMbMpdag(x, y).
- for (int i = 0; i < nodes.size(); i++) {
- for (int j = 0; j < nodes.size(); j++) {
- Node x = nodes.get(i);
- Node y = nodes.get(j);
+ for (Node x : nodes) {
+ for (Node y : nodes) {
if (x == y) continue;
- if (graph.isAdjacentTo(x, y) && graph.getEdge(x, y).pointsTowards(y)) {
- System.out.println("Edge: " + graph.getEdge(x, y));
- } else if (graph.isAdjacentTo(x, y) && Edges.isUndirectedEdge(graph.getEdge(x, y))) {
- System.out.println("Undirected edge: " + graph.getEdge(x, y));
+ if (!graph.isAdjacentTo(x, y)) continue;
+
+ if (graph.getEdge(x, y).pointsTowards(y)) {
+ System.out.println("\nDirected Edge: " + graph.getEdge(x, y));
+ } else if (Edges.isUndirectedEdge(graph.getEdge(x, y))) {
+ System.out.println("\nUndirected edge: " + graph.getEdge(x, y));
+ } else if (graph.getEdge(x, y).pointsTowards(x)) {
+ continue;
} else {
- System.out.println("Wrong: " + graph.getEdge(x, y));
+ throw new IllegalStateException("No edge between " + x + " and " + y);
}
- Set> sets = graph.paths().adjustmentSets2(x, y, -1);
+ Set> sets = graph.paths().adjustmentSets2(x, y, numSmnallestSizes);
+
+ if (sets.isEmpty()) {
+ System.out.println("For " + x + " and " + y + ", no sets.");
+ }
for (Set set : sets) {
System.out.println("For " + x + " and " + y + ", set = " + set);
-// assertTrue(graph.paths().isMSeparatedFrom(x, y, set));
}
}
}
}
+ @Test
+ public void test10() {
+ RandomUtil.getInstance().setSeed(1040404L);
+
+ // 10 times over, make a random DAG
+ for (int i = 0; i < 10; i++) {
+ Graph graph = RandomGraph.randomGraphRandomForwardEdges(10, 10, 5,
+ 10, 10, 10, false);
+
+ // Construct its CPDAG
+ Graph cpdag = GraphTransforms.cpdagForDag(graph);
+ assertTrue(cpdag.paths().isLegalCpdag());
+ assertTrue(cpdag.paths().isLegalMpdag());
+
+// // Test whether the CPDAG is a legal DAG; if not, print it.
+// if (!cpdag.paths().isLegalCpdag()) {
+//
+// System.out.println("Not legal CPDAG:");
+//
+// System.out.println(cpdag);
+//
+// List pi = new ArrayList<>(cpdag.getNodes());
+// cpdag.paths().makeValidOrder(pi);
+//
+// System.out.println("Valid order: " + pi);
+//
+// Graph dag = Paths.getDag(pi, cpdag, true);
+//
+// System.out.println("DAG: " + dag);
+//
+// Graph cpdag2 = GraphTransforms.cpdagForDag(dag);
+//
+// System.out.println("CPDAG for DAG: " + cpdag2);
+//
+// break;
+// }
+ }
+
+ }
+
+
private Set set(Node... z) {
Set list = new HashSet<>();
Collections.addAll(list, z);
diff --git a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGrasp.java b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGrasp.java
index e3e68939ff..d3a6b64d4c 100644
--- a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGrasp.java
+++ b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGrasp.java
@@ -2364,7 +2364,7 @@ private boolean setPathsCanceling(Node x1, Node x4, StandardizedSemIm imsd, List
SemGraph graph = imsd.getSemPm().getGraph();
graph.setShowErrorTerms(false);
- List> paths = graph.paths().allDirectedPathsFromTo(x1, x4, -1);
+ List> paths = graph.paths().allDirectedPaths(x1, x4, -1);
if (paths.size() < 2) return false;
@@ -3298,7 +3298,7 @@ public void testAddUnfaithfulIndependencies() {
count++;
} else {
- List> paths = graph.paths().allPathsFromTo(x, y, 4);
+ List> paths = graph.paths().allPaths(x, y, 4);
if (paths.size() >= 1) {
List> nonTrekPaths = new ArrayList<>();
diff --git a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestPc.java b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestPc.java
index a0b7b31cc7..d573279c5b 100644
--- a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestPc.java
+++ b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestPc.java
@@ -399,7 +399,7 @@ private double[] printStats(String[] algorithms, int t,
}
if (edge.getEndpoint1() == Endpoint.TAIL) {
- if (dag.paths().existsDirectedPathFromTo(edge.getNode1(), edge.getNode2())) {
+ if (dag.paths().existsDirectedPath(edge.getNode1(), edge.getNode2())) {
tailsTp++;
} else {
tailsFp++;
@@ -409,7 +409,7 @@ private double[] printStats(String[] algorithms, int t,
}
if (edge.getEndpoint2() == Endpoint.TAIL) {
- if (dag.paths().existsDirectedPathFromTo(edge.getNode2(), edge.getNode1())) {
+ if (dag.paths().existsDirectedPath(edge.getNode2(), edge.getNode1())) {
tailsTp++;
} else {
tailsFp++;
diff --git a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestSearchGraph.java b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestSearchGraph.java
index 67133fe906..4a7d86f05a 100755
--- a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestSearchGraph.java
+++ b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestSearchGraph.java
@@ -241,6 +241,8 @@ public void testMSeparation() {
}
if (graph.isMSeparatedFrom(x, y, z) != graph.isMSeparatedFrom(y, x, z)) {
+
+
fail(LogUtilsSearch.independenceFact(x, y, z) + " should have same m-sep result as " +
LogUtilsSearch.independenceFact(y, x, z));
}
From d90c69d18eda664a6f403234a1a69d61c4f90119 Mon Sep 17 00:00:00 2001
From: jdramsey
Date: Sun, 14 Apr 2024 04:04:29 -0400
Subject: [PATCH 003/101] Refactor graph separation logic and simplify EdgeNode
Revised the logic used to determine whether nodes in a graph are separated, and modified EdgeNode construct to omit redundant 'sawInArrow' property. This simplification streamlines the EdgeNode construct while preserving functionality, and adjusts various reachability methods to have more direct, readable logic.
---
.../model/CPDAGFromDagGraphWrapper.java | 10 +--
.../main/java/edu/cmu/tetrad/graph/Paths.java | 89 ++++++++-----------
.../java/edu/cmu/tetrad/test/TestGFci.java | 4 +-
.../edu/cmu/tetrad/test/TestGraphUtils.java | 62 +++++++------
.../edu/cmu/tetrad/test/TestSearchGraph.java | 2 +-
5 files changed, 81 insertions(+), 86 deletions(-)
diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/CPDAGFromDagGraphWrapper.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/CPDAGFromDagGraphWrapper.java
index bf1c680608..bc7e29c5d2 100644
--- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/CPDAGFromDagGraphWrapper.java
+++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/CPDAGFromDagGraphWrapper.java
@@ -29,6 +29,8 @@
import edu.cmu.tetrad.util.TetradLogger;
import edu.cmu.tetradapp.session.DoNotAddOldModel;
+import javax.swing.*;
+
/**
* CpdagFromDagGraphWrapper class.
*
@@ -58,11 +60,9 @@ public CPDAGFromDagGraphWrapper(GraphSource source, Parameters parameters) {
public CPDAGFromDagGraphWrapper(Graph graph) {
super(new EdgeListGraph());
- // make sure the given graph is a dag.
- try {
- new Dag(graph);
- } catch (Exception e) {
- throw new IllegalArgumentException("The source graph is not a DAG.");
+ if (!graph.paths().isLegalDag()) {
+ JOptionPane.showMessageDialog(null, "The source graph is not a DAG.",
+ null, JOptionPane.WARNING_MESSAGE);
}
Graph cpdag = CPDAGFromDagGraphWrapper.getCpdag(new EdgeListGraph(graph));
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/Paths.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/Paths.java
index 5d61502262..a7ad5f563d 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/Paths.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/Paths.java
@@ -106,7 +106,7 @@ public static Set getParents(List pi, int p, Graph g, boolean verbos
minus.remove(x);
Set z = new HashSet<>(minus);
- if (!g.paths().isMSeparatedFrom(y, x, z)) {
+ if (!g.paths().isMSeparatedFrom(x, y, z)) {
if (verbose) {
System.out.println("Adding " + y + " as a parent of " + x + " with z = " + z);
}
@@ -950,12 +950,10 @@ class EdgeNode {
private final Edge edge;
private final Node node;
- private boolean sawInArrow = false;
- public EdgeNode(Edge edge, Node node, boolean sawInArrow) {
+ public EdgeNode(Edge edge, Node node) {
this.edge = edge;
this.node = node;
- this.sawInArrow = sawInArrow;
}
public int hashCode() {
@@ -966,7 +964,7 @@ public boolean equals(Object o) {
if (!(o instanceof EdgeNode _o)) {
throw new IllegalArgumentException();
}
- return _o.edge == this.edge && _o.node == this.node && _o.sawInArrow == this.sawInArrow;
+ return _o.edge == this.edge && _o.node == this.node;
}
}
@@ -974,7 +972,7 @@ public boolean equals(Object o) {
Set V = new HashSet<>();
for (Edge edge : graph.getEdges(y)) {
- EdgeNode edgeNode = new EdgeNode(edge, y, false);
+ EdgeNode edgeNode = new EdgeNode(edge, y);
Q.offer(edgeNode);
V.add(edgeNode);
Y.add(edge.getDistalNode(y));
@@ -993,10 +991,8 @@ public boolean equals(Object o) {
continue;
}
- boolean sawInArrow = t.sawInArrow || edge1.getProximalEndpoint(b) == Endpoint.ARROW;
-
- if (reachable(edge1, edge2, a, z, sawInArrow)) {
- EdgeNode u = new EdgeNode(edge2, b, sawInArrow);
+ if (reachable(edge1, edge2, a, z)) {
+ EdgeNode u = new EdgeNode(edge2, b);
if (!V.contains(u)) {
V.add(u);
@@ -1025,12 +1021,10 @@ class EdgeNode {
private final Edge edge;
private final Node node;
- private final boolean sawInArrow;
- public EdgeNode(Edge edge, Node node, boolean sawInArrow) {
+ public EdgeNode(Edge edge, Node node) {
this.edge = edge;
this.node = node;
- this.sawInArrow = sawInArrow;
}
public int hashCode() {
@@ -1041,7 +1035,7 @@ public boolean equals(Object o) {
if (!(o instanceof EdgeNode _o)) {
throw new IllegalArgumentException();
}
- return _o.edge == this.edge && _o.node == this.node && _o.sawInArrow == this.sawInArrow;
+ return _o.edge == this.edge && _o.node == this.node;
}
}
@@ -1049,7 +1043,7 @@ public boolean equals(Object o) {
Set V = new HashSet<>();
for (Edge edge : graph.getEdges(y)) {
- EdgeNode edgeNode = new EdgeNode(edge, y, false);
+ EdgeNode edgeNode = new EdgeNode(edge, y);
Q.offer(edgeNode);
V.add(edgeNode);
Y.add(edge.getDistalNode(y));
@@ -1068,10 +1062,8 @@ public boolean equals(Object o) {
continue;
}
- boolean sawInArrow = edge1.getProximalEndpoint(b) == Endpoint.ARROW;
-
- if (reachable(edge1, edge2, a, z, ancestors, sawInArrow)) {
- EdgeNode u = new EdgeNode(edge2, b, sawInArrow);
+ if (reachable(edge1, edge2, a, z, ancestors)) {
+ EdgeNode u = new EdgeNode(edge2, b);
if (!V.contains(u)) {
V.add(u);
@@ -1085,31 +1077,26 @@ public boolean equals(Object o) {
return Y;
}
- private boolean reachable(Edge e1, Edge e2, Node a, Set z, boolean sawInaArrow) {
+ private boolean reachable(Edge e1, Edge e2, Node a, Set z) {
Node b = e1.getDistalNode(a);
Node c = e2.getDistalNode(b);
- boolean collider = (e1.getProximalEndpoint(b) == Endpoint.ARROW)
- && e2.getProximalEndpoint(b) == Endpoint.ARROW;
+ boolean collider = e1.getProximalEndpoint(b) == Endpoint.ARROW && e2.getProximalEndpoint(b) == Endpoint.ARROW;
if ((!collider || graph.isUnderlineTriple(a, b, c)) && !z.contains(b)) {
return true;
}
- if (sawInaArrow && e2.getProximalEndpoint(b) == Endpoint.ARROW) {
- return false;
- }
-
boolean ancestor = isAncestor(b, z);
return collider && ancestor;
}
// Return true if b is an ancestor of any node in z
- private boolean reachable(Edge e1, Edge e2, Node a, Set z, Map> ancestors, boolean sawInArrow) {
+ private boolean reachable(Edge e1, Edge e2, Node a, Set z, Map> ancestors) {
Node b = e1.getDistalNode(a);
Node c = e2.getDistalNode(b);
- boolean collider = (e1.getProximalEndpoint(b) == Endpoint.ARROW || sawInArrow) && e2.getProximalEndpoint(b) == Endpoint.ARROW;
+ boolean collider = e1.getProximalEndpoint(b) == Endpoint.ARROW && e2.getProximalEndpoint(b) == Endpoint.ARROW;
boolean ancestor = false;
@@ -1124,7 +1111,11 @@ private boolean reachable(Edge e1, Edge e2, Node a, Set z, Map z) {
/**
* Checks if two nodes are M-separated.
*
- * @param node1 The first node.
- * @param node2 The second node.
- * @param z The set of nodes to be excluded from the path.
+ * @param node1 The first node.
+ * @param node2 The second node.
+ * @param z The set of nodes to be excluded from the path.
* @param ancestors A map containing the ancestors of each node.
* @return {@code true} if the two nodes are M-separated, {@code false} otherwise.
*/
@@ -2159,9 +2146,9 @@ public boolean isMSeparatedFrom(Node node1, Node node2, Set z, Map nodes2, LinkedList path) {
diff --git a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGFci.java b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGFci.java
index 4653051cec..c51dfb7a7d 100644
--- a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGFci.java
+++ b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGFci.java
@@ -152,6 +152,8 @@ public void test2() {
g1.addDirectedEdge(L, x2);
g1.addDirectedEdge(L, x3);
+ System.out.println(g1);
+
GFci gfci = new GFci(new MsepTest(g1), new GraphScore(g1));
Graph pag = gfci.search();
@@ -167,7 +169,7 @@ public void test2() {
truePag.addBidirectedEdge(x2, x3);
truePag.addPartiallyOrientedEdge(x4, x3);
- assertEquals(pag, truePag);
+ assertEquals(truePag, pag);
}
// @Test
diff --git a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGraphUtils.java b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGraphUtils.java
index 5f58dfbdd8..ad133fcd1c 100644
--- a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGraphUtils.java
+++ b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGraphUtils.java
@@ -191,6 +191,8 @@ public void testMsep() {
graph.addDirectedEdge(x, y);
graph.addDirectedEdge(y, x);
+// System.out.println(graph);
+
assertTrue(graph.paths().isAncestorOf(a, a));
assertTrue(graph.paths().isAncestorOf(b, b));
assertTrue(graph.paths().isAncestorOf(x, x));
@@ -211,6 +213,7 @@ public void testMsep() {
assertTrue(graph.paths().isMConnectedTo(a, y, new HashSet<>()));
assertTrue(graph.paths().isMConnectedTo(b, x, new HashSet<>()));
+ // MSEP problem now with 2-cycles. TODO
assertTrue(graph.paths().isMConnectedTo(a, y, Collections.singleton(x)));
assertTrue(graph.paths().isMConnectedTo(b, x, Collections.singleton(y)));
@@ -237,12 +240,15 @@ public void testMsep2() {
graph.addDirectedEdge(b, c);
graph.addDirectedEdge(c, b);
+// System.out.println(graph);
+
assertTrue(graph.paths().isAncestorOf(a, b));
assertTrue(graph.paths().isAncestorOf(a, c));
+ // MSEP problem now with 2-cycles. TODO
assertTrue(graph.paths().isMConnectedTo(a, b, Collections.EMPTY_SET));
assertTrue(graph.paths().isMConnectedTo(a, c, Collections.EMPTY_SET));
-
+//
assertTrue(graph.paths().isMConnectedTo(a, c, Collections.singleton(b)));
assertTrue(graph.paths().isMConnectedTo(c, a, Collections.singleton(b)));
}
@@ -251,7 +257,7 @@ public void testMsep2() {
public void test8() {
final int numNodes = 5;
- for (int i = 0; i < 100000; i++) {
+ for (int i = 0; i < 100; i++) {
Graph graph = RandomGraph.randomGraphRandomForwardEdges(numNodes, 0, numNodes, 10, 10, 10, true);
List nodes = graph.getNodes();
@@ -322,40 +328,40 @@ public void test9() {
@Test
public void test10() {
- RandomUtil.getInstance().setSeed(1040404L);
+// RandomUtil.getInstance().setSeed(1040404L);
// 10 times over, make a random DAG
- for (int i = 0; i < 10; i++) {
- Graph graph = RandomGraph.randomGraphRandomForwardEdges(10, 10, 5,
- 10, 10, 10, false);
+ for (int i = 0; i < 1000; i++) {
+ Graph graph = RandomGraph.randomGraphRandomForwardEdges(5, 0, 5,
+ 100, 100, 100, false);
// Construct its CPDAG
Graph cpdag = GraphTransforms.cpdagForDag(graph);
assertTrue(cpdag.paths().isLegalCpdag());
assertTrue(cpdag.paths().isLegalMpdag());
-// // Test whether the CPDAG is a legal DAG; if not, print it.
-// if (!cpdag.paths().isLegalCpdag()) {
-//
-// System.out.println("Not legal CPDAG:");
-//
-// System.out.println(cpdag);
-//
-// List pi = new ArrayList<>(cpdag.getNodes());
-// cpdag.paths().makeValidOrder(pi);
-//
-// System.out.println("Valid order: " + pi);
-//
-// Graph dag = Paths.getDag(pi, cpdag, true);
-//
-// System.out.println("DAG: " + dag);
-//
-// Graph cpdag2 = GraphTransforms.cpdagForDag(dag);
-//
-// System.out.println("CPDAG for DAG: " + cpdag2);
-//
-// break;
-// }
+// Test whether the CPDAG is a legal DAG; if not, print it.
+ if (!cpdag.paths().isLegalCpdag()) {
+
+ System.out.println("Not legal CPDAG:");
+
+ System.out.println(cpdag);
+
+ List pi = new ArrayList<>(cpdag.getNodes());
+ cpdag.paths().makeValidOrder(pi);
+
+ System.out.println("Valid order: " + pi);
+
+ Graph dag = Paths.getDag(pi, cpdag, true);
+
+ System.out.println("DAG: " + dag);
+
+ Graph cpdag2 = GraphTransforms.cpdagForDag(dag);
+
+ System.out.println("CPDAG for DAG: " + cpdag2);
+
+ break;
+ }
}
}
diff --git a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestSearchGraph.java b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestSearchGraph.java
index 4a7d86f05a..9cbe727137 100755
--- a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestSearchGraph.java
+++ b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestSearchGraph.java
@@ -241,7 +241,7 @@ public void testMSeparation() {
}
if (graph.isMSeparatedFrom(x, y, z) != graph.isMSeparatedFrom(y, x, z)) {
-
+ System.out.println(graph);
fail(LogUtilsSearch.independenceFact(x, y, z) + " should have same m-sep result as " +
LogUtilsSearch.independenceFact(y, x, z));
From 216a8bd147f38ff02228ced11fed5ea007c05ccb Mon Sep 17 00:00:00 2001
From: jdramsey
Date: Sun, 14 Apr 2024 05:41:02 -0400
Subject: [PATCH 004/101] Update methods to include additional parameter
Several methods related to checking node separations have been updated to include an additional boolean parameter. This change has been propagated across multiple files. The update also involved commenting out certain lines and modifying relevant unit tests accordingly.
---
.../edu/cmu/tetrad/bayes/UpdatedBayesIm.java | 2 +-
.../edu/cmu/tetrad/graph/EdgeListGraph.java | 27 +-----------------
.../java/edu/cmu/tetrad/graph/GraphUtils.java | 5 ++--
.../java/edu/cmu/tetrad/search/SvarFges.java | 13 +++++----
.../cmu/tetrad/search/score/GraphScore.java | 4 +--
.../edu/cmu/tetrad/search/test/MsepTest.java | 22 +++++++++++++--
.../cmu/tetrad/search/utils/DagSepsets.java | 2 +-
.../tetrad/search/work_in_progress/Dci.java | 8 +++---
.../tetrad/search/work_in_progress/Ion.java | 4 +--
.../edu/cmu/tetrad/study/RBExperiments.java | 6 ++--
.../bayesian/constraint/search/RfciBsc.java | 6 ++--
.../java/edu/cmu/tetrad/test/TestDag.java | 2 +-
.../cmu/tetrad/test/TestEdgeListGraph.java | 2 +-
.../java/edu/cmu/tetrad/test/TestGraph.java | 2 +-
.../edu/cmu/tetrad/test/TestGraphUtils.java | 28 +++++++++----------
.../java/edu/cmu/tetrad/test/TestGrasp.java | 2 +-
.../edu/cmu/tetrad/test/TestSearchGraph.java | 10 +++----
17 files changed, 70 insertions(+), 75 deletions(-)
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/bayes/UpdatedBayesIm.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/bayes/UpdatedBayesIm.java
index 2e4e03000d..b5cb2d0ffa 100755
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/bayes/UpdatedBayesIm.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/bayes/UpdatedBayesIm.java
@@ -700,7 +700,7 @@ private boolean[] calcRelevantVars(int nodeIndex) {
// Added the condition node == node2 since the updater was corrected to exclude this.
// jdramsey 12.13.2014
- if (node == node2 || this.bayesIm.getDag().paths().isMConnectedTo(node, node2, conditionedNodes)) {
+ if (node == node2 || this.bayesIm.getDag().paths().isMConnectedTo(node, node2, conditionedNodes, false)) {
relevantVars[i] = true;
}
}
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/EdgeListGraph.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/EdgeListGraph.java
index 8a76b3f297..3d928e09ec 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/EdgeListGraph.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/EdgeListGraph.java
@@ -496,32 +496,7 @@ public Set getSepset(Node x, Node y) {
* @return True if the nodes in x are all d-separated from nodes in y given nodes in z, false if not.
*/
public boolean isMSeparatedFrom(Node x, Node y, Set z) {
- return !new Paths(this).isMConnectedTo(x, y, z);
- }
-
- /**
- * Determines whether two nodes are d-separated given z.
- *
- * @param x a {@link java.util.Set} object
- * @param y a {@link java.util.Set} object
- * @param z a {@link java.util.Set} object
- * @return True if the nodes in x are all d-separated from nodes in y given nodes in z, false if not.
- */
- public boolean isMSeparatedFrom(Set x, Set y, Set z) {
- return !new Paths(this).isMConnectedTo(x, y, z);
- }
-
- /**
- * Determines whether two nodes are d-separated given z.
- *
- * @param ancestors A map of ancestors for each node.
- * @param x a {@link java.util.Set} object
- * @param y a {@link java.util.Set} object
- * @param z a {@link java.util.Set} object
- * @return True if the nodes are d-separated given z, false if not.
- */
- public boolean isMSeparatedFrom(Set x, Set y, Set z, Map> ancestors) {
- return !new Paths(this).isMConnectedTo(x, y, z, ancestors);
+ return !new Paths(this).isMConnectedTo(x, y, z, false);
}
/**
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/GraphUtils.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/GraphUtils.java
index db3ccf6852..67d9f6364c 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/GraphUtils.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/GraphUtils.java
@@ -2171,7 +2171,8 @@ public static Set> adjustmentSets2(Graph G, Node x, Node y, int numSma
* @return the subsets T of S such that X _||_ Y | T in G and T is a subset of up to the numSmallestSizes minimal
* sizes of subsets for S
*/
- private static Set> getNMinimalSubsets(Graph G, Set S, Node X, Node Y, int numSmallestSizes) {
+ private static Set> getNMinimalSubsets(Graph G, Set S, Node X, Node Y,
+ int numSmallestSizes) {
if (numSmallestSizes < 0) {
throw new IllegalArgumentException("numSmallestSizes must be greater than or equal to 0.");
}
@@ -2186,7 +2187,7 @@ private static Set> getNMinimalSubsets(Graph G, Set S, Node X, N
while ((choice = sublists.next()) != null) {
List subset = GraphUtils.asList(choice, _S);
HashSet s = new HashSet<>(subset);
- if (G.paths().isMSeparatedFrom(X, Y, s)) {
+ if (G.paths().isMSeparatedFrom(X, Y, s, false)) {
if (choice.length > size) {
size = choice.length;
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/SvarFges.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/SvarFges.java
index 54e0b0caa0..f8ee0e9d0f 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/SvarFges.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/SvarFges.java
@@ -745,10 +745,10 @@ protected Boolean compute() {
}
Node y = nodes.get(i);
- Set cond = new HashSet<>();
- Set D = new HashSet<>(SvarFges.this.graph.paths().getMConnectedVars(y, cond));
+// Set cond = new HashSet<>();
+ Set D = new HashSet<>(variables);// SvarFges.this.graph.paths().getMConnectedVars(y, cond));
D.remove(y);
- SvarFges.this.effectEdgesGraph.getAdjacentNodes(y).forEach(D::remove);
+// SvarFges.this.effectEdgesGraph.getAdjacentNodes(y).forEach(D::remove);
for (Node x : D) {
if (existsKnowledge()) {
@@ -1064,9 +1064,10 @@ protected Boolean compute() {
adj = new ArrayList<>(g);
} else if (SvarFges.this.mode == Mode.allowUnfaithfulness) {
- HashSet D = new HashSet<>(SvarFges.this.graph.paths().getMConnectedVars(x, new HashSet<>()));
- D.remove(x);
- adj = new ArrayList<>(D);
+// HashSet D = new HashSet<>(SvarFges.this.graph.paths().getMConnectedVars(x, new HashSet<>()));
+// D.remove(x);
+ adj = new ArrayList<>(variables);
+ adj.remove(x);
} else {
throw new IllegalStateException();
}
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/GraphScore.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/GraphScore.java
index bb2760aae4..73d1c9806a 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/GraphScore.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/GraphScore.java
@@ -199,7 +199,7 @@ private double locallyConsistentScoringCriterion(int x, int y, int[] z) {
boolean dSeparatedFrom;
if (dag != null) {
- dSeparatedFrom = dag.paths().isMSeparatedFrom(_x, _y, _z);
+ dSeparatedFrom = dag.paths().isMSeparatedFrom(_x, _y, _z, false);
} else if (facts != null) {
dSeparatedFrom = facts.isIndependent(_x, _y, _z);
} else {
@@ -211,7 +211,7 @@ private double locallyConsistentScoringCriterion(int x, int y, int[] z) {
private boolean isMSeparatedFrom(Node x, Node y, Set z) {
if (dag != null) {
- return dag.paths().isMSeparatedFrom(x, y, z);
+ return dag.paths().isMSeparatedFrom(x, y, z, false);
} else if (facts != null) {
return facts.isIndependent(x, y, z);
}
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/MsepTest.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/MsepTest.java
index 7df72d375b..b8edf38925 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/MsepTest.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/MsepTest.java
@@ -77,6 +77,10 @@ public class MsepTest implements IndependenceTest {
* The "p-value" of the last test (this is 0 or 1).
*/
private double pvalue = 0;
+ /**
+ * Whether there are any latents.
+ */
+ private boolean hasLatents = false;
/**
* Constructor.
@@ -128,6 +132,13 @@ public MsepTest(Graph graph, boolean keepLatents) {
this.ancestorMap = graph.paths().getAncestorMap();
this._observedVars = calcVars(graph.getNodes(), keepLatents);
this.observedVars = new ArrayList<>(_observedVars);
+ this.hasLatents = false;
+ for (Node node : graph.getNodes()) {
+ if (node.getNodeType() == NodeType.LATENT) {
+ this.hasLatents = true;
+ break;
+ }
+ }
}
/**
@@ -147,6 +158,13 @@ public MsepTest(IndependenceFacts facts, boolean keepLatents) {
this._observedVars = calcVars(facts.getVariables(), keepLatents);
this.observedVars = new ArrayList<>(_observedVars);
+ this.hasLatents = false;
+ for (Node node : facts.getVariables()) {
+ if (node.getNodeType() == NodeType.LATENT) {
+ this.hasLatents = true;
+ break;
+ }
+ }
}
/**
@@ -238,7 +256,7 @@ public IndependenceResult checkIndependence(Node x, Node y, Set z) {
boolean mSeparated;
if (graph != null) {
- mSeparated = !getGraph().paths().isMConnectedTo(x, y, z, ancestorMap);
+ mSeparated = !getGraph().paths().isMConnectedTo(x, y, z, ancestorMap, false);
} else {
mSeparated = independenceFacts.isIndependent(x, y, z);
}
@@ -289,7 +307,7 @@ public boolean isMSeparated(Node x, Node y, Set z) {
}
}
- return getGraph().paths().isMSeparatedFrom(x, y, z, ancestorMap);
+ return getGraph().paths().isMSeparatedFrom(x, y, z, ancestorMap, hasLatents);
}
/**
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/DagSepsets.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/DagSepsets.java
index fc597ded81..992209409c 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/DagSepsets.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/DagSepsets.java
@@ -88,7 +88,7 @@ public double getScore() {
*/
@Override
public boolean isIndependent(Node a, Node b, Set c) {
- return this.dag.paths().isMSeparatedFrom(a, b, c);
+ return this.dag.paths().isMSeparatedFrom(a, b, c, false);
}
/**
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/Dci.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/Dci.java
index 1b380c475a..1d78c15329 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/Dci.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/Dci.java
@@ -1744,7 +1744,7 @@ private boolean predictsFalseDependence(Graph graph) {
continue;
}
for (Set condSet : sepset.getSet(x, y)) {
- if (!graph.paths().isMSeparatedFrom(x, y, condSet)) {
+ if (!graph.paths().isMSeparatedFrom(x, y, condSet, false)) {
return true;
}
}
@@ -1864,7 +1864,7 @@ private void resolveResultingIndependenciesB() {
System.out.println("Resolving inconsistencies... " + c + " of " + cs + " (" + p + " of " + pairs.size() + " pairs)");
c++;
Set z = new HashSet<>(set);
- if (allInd.paths().isMConnectedTo(pair.getFirst(), pair.getSecond(), z)) {
+ if (allInd.paths().isMConnectedTo(pair.getFirst(), pair.getSecond(), z, false)) {
continue;
}
combinedSepset.set(pair.getFirst(), pair.getSecond(), new HashSet<>(set));
@@ -1937,7 +1937,7 @@ private void resolveResultingIndependenciesC() {
for (Set inpset : pset) {
Set cond = new HashSet<>(inpset);
cond.add(node);
- if (fciResult.paths().isMSeparatedFrom(x, y, cond)) {
+ if (fciResult.paths().isMSeparatedFrom(x, y, cond, false)) {
newSepset.set(x, y, cond);
}
}
@@ -1969,7 +1969,7 @@ private void doSepsetClosure(SepsetMapDci sepset, Graph graph) {
int ps = (int) FastMath.pow(2, possibleNodes.size());
for (Set condSet : new PowerSet<>(possibleNodes)) {
System.out.println("Getting closure set... " + c + " of " + ps + "(" + p + " of " + pairs.size() + " remaining)");
- if (graph.paths().isMSeparatedFrom(x, y, new HashSet<>(condSet))) {
+ if (graph.paths().isMSeparatedFrom(x, y, new HashSet<>(condSet), false)) {
sepset.set(x, y, new HashSet<>(condSet));
}
c++;
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/Ion.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/Ion.java
index 3aec16d906..3c56b4c69e 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/Ion.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/Ion.java
@@ -871,7 +871,7 @@ private List> findSepAndAssoc(Graph graph) {
for (Node node : subset) {
pagSubset.add(pag.getNode(node.getName()));
}
- if (pag.paths().isMSeparatedFrom(pagX, pagY, new HashSet<>(pagSubset))) {
+ if (pag.paths().isMSeparatedFrom(pagX, pagY, new HashSet<>(pagSubset), false)) {
if (!pag.isAdjacentTo(pagX, pagY)) {
addIndep = true;
indep.addMoreZ(new HashSet<>(subset));
@@ -918,7 +918,7 @@ private boolean predictsFalseIndependence(Set associations
for (IonIndependenceFacts assocFact : associations)
for (Set conditioningSet : assocFact.getZ())
if (pag.paths().isMSeparatedFrom(
- assocFact.getX(), assocFact.getY(), conditioningSet))
+ assocFact.getX(), assocFact.getY(), conditioningSet, false))
return true;
return false;
}
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/study/RBExperiments.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/study/RBExperiments.java
index d317c4b64a..efda98a00d 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/study/RBExperiments.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/study/RBExperiments.java
@@ -511,7 +511,7 @@ private double getLnProbUsingDepFiltering(Graph pag, Map H) {
for (IndependenceFact fact : H.keySet()) {
BCInference.OP op;
- if (pag.paths().isMSeparatedFrom(fact.getX(), fact.getY(), fact.getZ())) {
+ if (pag.paths().isMSeparatedFrom(fact.getX(), fact.getY(), fact.getZ(), false)) {
op = BCInference.OP.independent;
} else {
op = BCInference.OP.dependent;
diff --git a/tetrad-lib/src/main/java/edu/pitt/dbmi/algo/bayesian/constraint/search/RfciBsc.java b/tetrad-lib/src/main/java/edu/pitt/dbmi/algo/bayesian/constraint/search/RfciBsc.java
index 9cc8fac898..d3f1ff5b83 100644
--- a/tetrad-lib/src/main/java/edu/pitt/dbmi/algo/bayesian/constraint/search/RfciBsc.java
+++ b/tetrad-lib/src/main/java/edu/pitt/dbmi/algo/bayesian/constraint/search/RfciBsc.java
@@ -114,7 +114,7 @@ private static double getLnProbUsingDepFiltering(Graph pag, Map H) {
for (IndependenceFact fact : H.keySet()) {
BCInference.OP op;
- if (pag.paths().isMSeparatedFrom(fact.getX(), fact.getY(), fact.getZ())) {
+ if (pag.paths().isMSeparatedFrom(fact.getX(), fact.getY(), fact.getZ(), false)) {
op = BCInference.OP.independent;
} else {
op = BCInference.OP.dependent;
diff --git a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestDag.java b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestDag.java
index ae993a09ca..73b6480278 100644
--- a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestDag.java
+++ b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestDag.java
@@ -74,7 +74,7 @@ private void checkAddRemoveNodes(Dag graph) {
assertTrue(parents.contains(x3));
assertTrue(parents.contains(x5));
- assertTrue(graph.paths().isMConnectedTo(x1, x3, Collections.EMPTY_SET));
+ assertTrue(graph.paths().isMConnectedTo(x1, x3, Collections.EMPTY_SET, false));
assertTrue(graph.paths().existsDirectedPath(x1, x4));
assertFalse(graph.paths().existsDirectedPath(x1, x5));
diff --git a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestEdgeListGraph.java b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestEdgeListGraph.java
index c9f7e1758a..70ce6d035f 100755
--- a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestEdgeListGraph.java
+++ b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestEdgeListGraph.java
@@ -74,7 +74,7 @@ public void testSequence1() {
assertEquals(children, Collections.singletonList(this.x2));
assertEquals(parents, Collections.singletonList(this.x3));
- assertTrue(this.graph.paths().isMConnectedTo(this.x1, this.x3, Collections.EMPTY_SET));
+ assertTrue(this.graph.paths().isMConnectedTo(this.x1, this.x3, Collections.EMPTY_SET, false));
this.graph.removeNode(this.x2);
// No cycles.
diff --git a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGraph.java b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGraph.java
index 8b483c6587..469d9918fa 100755
--- a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGraph.java
+++ b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGraph.java
@@ -282,7 +282,7 @@ private void checkAddRemoveNodes(Graph graph) {
List children = graph.getChildren(x1);
List parents = graph.getParents(x4);
- assertTrue(graph.paths().isMConnectedTo(x1, x3, new HashSet<>()));
+ assertTrue(graph.paths().isMConnectedTo(x1, x3, new HashSet<>(), false));
graph.removeNode(x2);
diff --git a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGraphUtils.java b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGraphUtils.java
index ad133fcd1c..428b93b287 100644
--- a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGraphUtils.java
+++ b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGraphUtils.java
@@ -210,18 +210,18 @@ public void testMsep() {
assertFalse(graph.paths().isAncestorOf(y, a));
assertFalse(graph.paths().isAncestorOf(x, b));
- assertTrue(graph.paths().isMConnectedTo(a, y, new HashSet<>()));
- assertTrue(graph.paths().isMConnectedTo(b, x, new HashSet<>()));
+ assertTrue(graph.paths().isMConnectedTo(a, y, new HashSet<>(), false));
+ assertTrue(graph.paths().isMConnectedTo(b, x, new HashSet<>(), false));
// MSEP problem now with 2-cycles. TODO
- assertTrue(graph.paths().isMConnectedTo(a, y, Collections.singleton(x)));
- assertTrue(graph.paths().isMConnectedTo(b, x, Collections.singleton(y)));
+ assertTrue(graph.paths().isMConnectedTo(a, y, Collections.singleton(x), false));
+ assertTrue(graph.paths().isMConnectedTo(b, x, Collections.singleton(y), false));
- assertTrue(graph.paths().isMConnectedTo(a, y, Collections.singleton(b)));
- assertTrue(graph.paths().isMConnectedTo(b, x, Collections.singleton(a)));
+ assertTrue(graph.paths().isMConnectedTo(a, y, Collections.singleton(b), false));
+ assertTrue(graph.paths().isMConnectedTo(b, x, Collections.singleton(a), false));
- assertTrue(graph.paths().isMConnectedTo(y, a, Collections.singleton(b)));
- assertTrue(graph.paths().isMConnectedTo(x, b, Collections.singleton(a)));
+ assertTrue(graph.paths().isMConnectedTo(y, a, Collections.singleton(b), false));
+ assertTrue(graph.paths().isMConnectedTo(x, b, Collections.singleton(a), false));
}
@Test
@@ -246,11 +246,11 @@ public void testMsep2() {
assertTrue(graph.paths().isAncestorOf(a, c));
// MSEP problem now with 2-cycles. TODO
- assertTrue(graph.paths().isMConnectedTo(a, b, Collections.EMPTY_SET));
- assertTrue(graph.paths().isMConnectedTo(a, c, Collections.EMPTY_SET));
+ assertTrue(graph.paths().isMConnectedTo(a, b, Collections.EMPTY_SET, false));
+ assertTrue(graph.paths().isMConnectedTo(a, c, Collections.EMPTY_SET, false));
//
- assertTrue(graph.paths().isMConnectedTo(a, c, Collections.singleton(b)));
- assertTrue(graph.paths().isMConnectedTo(c, a, Collections.singleton(b)));
+ assertTrue(graph.paths().isMConnectedTo(a, c, Collections.singleton(b), false));
+ assertTrue(graph.paths().isMConnectedTo(c, a, Collections.singleton(b), false));
}
@@ -266,8 +266,8 @@ public void test8() {
Node z1 = nodes.get(RandomUtil.getInstance().nextInt(numNodes));
Node z2 = nodes.get(RandomUtil.getInstance().nextInt(numNodes));
- if (graph.paths().isMSeparatedFrom(x, y, set(z1)) && graph.paths().isMSeparatedFrom(x, y, set(z2)) &&
- !graph.paths().isMSeparatedFrom(x, y, set(z1, z2))) {
+ if (graph.paths().isMSeparatedFrom(x, y, set(z1), false) && graph.paths().isMSeparatedFrom(x, y, set(z2), false) &&
+ !graph.paths().isMSeparatedFrom(x, y, set(z1, z2), false)) {
System.out.println("x = " + x);
System.out.println("y = " + y);
System.out.println("z1 = " + z1);
diff --git a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGrasp.java b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGrasp.java
index d3a6b64d4c..5aef281559 100644
--- a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGrasp.java
+++ b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGrasp.java
@@ -2773,7 +2773,7 @@ public void testDsep() {
for (Node y : graph.getNodes()) {
if (!graph.paths().isDescendentOf(y, x) && !parents.contains(y)) {
- if (!graph.paths().isMSeparatedFrom(x, y, parents)) {
+ if (!graph.paths().isMSeparatedFrom(x, y, parents, false)) {
System.out.println("Failure! " + LogUtilsSearch.dependenceFactMsg(x, y, parents, 1.0));
}
}
diff --git a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestSearchGraph.java b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestSearchGraph.java
index 9cbe727137..c875ae467a 100755
--- a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestSearchGraph.java
+++ b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestSearchGraph.java
@@ -287,8 +287,8 @@ public void testMSeparation2() {
z.add(theRest.get(value));
}
- boolean mConnectedTo = graph.paths().isMConnectedTo(x, y, z);
- boolean mConnectedTo1 = graph.paths().isMConnectedTo(y, x, z);
+ boolean mConnectedTo = graph.paths().isMConnectedTo(x, y, z, false);
+ boolean mConnectedTo1 = graph.paths().isMConnectedTo(y, x, z, false);
if (mConnectedTo != mConnectedTo1) {
System.out.println(x + " d connected to " + y + " given " + z);
@@ -306,10 +306,10 @@ public void testMSeparation2() {
// Trying to trip up the breadth first algorithm.
public void testMSeparation3() {
Graph graph = GraphUtils.convert("x-->s1,x-->s2,s1-->s3,s3-->s2,s3<--y");
- assertTrue(graph.paths().isMSeparatedFrom(graph.getNode("x"), graph.getNode("y"), new HashSet<>()));
+ assertTrue(graph.paths().isMSeparatedFrom(graph.getNode("x"), graph.getNode("y"), new HashSet<>(), false));
graph = GraphUtils.convert("1-->2,2<--4,2-->7,2-->3");
- assertTrue(graph.paths().isMSeparatedFrom(graph.getNode("4"), graph.getNode("1"), new HashSet<>()));
+ assertTrue(graph.paths().isMSeparatedFrom(graph.getNode("4"), graph.getNode("1"), new HashSet<>(), false));
graph = GraphUtils.convert("X1-->X5,X1-->X6,X2-->X3,X4-->X6,X5-->X3,X6-->X5,X7-->X3");
assertTrue(mConnected(graph, "X2", "X4", "X3", "X6"));
@@ -380,7 +380,7 @@ private boolean mConnected(Graph graph, String x, String y, String... z) {
_z.add(graph.getNode(name));
}
- return graph.paths().isMConnectedTo(_x, _y, _z);
+ return graph.paths().isMConnectedTo(_x, _y, _z, false);
}
public void testAlternativeGraphs() {
From f350195f77b11aa93a038f275eab32d7fc85ce13 Mon Sep 17 00:00:00 2001
From: jdramsey
Date: Sun, 14 Apr 2024 06:16:18 -0400
Subject: [PATCH 005/101] Add selection bias option to getParents method
The 'getParents' method now includes an option to allow for selection bias, impacting how undirected edges are interpreted. This changes the conditions for adding nodes as parents in the path-tracing process. This update will notably affect cyclic directed graphs and PAGs.
---
.../main/java/edu/cmu/tetrad/graph/Paths.java | 221 +++++-------------
1 file changed, 62 insertions(+), 159 deletions(-)
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/Paths.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/Paths.java
index a7ad5f563d..728d420ee1 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/Paths.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/Paths.java
@@ -80,7 +80,7 @@ public static Graph getDag(List pi, Graph g, boolean verbose) {
Graph graph = new EdgeListGraph(pi);
for (int a = 0; a < pi.size(); a++) {
- for (Node b : getParents(pi, a, g, verbose)) {
+ for (Node b : getParents(pi, a, g, verbose, false)) {
graph.addDirectedEdge(b, pi.get(a));
}
}
@@ -91,11 +91,13 @@ public static Graph getDag(List pi, Graph g, boolean verbose) {
/**
* Returns the parents of the node at index p, calculated using Pearl's method.
*
- * @param p The index.
- * @param verbose
+ * @param p The index.
+ * @param verbose Whether to print verbose output.
+ * @param allowSelectionBias whether to allow selection bias; if true, then undirected edges X--Y are uniformly
+ * treated as X->L<-Y.
* @return The parents, as a Pair object (parents + score).
*/
- public static Set getParents(List pi, int p, Graph g, boolean verbose) {
+ public static Set getParents(List pi, int p, Graph g, boolean verbose, boolean allowSelectionBias) {
Node x = pi.get(p);
Set parents = new HashSet<>();
Set prefix = getPrefix(pi, p);
@@ -106,7 +108,7 @@ public static Set getParents(List pi, int p, Graph g, boolean verbos
minus.remove(x);
Set z = new HashSet<>(minus);
- if (!g.paths().isMSeparatedFrom(x, y, z)) {
+ if (!g.paths().isMSeparatedFrom(x, y, z, allowSelectionBias)) {
if (verbose) {
System.out.println("Adding " + y + " as a parent of " + x + " with z = " + z);
}
@@ -810,138 +812,12 @@ public boolean existsSemiDirectedPath(Node from, Node to) {
}
/**
- * isMConnectedTo.
- *
- * @param x a {@link java.util.Set} object
- * @param y a {@link java.util.Set} object
- * @param z a {@link java.util.Set} object
- * @return a boolean
- */
- public boolean isMConnectedTo(Set x, Set y, Set z) {
- Set ancestors = ancestorsOf(z);
-
- Queue> Q = new ArrayDeque<>();
- Set> V = new HashSet<>();
-
- for (Node _x : x) {
- for (Node node : graph.getAdjacentNodes(_x)) {
- if (y.contains(node)) {
- return true;
- }
- OrderedPair edge = new OrderedPair<>(_x, node);
- Q.offer(edge);
- V.add(edge);
- }
- }
-
- while (!Q.isEmpty()) {
- OrderedPair t = Q.poll();
-
- Node b = t.getFirst();
- Node a = t.getSecond();
-
- for (Node c : graph.getAdjacentNodes(b)) {
- if (c == a) {
- continue;
- }
-
- boolean collider = graph.isDefCollider(a, b, c);
- if (!((collider && ancestors.contains(b)) || (!collider && !z.contains(b)))) {
- continue;
- }
-
- if (y.contains(c)) {
- return true;
- }
-
- OrderedPair u = new OrderedPair<>(b, c);
- if (V.contains(u)) {
- continue;
- }
-
- V.add(u);
- Q.offer(u);
- }
- }
-
- return false;
- }
-
- /**
- * Checks to see if x and y are d-connected given z.
+ * Retrieves the set of nodes that are connected to the given node {@code y} and are also present in the set of
+ * nodes {@code z}.
*
- * @param ancestorMap A map of nodes to their ancestors.
- * @param x a {@link java.util.Set} object
- * @param y a {@link java.util.Set} object
- * @param z a {@link java.util.Set} object
- * @return True if x and y are d-connected given z.
- */
- public boolean isMConnectedTo(Set x, Set y, Set z, Map> ancestorMap) {
- if (ancestorMap == null) throw new NullPointerException("Ancestor map cannot be null.");
-
- Queue> Q = new ArrayDeque<>();
- Set> V = new HashSet<>();
-
- for (Node _x : x) {
- for (Node node : graph.getAdjacentNodes(_x)) {
- if (y.contains(node)) {
- return true;
- }
- OrderedPair edge = new OrderedPair<>(_x, node);
- Q.offer(edge);
- V.add(edge);
- }
- }
-
- while (!Q.isEmpty()) {
- OrderedPair t = Q.poll();
-
- Node b = t.getFirst();
- Node a = t.getSecond();
-
- for (Node c : graph.getAdjacentNodes(b)) {
- if (c == a) {
- continue;
- }
-
- boolean collider = graph.isDefCollider(a, b, c);
-
- boolean ancestor = false;
-
- for (Node _z : z) {
- if (ancestorMap.get(_z).contains(b)) {
- ancestor = true;
- break;
- }
- }
-
- if (!((collider && ancestor) || (!collider && !z.contains(b)))) {
- continue;
- }
-
- if (y.contains(c)) {
- return true;
- }
-
- OrderedPair u = new OrderedPair<>(b, c);
- if (V.contains(u)) {
- continue;
- }
-
- V.add(u);
- Q.offer(u);
- }
- }
-
- return false;
- }
-
- /**
- * getMConnectedVars.
- *
- * @param y a {@link edu.cmu.tetrad.graph.Node} object
- * @param z a {@link java.util.Set} object
- * @return a {@link java.util.Set} object
+ * @param y The node for which to find the connected nodes.
+ * @param z The set of nodes to be considered for connecting nodes.
+ * @return The set of nodes that are connected to {@code y} and present in {@code z}.
*/
public Set getMConnectedVars(Node y, Set z) {
Set Y = new HashSet<>();
@@ -1541,7 +1417,7 @@ public boolean isSatisfyBackDoorCriterion(Graph graph, Node x, Node y, Set
});
});
- return dag.paths().isMSeparatedFrom(x, y, z);
+ return dag.paths().isMSeparatedFrom(x, y, z, false);
}
// Finds a sepset for x and y, if there is one; otherwise, returns null.
@@ -1657,12 +1533,14 @@ private boolean sepsetPathFound(Node a, Node b, Node y, Set path, SetL<-Y.
* @return true if x and y are d-connected given z; false otherwise.
*/
- public boolean isMConnectedTo(Node x, Node y, Set z) {
+ public boolean isMConnectedTo(Node x, Node y, Set z, boolean allowSelectionBias) {
class EdgeNode {
private final Edge edge;
@@ -1719,7 +1597,15 @@ public boolean equals(Object o) {
return true;
}
- if (Edges.isDirectedEdge(edge1) && edge1.pointsTowards(b) && Edges.isUndirectedEdge(edge2)) {
+ // If in a CPDAG we have X->Y--Z<-W, reachability can't determine that the path should be
+ // blocked now matter which way Y--Z is oriented, so we need to make a choice. Choosing Y->Z
+ // works for cyclic directed graphs and for PAGs except where X->Y with no circle at X,
+ // in which case Y--Z should be interpreted as selection bias. This is a limitation of the
+ // reachability algorithm here. The problem is that Y--Z is interpreted differently for CPDAGs
+ // than for PAGs, and we are trying to make an m-connection procedure that works for both.
+ // Simply knowing whether selection bias is being allowed is sufficient to make the right choice.
+ // jdramsey 2024-04-14
+ if (!allowSelectionBias && Edges.isDirectedEdge(edge1) && edge1.pointsTowards(b) && Edges.isUndirectedEdge(edge2)) {
edge2 = Edges.directedEdge(b, edge2.getDistalNode(b));
}
@@ -1739,13 +1625,15 @@ public boolean equals(Object o) {
/**
* Detemrmines whether x and y are d-connected given z.
*
- * @param x a {@link edu.cmu.tetrad.graph.Node} object
- * @param y a {@link edu.cmu.tetrad.graph.Node} object
- * @param z a {@link java.util.Set} object
- * @param ancestors a {@link java.util.Map} object
+ * @param x a {@link Node} object
+ * @param y a {@link Node} object
+ * @param z a {@link Set} object
+ * @param ancestors a {@link Map} object
+ * @param allowSelectionBias whether to allow selection bias; if true, then undirected edges X--Y are uniformly
+ * treated as X->L<-Y.
* @return true if x and y are d-connected given z; false otherwise.
*/
- public boolean isMConnectedTo(Node x, Node y, Set z, Map> ancestors) {
+ public boolean isMConnectedTo(Node x, Node y, Set z, Map> ancestors, boolean allowSelectionBias) {
class EdgeNode {
private final Edge edge;
@@ -1802,6 +1690,18 @@ public boolean equals(Object o) {
return true;
}
+ // If in a CPDAG we have X->Y--Z<-W, reachability can't determine that the path should be
+ // blocked now matter which way Y--Z is oriented, so we need to make a choice. Choosing Y->Z
+ // works for cyclic directed graphs and for PAGs except where X->Y with no circle at X,
+ // in which case Y--Z should be interpreted as selection bias. This is a limitation of the
+ // reachability algorithm here. The problem is that Y--Z is interpreted differently for CPDAGs
+ // than for PAGs, and we are trying to make an m-connection procedure that works for both.
+ // Simply knowing whether selection bias is being allowed is sufficient to make the right choice.
+ // jdramsey 2024-04-14
+ if (!allowSelectionBias && Edges.isDirectedEdge(edge1) && edge1.pointsTowards(b) && Edges.isUndirectedEdge(edge2)) {
+ edge2 = Edges.directedEdge(b, edge2.getDistalNode(b));
+ }
+
EdgeNode u = new EdgeNode(edge2, b);
if (!V.contains(u)) {
@@ -2120,27 +2020,30 @@ public boolean definiteNonDescendent(Node node1, Node node2) {
*
* Precondition: This graph is a DAG. Please don't violate this constraint; weird things can happen!
*
- * @param node1 the first node.
- * @param node2 the second node.
- * @param z the conditioning set.
+ * @param node1 the first node.
+ * @param node2 the second node.
+ * @param z the conditioning set.
+ * @param allowSelectionBias whether to allow selection bias; if true, then undirected edges X--Y are uniformly
+ * treated as X->L<-Y.
* @return true if node1 is d-separated from node2 given set t, false if not.
- * @see #isMConnectedTo
*/
- public boolean isMSeparatedFrom(Node node1, Node node2, Set z) {
- return !isMConnectedTo(node1, node2, z);
+ public boolean isMSeparatedFrom(Node node1, Node node2, Set z, boolean allowSelectionBias) {
+ return !isMConnectedTo(node1, node2, z, allowSelectionBias);
}
/**
* Checks if two nodes are M-separated.
*
- * @param node1 The first node.
- * @param node2 The second node.
- * @param z The set of nodes to be excluded from the path.
- * @param ancestors A map containing the ancestors of each node.
+ * @param node1 The first node.
+ * @param node2 The second node.
+ * @param z The set of nodes to be excluded from the path.
+ * @param ancestors A map containing the ancestors of each node.
+ * @param allowSelectionBias whether to allow selection bias; if true, then undirected edges X--Y are uniformly
+ * treated as X->L<-Y.
* @return {@code true} if the two nodes are M-separated, {@code false} otherwise.
*/
- public boolean isMSeparatedFrom(Node node1, Node node2, Set z, Map> ancestors) {
- return !isMConnectedTo(node1, node2, z, ancestors);
+ public boolean isMSeparatedFrom(Node node1, Node node2, Set z, Map> ancestors, boolean allowSelectionBias) {
+ return !isMConnectedTo(node1, node2, z, ancestors, allowSelectionBias);
}
/**
From 32cb83e0c4f8f6577a3e52b5ce06541bf7ccb024 Mon Sep 17 00:00:00 2001
From: jdramsey
Date: Sun, 14 Apr 2024 13:47:22 -0400
Subject: [PATCH 006/101] Add checks for graph types in GUI
Added actions to the GUI that allows users to check if a displayed graph is of a certain type (DAG, CPDAG, MPDAG, MAG, PAG) and displays a corresponding message. The graph types are checked using their respective 'isLegal' methods in the GraphWorkbench class.
---
.../editor/CheckGraphForCpdagAction.java | 79 +++++++++++++++++
.../editor/CheckGraphForDagAction.java | 87 +++++++++++++++++++
.../editor/CheckGraphForMagAction.java | 79 +++++++++++++++++
.../editor/CheckGraphForMpdagAction.java | 80 +++++++++++++++++
.../editor/CheckGraphForPagAction.java | 79 +++++++++++++++++
.../edu/cmu/tetradapp/editor/GraphEditor.java | 3 +
.../cmu/tetradapp/editor/SemGraphEditor.java | 2 +
.../tetradapp/editor/search/GraphCard.java | 2 +
.../edu/cmu/tetradapp/util/GraphUtils.java | 19 ++++
9 files changed, 430 insertions(+)
create mode 100644 tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/CheckGraphForCpdagAction.java
create mode 100644 tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/CheckGraphForDagAction.java
create mode 100644 tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/CheckGraphForMagAction.java
create mode 100644 tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/CheckGraphForMpdagAction.java
create mode 100644 tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/CheckGraphForPagAction.java
diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/CheckGraphForCpdagAction.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/CheckGraphForCpdagAction.java
new file mode 100644
index 0000000000..1104459604
--- /dev/null
+++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/CheckGraphForCpdagAction.java
@@ -0,0 +1,79 @@
+///////////////////////////////////////////////////////////////////////////////
+// For information as to what this class does, see the Javadoc, below. //
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, //
+// 2007, 2008, 2009, 2010, 2014, 2015, 2022 by Peter Spirtes, Richard //
+// Scheines, Joseph Ramsey, and Clark Glymour. //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation; either version 2 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program; if not, write to the Free Software //
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA //
+///////////////////////////////////////////////////////////////////////////////
+
+package edu.cmu.tetradapp.editor;
+
+import edu.cmu.tetrad.graph.Graph;
+import edu.cmu.tetradapp.workbench.GraphWorkbench;
+
+import javax.swing.*;
+import java.awt.event.ActionEvent;
+
+/**
+ * CheckGraphForCpdagAction is an action class that checks if a given graph is a legal CPDAG
+ * (Completed Partially Directed Acyclic Graph) and displays a message to indicate the result.
+ */
+public class CheckGraphForCpdagAction extends AbstractAction {
+
+ /**
+ * The desktop containing the target session editor.
+ */
+ private final GraphWorkbench workbench;
+
+ /**
+ * Highlights all latent variables in the given display graph.
+ *
+ * @param workbench the given workbench.
+ */
+ public CheckGraphForCpdagAction(GraphWorkbench workbench) {
+ super("Check to see if Graph is a CPDAG");
+
+ if (workbench == null) {
+ throw new NullPointerException("Desktop must not be null.");
+ }
+
+ this.workbench = workbench;
+ }
+
+ /**
+ * This method is used to perform an action when an event is triggered, specifically when the user clicks on a button or menu item associated with it. It checks if a graph is
+ * a legal CPDAG (Completed Partially Directed Acyclic Graph).
+ *
+ * @param e The ActionEvent object that represents the event generated by the user action.
+ */
+ public void actionPerformed(ActionEvent e) {
+ Graph graph = workbench.getGraph();
+
+ if (graph == null) {
+ JOptionPane.showMessageDialog(workbench, "No graph to check for CPDAGness.");
+ return;
+ }
+
+ if (graph.paths().isLegalCpdag()) {
+ JOptionPane.showMessageDialog(workbench, "Graph is a legal CPDAG.");
+ } else {
+ JOptionPane.showMessageDialog(workbench, "Graph is not a legal CPDAG.");
+ }
+ }
+}
+
+
+
diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/CheckGraphForDagAction.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/CheckGraphForDagAction.java
new file mode 100644
index 0000000000..43f9072161
--- /dev/null
+++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/CheckGraphForDagAction.java
@@ -0,0 +1,87 @@
+///////////////////////////////////////////////////////////////////////////////
+// For information as to what this class does, see the Javadoc, below. //
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, //
+// 2007, 2008, 2009, 2010, 2014, 2015, 2022 by Peter Spirtes, Richard //
+// Scheines, Joseph Ramsey, and Clark Glymour. //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation; either version 2 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program; if not, write to the Free Software //
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA //
+///////////////////////////////////////////////////////////////////////////////
+
+package edu.cmu.tetradapp.editor;
+
+import edu.cmu.tetrad.graph.Edge;
+import edu.cmu.tetrad.graph.Graph;
+import edu.cmu.tetrad.graph.Node;
+import edu.cmu.tetrad.graph.NodeType;
+import edu.cmu.tetradapp.workbench.DisplayEdge;
+import edu.cmu.tetradapp.workbench.DisplayNode;
+import edu.cmu.tetradapp.workbench.GraphWorkbench;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.ClipboardOwner;
+import java.awt.datatransfer.Transferable;
+import java.awt.event.ActionEvent;
+
+/**
+ * This class represents an action that checks if a graph is a Directed Acyclic Graph (DAG).
+ * It extends the AbstractAction class.
+ */
+public class CheckGraphForDagAction extends AbstractAction {
+
+ /**
+ * The desktop containing the target session editor.
+ */
+ private final GraphWorkbench workbench;
+
+ /**
+ * Highlights all latent variables in the given display graph.
+ *
+ * @param workbench the given workbench.
+ */
+ public CheckGraphForDagAction(GraphWorkbench workbench) {
+ super("Check to see if Graph is a DAG");
+
+ if (workbench == null) {
+ throw new NullPointerException("Desktop must not be null.");
+ }
+
+ this.workbench = workbench;
+ }
+
+ /**
+ * This method checks if the graph is a Directed Acyclic Graph (DAG).
+ *
+ * @param e the action event that triggered the method
+ */
+ public void actionPerformed(ActionEvent e) {
+ Graph graph = workbench.getGraph();
+
+ if (graph == null) {
+ JOptionPane.showMessageDialog(workbench, "No graph to check for DAGness.");
+ return;
+ }
+
+ if (graph.paths().isLegalDag()) {
+ JOptionPane.showMessageDialog(workbench, "Graph is a legal DAG.");
+ } else {
+ JOptionPane.showMessageDialog(workbench, "Graph is not a legal DAG.");
+ }
+ }
+}
+
+
+
diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/CheckGraphForMagAction.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/CheckGraphForMagAction.java
new file mode 100644
index 0000000000..6a79d51788
--- /dev/null
+++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/CheckGraphForMagAction.java
@@ -0,0 +1,79 @@
+///////////////////////////////////////////////////////////////////////////////
+// For information as to what this class does, see the Javadoc, below. //
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, //
+// 2007, 2008, 2009, 2010, 2014, 2015, 2022 by Peter Spirtes, Richard //
+// Scheines, Joseph Ramsey, and Clark Glymour. //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation; either version 2 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program; if not, write to the Free Software //
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA //
+///////////////////////////////////////////////////////////////////////////////
+
+package edu.cmu.tetradapp.editor;
+
+import edu.cmu.tetrad.graph.Graph;
+import edu.cmu.tetradapp.workbench.GraphWorkbench;
+
+import javax.swing.*;
+import java.awt.event.ActionEvent;
+
+/**
+ * CheckGraphForMpdagAction is an action class that checks if a given graph is a legal MPDAG (Mixed Ancestral Graph) and
+ * displays a message to indicate the result.
+ */
+public class CheckGraphForMagAction extends AbstractAction {
+
+ /**
+ * The desktop containing the target session editor.
+ */
+ private final GraphWorkbench workbench;
+
+ /**
+ * Highlights all latent variables in the given display graph.
+ *
+ * @param workbench the given workbench.
+ */
+ public CheckGraphForMagAction(GraphWorkbench workbench) {
+ super("Check to see if Graph is a MAG");
+
+ if (workbench == null) {
+ throw new NullPointerException("Desktop must not be null.");
+ }
+
+ this.workbench = workbench;
+ }
+
+ /**
+ * This method is used to perform an action when an event is triggered, specifically when the user clicks on a
+ * button or menu item associated with it. It checks if a graph is a legal MAG (Mixed Ancestral Graph).
+ *
+ * @param e The ActionEvent object that represents the event generated by the user action.
+ */
+ public void actionPerformed(ActionEvent e) {
+ Graph graph = workbench.getGraph();
+
+ if (graph == null) {
+ JOptionPane.showMessageDialog(workbench, "No graph to check for MAGness.");
+ return;
+ }
+
+ if (graph.paths().isLegalMag()) {
+ JOptionPane.showMessageDialog(workbench, "Graph is a legal MAG.");
+ } else {
+ JOptionPane.showMessageDialog(workbench, "Graph is not a legal MAG.");
+ }
+ }
+}
+
+
+
diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/CheckGraphForMpdagAction.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/CheckGraphForMpdagAction.java
new file mode 100644
index 0000000000..ecc58bf744
--- /dev/null
+++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/CheckGraphForMpdagAction.java
@@ -0,0 +1,80 @@
+///////////////////////////////////////////////////////////////////////////////
+// For information as to what this class does, see the Javadoc, below. //
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, //
+// 2007, 2008, 2009, 2010, 2014, 2015, 2022 by Peter Spirtes, Richard //
+// Scheines, Joseph Ramsey, and Clark Glymour. //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation; either version 2 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program; if not, write to the Free Software //
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA //
+///////////////////////////////////////////////////////////////////////////////
+
+package edu.cmu.tetradapp.editor;
+
+import edu.cmu.tetrad.graph.Graph;
+import edu.cmu.tetradapp.workbench.GraphWorkbench;
+
+import javax.swing.*;
+import java.awt.event.ActionEvent;
+
+/**
+ * CheckGraphForMpdagAction is an action class that checks if a given graph is a legal MPDAG (Maximal Partially Directed
+ * Acyclic Graph) and displays a message to indicate the result.
+ */
+public class CheckGraphForMpdagAction extends AbstractAction {
+
+ /**
+ * The desktop containing the target session editor.
+ */
+ private final GraphWorkbench workbench;
+
+ /**
+ * Highlights all latent variables in the given display graph.
+ *
+ * @param workbench the given workbench.
+ */
+ public CheckGraphForMpdagAction(GraphWorkbench workbench) {
+ super("Check to see if Graph is a MPDAG");
+
+ if (workbench == null) {
+ throw new NullPointerException("Desktop must not be null.");
+ }
+
+ this.workbench = workbench;
+ }
+
+ /**
+ * This method is used to perform an action when an event is triggered, specifically when the user clicks on a
+ * button or menu item associated with it. It checks if a graph is a legal MPDAG (Maximal Partially Directed
+ * Acyclic Graph).
+ *
+ * @param e The ActionEvent object that represents the event generated by the user action.
+ */
+ public void actionPerformed(ActionEvent e) {
+ Graph graph = workbench.getGraph();
+
+ if (graph == null) {
+ JOptionPane.showMessageDialog(workbench, "No graph to check for MPDAGness.");
+ return;
+ }
+
+ if (graph.paths().isLegalMpdag()) {
+ JOptionPane.showMessageDialog(workbench, "Graph is a legal MPDAG.");
+ } else {
+ JOptionPane.showMessageDialog(workbench, "Graph is not a legal MPDAG.");
+ }
+ }
+}
+
+
+
diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/CheckGraphForPagAction.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/CheckGraphForPagAction.java
new file mode 100644
index 0000000000..d4f760b061
--- /dev/null
+++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/CheckGraphForPagAction.java
@@ -0,0 +1,79 @@
+///////////////////////////////////////////////////////////////////////////////
+// For information as to what this class does, see the Javadoc, below. //
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, //
+// 2007, 2008, 2009, 2010, 2014, 2015, 2022 by Peter Spirtes, Richard //
+// Scheines, Joseph Ramsey, and Clark Glymour. //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation; either version 2 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program; if not, write to the Free Software //
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA //
+///////////////////////////////////////////////////////////////////////////////
+
+package edu.cmu.tetradapp.editor;
+
+import edu.cmu.tetrad.graph.Graph;
+import edu.cmu.tetradapp.workbench.GraphWorkbench;
+
+import javax.swing.*;
+import java.awt.event.ActionEvent;
+
+/**
+ * CheckGraphForMpdagAction is an action class that checks if a given graph is a legal PAG (Mixed Ancesgral Graph) and
+ * displays a message to indicate the result.
+ */
+public class CheckGraphForPagAction extends AbstractAction {
+
+ /**
+ * The desktop containing the target session editor.
+ */
+ private final GraphWorkbench workbench;
+
+ /**
+ * Highlights all latent variables in the given display graph.
+ *
+ * @param workbench the given workbench.
+ */
+ public CheckGraphForPagAction(GraphWorkbench workbench) {
+ super("Check to see if Graph is a PAG");
+
+ if (workbench == null) {
+ throw new NullPointerException("Desktop must not be null.");
+ }
+
+ this.workbench = workbench;
+ }
+
+ /**
+ * This method is used to perform an action when an event is triggered, specifically when the user clicks on a
+ * button or menu item associated with it. It checks if a graph is a legal DAG (Partial Ancestral Graph).
+ *
+ * @param e The ActionEvent object that represents the event generated by the user action.
+ */
+ public void actionPerformed(ActionEvent e) {
+ Graph graph = workbench.getGraph();
+
+ if (graph == null) {
+ JOptionPane.showMessageDialog(workbench, "No graph to check for PAGness.");
+ return;
+ }
+
+ if (graph.paths().isLegalPag()) {
+ JOptionPane.showMessageDialog(workbench, "Graph is a legal PAG.");
+ } else {
+ JOptionPane.showMessageDialog(workbench, "Graph is not a legal PAG.");
+ }
+ }
+}
+
+
+
diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/GraphEditor.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/GraphEditor.java
index 1a5ae126fc..094bd85d77 100644
--- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/GraphEditor.java
+++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/GraphEditor.java
@@ -31,6 +31,7 @@
import edu.cmu.tetradapp.model.IndTestProducer;
import edu.cmu.tetradapp.ui.PaddingPanel;
import edu.cmu.tetradapp.util.DesktopController;
+import edu.cmu.tetradapp.util.GraphUtils;
import edu.cmu.tetradapp.util.LayoutEditable;
import edu.cmu.tetradapp.workbench.DisplayEdge;
import edu.cmu.tetradapp.workbench.DisplayNode;
@@ -483,6 +484,7 @@ JMenuBar createGraphMenuBarNoEditing() {
graph.add(new JMenuItem(new SelectUndirectedAction(this.workbench)));
graph.add(new JMenuItem(new SelectTrianglesAction(this.workbench)));
graph.add(new JMenuItem(new SelectLatentsAction(this.workbench)));
+ graph.add(GraphUtils.getCheckGraphMenu(this.workbench));
// graph.addSeparator();
graph.add(new PagColorer(getWorkbench()));
@@ -588,6 +590,7 @@ public void internalFrameClosed(InternalFrameEvent e1) {
graph.add(new JMenuItem(new SelectUndirectedAction(getWorkbench())));
graph.add(new JMenuItem(new SelectTrianglesAction(getWorkbench())));
graph.add(new JMenuItem(new SelectLatentsAction(getWorkbench())));
+ graph.add(GraphUtils.getCheckGraphMenu(this.workbench));
graph.add(new PagColorer(getWorkbench()));
// Only show these menu options for graph that has interventional nodes - Zhou
diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/SemGraphEditor.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/SemGraphEditor.java
index 4d103f280f..08da7bfc9b 100644
--- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/SemGraphEditor.java
+++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/SemGraphEditor.java
@@ -32,6 +32,7 @@
import edu.cmu.tetradapp.session.DelegatesEditing;
import edu.cmu.tetradapp.ui.PaddingPanel;
import edu.cmu.tetradapp.util.DesktopController;
+import edu.cmu.tetradapp.util.GraphUtils;
import edu.cmu.tetradapp.util.LayoutEditable;
import edu.cmu.tetradapp.workbench.DisplayEdge;
import edu.cmu.tetradapp.workbench.DisplayNode;
@@ -565,6 +566,7 @@ public void internalFrameClosed(InternalFrameEvent e1) {
graph.add(new JMenuItem(new SelectTrianglesAction(getWorkbench())));
graph.add(new JMenuItem(new SelectUndirectedAction(getWorkbench())));
graph.add(new JMenuItem(new SelectLatentsAction(this.workbench)));
+ graph.add(GraphUtils.getCheckGraphMenu(this.workbench));
graph.add(new PagColorer(getWorkbench()));
return graph;
diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/search/GraphCard.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/search/GraphCard.java
index ad27d4b3a7..5a69c6021c 100644
--- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/search/GraphCard.java
+++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/search/GraphCard.java
@@ -24,6 +24,7 @@
import edu.cmu.tetradapp.editor.*;
import edu.cmu.tetradapp.model.GeneralAlgorithmRunner;
import edu.cmu.tetradapp.ui.PaddingPanel;
+import edu.cmu.tetradapp.util.GraphUtils;
import edu.cmu.tetradapp.util.ImageUtils;
import edu.cmu.tetradapp.workbench.GraphWorkbench;
@@ -131,6 +132,7 @@ JMenuBar menuBar() {
graph.add(new JMenuItem(new SelectUndirectedAction(this.workbench)));
graph.add(new JMenuItem(new SelectTrianglesAction(this.workbench)));
graph.add(new JMenuItem(new SelectLatentsAction(this.workbench)));
+ graph.add(GraphUtils.getCheckGraphMenu(this.workbench));
graph.add(new PagColorer(this.workbench));
menuBar.add(graph);
diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/util/GraphUtils.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/util/GraphUtils.java
index 04355670d2..8b889663b3 100644
--- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/util/GraphUtils.java
+++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/util/GraphUtils.java
@@ -4,7 +4,11 @@
import edu.cmu.tetrad.graph.*;
import edu.cmu.tetrad.util.Parameters;
import edu.cmu.tetrad.util.PointXy;
+import edu.cmu.tetradapp.editor.*;
+import edu.cmu.tetradapp.workbench.GraphWorkbench;
+import org.jetbrains.annotations.NotNull;
+import javax.swing.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -182,4 +186,19 @@ private static Graph makeRandomScaleFree(int numNodes, int numLatents, double al
alpha, beta, deltaIn, deltaOut);
}
+ public static @NotNull JMenu getCheckGraphMenu(GraphWorkbench workbench) {
+ JMenu checkGraph = new JMenu("Check Graph Type");
+ JMenuItem checkGraphForDag = new JMenuItem(new CheckGraphForDagAction(workbench));
+ JMenuItem checkGraphForCpdag = new JMenuItem(new CheckGraphForCpdagAction(workbench));
+ JMenuItem checkGraphForMpdag = new JMenuItem(new CheckGraphForMpdagAction(workbench));
+ JMenuItem checkGraphForMag = new JMenuItem(new CheckGraphForMagAction(workbench));
+ JMenuItem checkGraphForPag = new JMenuItem(new CheckGraphForPagAction(workbench));
+
+ checkGraph.add(checkGraphForDag);
+ checkGraph.add(checkGraphForCpdag);
+ checkGraph.add(checkGraphForMpdag);
+ checkGraph.add(checkGraphForMag);
+ checkGraph.add(checkGraphForPag);
+ return checkGraph;
+ }
}
From 1c3b626d46aa77761e98eeb4747859eb6992276e Mon Sep 17 00:00:00 2001
From: jdramsey
Date: Mon, 15 Apr 2024 03:49:20 -0400
Subject: [PATCH 007/101] Add support for user-supplied graphs in Algcomparison
Extended the functionality of the AlgcomparisonEditor class to accept and handle graphs supplied by the user. Adjusted the dropdown menu in the UI to include the user-supplied graph option when available. Updated the AlgcomparisonModel class to store and manage the user-supplied graph data.
---
.../tetradapp/editor/AlgcomparisonEditor.java | 37 +++++++++++++++----
.../tetradapp/model/AlgcomparisonModel.java | 19 ++++++++++
2 files changed, 49 insertions(+), 7 deletions(-)
diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/AlgcomparisonEditor.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/AlgcomparisonEditor.java
index 1f03d7672b..f7d7a535a4 100644
--- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/AlgcomparisonEditor.java
+++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/AlgcomparisonEditor.java
@@ -757,8 +757,19 @@ public static StringTextField getStringField(String parameter, Parameters parame
* @throws IllegalAccessException If the graph or simulation constructor or class is inaccessible.
*/
@NotNull
- private static edu.cmu.tetrad.algcomparison.simulation.Simulation getSimulation(Class extends edu.cmu.tetrad.algcomparison.graph.RandomGraph> graphClazz, Class extends edu.cmu.tetrad.algcomparison.simulation.Simulation> simulationClazz) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
- RandomGraph randomGraph = graphClazz.getConstructor().newInstance();
+ private edu.cmu.tetrad.algcomparison.simulation.Simulation getSimulation(Class extends edu.cmu.tetrad.algcomparison.graph.RandomGraph> graphClazz, Class extends edu.cmu.tetrad.algcomparison.simulation.Simulation> simulationClazz) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
+ RandomGraph randomGraph;
+
+ if (graphClazz == SingleGraph.class) {
+ if (model.getSuppliedGraph() == null) {
+ throw new IllegalArgumentException("No graph supplied.");
+ }
+
+ randomGraph = new SingleGraph(model.getSuppliedGraph());
+ } else {
+ randomGraph = graphClazz.getConstructor().newInstance();
+ }
+
return simulationClazz.getConstructor(RandomGraph.class).newInstance(randomGraph);
}
@@ -821,8 +832,12 @@ public static void scrollToWord(JTextArea textArea, JScrollPane scrollPane, Stri
}
@NotNull
- private static Class extends RandomGraph> getGraphClazz(String graphString) {
- List graphTypeStrings = Arrays.asList(ParameterTab.GRAPH_TYPE_ITEMS);
+ private Class extends RandomGraph> getGraphClazz(String graphString) {
+ List graphTypeStrings = new ArrayList<>(Arrays.asList(ParameterTab.GRAPH_TYPE_ITEMS));
+
+ if (model.getSuppliedGraph() != null) {
+ graphTypeStrings.add("User Supplied Graph");
+ }
return switch (graphTypeStrings.indexOf(graphString)) {
case 0:
@@ -831,12 +846,14 @@ private static Class extends RandomGraph> getGraphClazz(String graphString) {
yield ErdosRenyi.class;
case 2:
yield ScaleFree.class;
- case 4:
+ case 3:
yield Cyclic.class;
- case 5:
+ case 4:
yield RandomSingleFactorMim.class;
- case 6:
+ case 5:
yield RandomTwoFactorMim.class;
+ case 6:
+ yield SingleGraph.class;
default:
throw new IllegalArgumentException("Unexpected value: " + graphString);
};
@@ -1441,6 +1458,11 @@ private void addAddSimulationListener() {
JComboBox graphsDropdown = getGraphsDropdown();
Arrays.stream(ParameterTab.GRAPH_TYPE_ITEMS).forEach(graphsDropdown::addItem);
+
+ if (model.getSuppliedGraph() != null) {
+ graphsDropdown.addItem("User Supplied Graph");
+ }
+
graphsDropdown.setMaximumSize(graphsDropdown.getPreferredSize());
graphsDropdown.setSelectedItem(model.getLastGraphChoice());
@@ -1507,6 +1529,7 @@ private JComboBox getGraphsDropdown() {
model.setLastGraphChoice(selectedItem);
}
});
+
return graphsDropdown;
}
diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/AlgcomparisonModel.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/AlgcomparisonModel.java
index 91d4abba3b..7ea889a4b5 100644
--- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/AlgcomparisonModel.java
+++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/AlgcomparisonModel.java
@@ -33,6 +33,7 @@
import edu.cmu.tetrad.algcomparison.statistic.Statistics;
import edu.cmu.tetrad.algcomparison.utils.TakesIndependenceWrapper;
import edu.cmu.tetrad.algcomparison.utils.UsesScoreWrapper;
+import edu.cmu.tetrad.graph.Graph;
import edu.cmu.tetrad.util.ParamDescription;
import edu.cmu.tetrad.util.ParamDescriptions;
import edu.cmu.tetrad.util.Parameters;
@@ -72,6 +73,11 @@ public class AlgcomparisonModel implements SessionModel {
* The results path for the AlgcomparisonModel.
*/
private final String resultsRoot = System.getProperty("user.home");
+ /**
+ * The suppliedGraph variable represents a graph that can be supplied by the user.
+ * This graph will be given as an option in the user interface.
+ */
+ private Graph suppliedGraph = null;
/**
* The list of statistic names.
*/
@@ -130,6 +136,12 @@ public AlgcomparisonModel(Parameters parameters) {
initializeIfNull();
}
+ public AlgcomparisonModel(GraphSource graphSource, Parameters parameters) {
+ this.parameters = new Parameters();
+ this.suppliedGraph = graphSource.getGraph();
+ initializeIfNull();
+ }
+
/**
* Finds and returns a list of algorithm classes that implement the Algorithm interface.
*
@@ -800,6 +812,13 @@ public List getSelectedAlgorithmModels() {
return new ArrayList<>(selectedAlgorithmModels);
}
+ /**
+ * The user may supply a graph, which will be given as an option in the UI.
+ */
+ public Graph getSuppliedGraph() {
+ return suppliedGraph;
+ }
+
public static class MyTableColumn {
private final String columnName;
private final String description;
From 6015e261d4bdd300d2bdbf037f79ba9a2cd70e6d Mon Sep 17 00:00:00 2001
From: jdramsey
Date: Mon, 15 Apr 2024 11:40:19 -0400
Subject: [PATCH 008/101] Implement Meek Rules in Paths class
A new import, `edu.cmu.tetrad.search.utils.MeekRules`, was added to the Paths class. This was used to implement Meek rules which aid in orienting edges in the graphical model. The equals_check was adjusted - now it also verifies the maximality by comparing the original graph with the newly oriented one. If both are equal, it returns true; otherwise, it returns false.
---
.../src/main/java/edu/cmu/tetrad/graph/Paths.java | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/Paths.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/Paths.java
index 728d420ee1..cec60cff5d 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/Paths.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/Paths.java
@@ -2,6 +2,7 @@
import edu.cmu.tetrad.search.IndependenceTest;
import edu.cmu.tetrad.search.utils.GraphSearchUtils;
+import edu.cmu.tetrad.search.utils.MeekRules;
import edu.cmu.tetrad.search.utils.SepsetMap;
import edu.cmu.tetrad.util.SublistGenerator;
import edu.cmu.tetrad.util.TaskManager;
@@ -261,13 +262,21 @@ public boolean isLegalMpdag() {
try {
g.paths().makeValidOrder(pi);
- Graph dag = getDag(pi, g/*GraphTransforms.dagFromCpdag(g)*/, false);
+ Graph dag = getDag(pi, g, false);
Graph cpdag = GraphTransforms.cpdagForDag(dag);
-
Graph _g = new EdgeListGraph(g);
_g = GraphTransforms.cpdagForDag(_g);
- return _g.equals(cpdag);
+ boolean equals = _g.equals(cpdag);
+
+ // Check maximality...
+ if (equals) {
+ Graph __g = new EdgeListGraph(g);
+ new MeekRules().orientImplied(__g);
+ return g.equals(__g);
+ }
+
+ return false;
} catch (Exception e) {
// There was no valid sink.
System.out.println(e.getMessage());
From 1146fb33fef0424ff080581756f120cf172d1a04 Mon Sep 17 00:00:00 2001
From: jdramsey
Date: Mon, 15 Apr 2024 16:27:08 -0400
Subject: [PATCH 009/101] Update UI and graph logic
Refactored GraphEditor.java and related files to reorganize menu items and enhance graph operations. The main changes include the introduction of "Run Meek Rules" and "Revert to CPDAG" options for more comprehensive graph editing, along with keyboard shortcuts for these options. The refactoring also improved the method for calculating adjustment sets, making it more flexible and efficient. The significant UI enhancements improved the user interaction flow.
---
.../edu/cmu/tetradapp/editor/DagEditor.java | 19 +--
.../edu/cmu/tetradapp/editor/GraphEditor.java | 37 +++---
.../cmu/tetradapp/editor/RevertToCpdag.java | 105 +++++++++++++++++
.../cmu/tetradapp/editor/RunMeekRules.java | 109 ++++++++++++++++++
.../cmu/tetradapp/editor/SemGraphEditor.java | 21 ++--
.../tetradapp/editor/search/GraphCard.java | 17 ++-
.../edu/cmu/tetradapp/util/GraphUtils.java | 10 ++
.../java/edu/cmu/tetrad/graph/GraphUtils.java | 100 ++++++----------
.../main/java/edu/cmu/tetrad/graph/Paths.java | 44 ++++---
9 files changed, 350 insertions(+), 112 deletions(-)
create mode 100644 tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/RevertToCpdag.java
create mode 100644 tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/RunMeekRules.java
diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/DagEditor.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/DagEditor.java
index c0e14fb7ec..56386d09b1 100644
--- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/DagEditor.java
+++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/DagEditor.java
@@ -31,6 +31,7 @@
import edu.cmu.tetradapp.session.DelegatesEditing;
import edu.cmu.tetradapp.ui.PaddingPanel;
import edu.cmu.tetradapp.util.DesktopController;
+import edu.cmu.tetradapp.util.GraphUtils;
import edu.cmu.tetradapp.util.LayoutEditable;
import edu.cmu.tetradapp.workbench.DisplayEdge;
import edu.cmu.tetradapp.workbench.DisplayNode;
@@ -475,13 +476,17 @@ private JMenu createGraphMenu() {
graph.add(new GraphPropertiesAction(this.workbench));
graph.add(new PathsAction(this.workbench));
graph.add(new UnderliningsAction(this.workbench));
-
- graph.add(new JMenuItem(new SelectDirectedAction(this.workbench)));
- graph.add(new JMenuItem(new SelectBidirectedAction(this.workbench)));
- graph.add(new JMenuItem(new SelectUndirectedAction(this.workbench)));
- graph.add(new JMenuItem(new SelectTrianglesAction(this.workbench)));
- graph.add(new JMenuItem(new SelectLatentsAction(this.workbench)));
-// graph.add(new PagTypeSetter(getWorkbench()));
+ graph.add(GraphUtils.getHighlightMenu(this.workbench));
+ graph.add(GraphUtils.getCheckGraphMenu(this.workbench));
+ JMenuItem runMeekRules = new JMenuItem(new RunMeekRules(this.workbench));
+ graph.add(runMeekRules);
+ JMenuItem revertToCpdag = new JMenuItem(new RevertToCpdag(this.workbench));
+ graph.add(revertToCpdag);
+ graph.add(new PagColorer(this.workbench));
+ runMeekRules.setAccelerator(
+ KeyStroke.getKeyStroke(KeyEvent.VK_M, InputEvent.CTRL_DOWN_MASK));
+ revertToCpdag.setAccelerator(
+ KeyStroke.getKeyStroke(KeyEvent.VK_R, InputEvent.CTRL_DOWN_MASK));
randomGraph.addActionListener(e -> {
diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/GraphEditor.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/GraphEditor.java
index 094bd85d77..8092637202 100644
--- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/GraphEditor.java
+++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/GraphEditor.java
@@ -478,15 +478,17 @@ JMenuBar createGraphMenuBarNoEditing() {
graph.add(new GraphPropertiesAction(this.workbench));
graph.add(new PathsAction(this.workbench));
graph.add(new UnderliningsAction(this.workbench));
-
- graph.add(new JMenuItem(new SelectDirectedAction(this.workbench)));
- graph.add(new JMenuItem(new SelectBidirectedAction(this.workbench)));
- graph.add(new JMenuItem(new SelectUndirectedAction(this.workbench)));
- graph.add(new JMenuItem(new SelectTrianglesAction(this.workbench)));
- graph.add(new JMenuItem(new SelectLatentsAction(this.workbench)));
+ graph.add(GraphUtils.getHighlightMenu(this.workbench));
graph.add(GraphUtils.getCheckGraphMenu(this.workbench));
-// graph.addSeparator();
- graph.add(new PagColorer(getWorkbench()));
+ JMenuItem runMeekRules = new JMenuItem(new RunMeekRules(this.workbench));
+ graph.add(runMeekRules);
+ JMenuItem revertToCpdag = new JMenuItem(new RevertToCpdag(this.workbench));
+ graph.add(revertToCpdag);
+ graph.add(new PagColorer(this.workbench));
+ runMeekRules.setAccelerator(
+ KeyStroke.getKeyStroke(KeyEvent.VK_M, InputEvent.CTRL_DOWN_MASK));
+ revertToCpdag.setAccelerator(
+ KeyStroke.getKeyStroke(KeyEvent.VK_R, InputEvent.CTRL_DOWN_MASK));
menuBar.add(graph);
@@ -585,13 +587,20 @@ public void internalFrameClosed(InternalFrameEvent e1) {
});
});
- graph.add(new JMenuItem(new SelectDirectedAction(getWorkbench())));
- graph.add(new JMenuItem(new SelectBidirectedAction(getWorkbench())));
- graph.add(new JMenuItem(new SelectUndirectedAction(getWorkbench())));
- graph.add(new JMenuItem(new SelectTrianglesAction(getWorkbench())));
- graph.add(new JMenuItem(new SelectLatentsAction(getWorkbench())));
+ graph.add(new GraphPropertiesAction(this.workbench));
+ graph.add(new PathsAction(this.workbench));
+ graph.add(new UnderliningsAction(this.workbench));
+ graph.add(GraphUtils.getHighlightMenu(this.workbench));
graph.add(GraphUtils.getCheckGraphMenu(this.workbench));
- graph.add(new PagColorer(getWorkbench()));
+ JMenuItem runMeekRules = new JMenuItem(new RunMeekRules(this.workbench));
+ graph.add(runMeekRules);
+ JMenuItem revertToCpdag = new JMenuItem(new RevertToCpdag(this.workbench));
+ graph.add(revertToCpdag);
+ graph.add(new PagColorer(this.workbench));
+ runMeekRules.setAccelerator(
+ KeyStroke.getKeyStroke(KeyEvent.VK_M, InputEvent.CTRL_DOWN_MASK));
+ revertToCpdag.setAccelerator(
+ KeyStroke.getKeyStroke(KeyEvent.VK_R, InputEvent.CTRL_DOWN_MASK));
// Only show these menu options for graph that has interventional nodes - Zhou
if (isHasInterventional()) {
diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/RevertToCpdag.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/RevertToCpdag.java
new file mode 100644
index 0000000000..2f50e1eabc
--- /dev/null
+++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/RevertToCpdag.java
@@ -0,0 +1,105 @@
+///////////////////////////////////////////////////////////////////////////////
+// For information as to what this class does, see the Javadoc, below. //
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, //
+// 2007, 2008, 2009, 2010, 2014, 2015, 2022 by Peter Spirtes, Richard //
+// Scheines, Joseph Ramsey, and Clark Glymour. //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation; either version 2 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program; if not, write to the Free Software //
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA //
+///////////////////////////////////////////////////////////////////////////////
+
+package edu.cmu.tetradapp.editor;
+
+import edu.cmu.tetrad.graph.Edge;
+import edu.cmu.tetrad.graph.EdgeListGraph;
+import edu.cmu.tetrad.graph.Edges;
+import edu.cmu.tetrad.graph.Graph;
+import edu.cmu.tetrad.search.utils.MeekRules;
+import edu.cmu.tetradapp.workbench.GraphWorkbench;
+
+import javax.swing.*;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.ClipboardOwner;
+import java.awt.datatransfer.Transferable;
+import java.awt.event.ActionEvent;
+
+/**
+ * Selects all directed edges in the given display graph.
+ *
+ * @author josephramsey
+ * @version $Id: $Id
+ */
+public class RevertToCpdag extends AbstractAction implements ClipboardOwner {
+
+ /**
+ * The desktop containing the target session editor.
+ */
+ private final GraphWorkbench workbench;
+
+ /**
+ * Creates a new copy subsession action for the given desktop and clipboard.
+ *
+ * @param workbench the given workbench.
+ */
+ public RevertToCpdag(GraphWorkbench workbench) {
+ super("Revert to CPDAG");
+
+ if (workbench == null) {
+ throw new NullPointerException("Desktop must not be null.");
+ }
+
+ this.workbench = workbench;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Selects all directed edges in the given display graph.
+ */
+ public void actionPerformed(ActionEvent e) {
+ this.workbench.deselectAll();
+ Graph graph = this.workbench.getGraph();
+
+ if (graph == null) {
+ JOptionPane.showMessageDialog(this.workbench, "No graph to run Meek rules on.");
+ return;
+ }
+
+ // check to make sure the edges in the graph are all directed or undirected
+ for (Edge edge : graph.getEdges()) {
+ if (!Edges.isDirectedEdge(edge) && !Edges.isUndirectedEdge(edge)) {
+ JOptionPane.showMessageDialog(this.workbench,
+ "To revert to CPDAG, the graph must contain only directed or undirected edges.");
+ return;
+ }
+ }
+
+ graph = new EdgeListGraph(graph);
+ MeekRules meekRules = new MeekRules();
+ meekRules.setRevertToUnshieldedColliders(true);
+ meekRules.orientImplied(graph);
+ workbench.setGraph(graph);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Required by the AbstractAction interface; does nothing.
+ */
+ public void lostOwnership(Clipboard clipboard, Transferable contents) {
+ }
+}
+
+
+
diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/RunMeekRules.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/RunMeekRules.java
new file mode 100644
index 0000000000..a0b6f1a2e2
--- /dev/null
+++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/RunMeekRules.java
@@ -0,0 +1,109 @@
+///////////////////////////////////////////////////////////////////////////////
+// For information as to what this class does, see the Javadoc, below. //
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, //
+// 2007, 2008, 2009, 2010, 2014, 2015, 2022 by Peter Spirtes, Richard //
+// Scheines, Joseph Ramsey, and Clark Glymour. //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation; either version 2 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program; if not, write to the Free Software //
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA //
+///////////////////////////////////////////////////////////////////////////////
+
+package edu.cmu.tetradapp.editor;
+
+import edu.cmu.tetrad.graph.Edge;
+import edu.cmu.tetrad.graph.EdgeListGraph;
+import edu.cmu.tetrad.graph.Edges;
+import edu.cmu.tetrad.graph.Graph;
+import edu.cmu.tetrad.search.utils.MeekRules;
+import edu.cmu.tetradapp.workbench.DisplayEdge;
+import edu.cmu.tetradapp.workbench.GraphWorkbench;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.ClipboardOwner;
+import java.awt.datatransfer.Transferable;
+import java.awt.event.ActionEvent;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+
+/**
+ * Selects all directed edges in the given display graph.
+ *
+ * @author josephramsey
+ * @version $Id: $Id
+ */
+public class RunMeekRules extends AbstractAction implements ClipboardOwner {
+
+ /**
+ * The desktop containing the target session editor.
+ */
+ private final GraphWorkbench workbench;
+
+ /**
+ * Creates a new copy subsession action for the given desktop and clipboard.
+ *
+ * @param workbench the given workbench.
+ */
+ public RunMeekRules(GraphWorkbench workbench) {
+ super("Run Meek Rules");
+
+ if (workbench == null) {
+ throw new NullPointerException("Desktop must not be null.");
+ }
+
+ this.workbench = workbench;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Selects all directed edges in the given display graph.
+ */
+ public void actionPerformed(ActionEvent e) {
+ this.workbench.deselectAll();
+ Graph graph = this.workbench.getGraph();
+
+ if (graph == null) {
+ JOptionPane.showMessageDialog(this.workbench, "No graph to run Meek rules on.");
+ return;
+ }
+
+ // check to make sure the edges in the graph are all directed or undirected
+ for (Edge edge : graph.getEdges()) {
+ if (!Edges.isDirectedEdge(edge) && !Edges.isUndirectedEdge(edge)) {
+ JOptionPane.showMessageDialog(this.workbench,
+ "To run Meek rules, the graph must contain only directed or undirected edges.");
+ return;
+ }
+ }
+
+ graph = new EdgeListGraph(graph);
+ MeekRules meekRules = new MeekRules();
+ meekRules.setRevertToUnshieldedColliders(false);
+ meekRules.orientImplied(graph);
+ workbench.setGraph(graph);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Required by the AbstractAction interface; does nothing.
+ */
+ public void lostOwnership(Clipboard clipboard, Transferable contents) {
+ }
+}
+
+
+
diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/SemGraphEditor.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/SemGraphEditor.java
index 08da7bfc9b..1d899008f9 100644
--- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/SemGraphEditor.java
+++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/SemGraphEditor.java
@@ -560,14 +560,21 @@ public void internalFrameClosed(InternalFrameEvent e1) {
});
});
- graph.add(new JMenuItem(new SelectDirectedAction(this.workbench)));
- graph.add(new JMenuItem(new SelectBidirectedAction(this.workbench)));
- graph.add(new JMenuItem(new SelectUndirectedAction(getWorkbench())));
- graph.add(new JMenuItem(new SelectTrianglesAction(getWorkbench())));
- graph.add(new JMenuItem(new SelectUndirectedAction(getWorkbench())));
- graph.add(new JMenuItem(new SelectLatentsAction(this.workbench)));
+ graph.add(new GraphPropertiesAction(this.workbench));
+ graph.add(new PathsAction(this.workbench));
+ graph.add(new UnderliningsAction(this.workbench));
+ graph.add(GraphUtils.getHighlightMenu(this.workbench));
graph.add(GraphUtils.getCheckGraphMenu(this.workbench));
- graph.add(new PagColorer(getWorkbench()));
+ JMenuItem runMeekRules = new JMenuItem(new RunMeekRules(this.workbench));
+ graph.add(runMeekRules);
+ JMenuItem revertToCpdag = new JMenuItem(new RevertToCpdag(this.workbench));
+ graph.add(revertToCpdag);
+ graph.add(new PagColorer(this.workbench));
+ runMeekRules.setAccelerator(
+ KeyStroke.getKeyStroke(KeyEvent.VK_M, InputEvent.CTRL_DOWN_MASK));
+ revertToCpdag.setAccelerator(
+ KeyStroke.getKeyStroke(KeyEvent.VK_R, InputEvent.CTRL_DOWN_MASK));
+
return graph;
}
diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/search/GraphCard.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/search/GraphCard.java
index 5a69c6021c..6f9f02e549 100644
--- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/search/GraphCard.java
+++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/search/GraphCard.java
@@ -36,6 +36,8 @@
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
import java.io.Serial;
import java.net.URL;
@@ -126,14 +128,17 @@ JMenuBar menuBar() {
graph.add(new GraphPropertiesAction(this.workbench));
graph.add(new PathsAction(this.workbench));
graph.add(new UnderliningsAction(this.workbench));
-
- graph.add(new JMenuItem(new SelectDirectedAction(this.workbench)));
- graph.add(new JMenuItem(new SelectBidirectedAction(this.workbench)));
- graph.add(new JMenuItem(new SelectUndirectedAction(this.workbench)));
- graph.add(new JMenuItem(new SelectTrianglesAction(this.workbench)));
- graph.add(new JMenuItem(new SelectLatentsAction(this.workbench)));
+ graph.add(GraphUtils.getHighlightMenu(this.workbench));
graph.add(GraphUtils.getCheckGraphMenu(this.workbench));
+ JMenuItem runMeekRules = new JMenuItem(new RunMeekRules(this.workbench));
+ graph.add(runMeekRules);
+ JMenuItem revertToCpdag = new JMenuItem(new RevertToCpdag(this.workbench));
+ graph.add(revertToCpdag);
graph.add(new PagColorer(this.workbench));
+ runMeekRules.setAccelerator(
+ KeyStroke.getKeyStroke(KeyEvent.VK_M, InputEvent.CTRL_DOWN_MASK));
+ revertToCpdag.setAccelerator(
+ KeyStroke.getKeyStroke(KeyEvent.VK_R, InputEvent.CTRL_DOWN_MASK));
menuBar.add(graph);
diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/util/GraphUtils.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/util/GraphUtils.java
index 8b889663b3..ab3d044eaf 100644
--- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/util/GraphUtils.java
+++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/util/GraphUtils.java
@@ -201,4 +201,14 @@ private static Graph makeRandomScaleFree(int numNodes, int numLatents, double al
checkGraph.add(checkGraphForPag);
return checkGraph;
}
+
+ public static @NotNull JMenu getHighlightMenu(GraphWorkbench workbench) {
+ JMenu highlightMenu = new JMenu("Highlight");
+ highlightMenu.add(new SelectDirectedAction(workbench));
+ highlightMenu.add(new SelectBidirectedAction(workbench));
+ highlightMenu.add(new SelectUndirectedAction(workbench));
+ highlightMenu.add(new SelectTrianglesAction(workbench));
+ highlightMenu.add(new SelectLatentsAction(workbench));
+ return highlightMenu;
+ }
}
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/GraphUtils.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/GraphUtils.java
index 67d9f6364c..6878a26f54 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/GraphUtils.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/GraphUtils.java
@@ -23,7 +23,6 @@
import edu.cmu.tetrad.data.Knowledge;
import edu.cmu.tetrad.data.KnowledgeEdge;
import edu.cmu.tetrad.graph.Edge.Property;
-import edu.cmu.tetrad.search.test.MsepTest;
import edu.cmu.tetrad.search.utils.FciOrient;
import edu.cmu.tetrad.search.utils.GraphSearchUtils;
import edu.cmu.tetrad.search.utils.MeekRules;
@@ -2045,83 +2044,56 @@ public static Set district(Node x, Graph G) {
}
/**
- * Returns adjustment sets of X-&Y in MPDAG G2 that are subsets of the Markov blanket for X in G2 or the Markov
- * blanket of Y in G2, once the edge X-&Y is removed from the graph. If X and Y are not adjacent in G2, the
- * method returns an empty set. If X and Y are connected by an undirected edge, first the edge is oriented as
- * X->Y, and then the Meek rules are applied to find an MPDAG G2' that is consistent with G2 and the orientation
- * of X->Y. The adjustment sets are then calculated in G2' as above.
+ * Calculates the adjustment sets of a given graph G between two nodes x and y that are subsets of MB(X).
+ *
+ * @param G the input graph
+ * @param x the source node
+ * @param y the target node
+ * @param numSmallestSizes the number of smallest adjustment sets to return
+ * @return the adjustment sets as a set of sets of nodes
+ * @throws IllegalArgumentException if the input graph is not a legal MPDAG
*/
- public static Set> adjustmentSets1(Graph G, Node X, Node Y) {
+ public static Set> adjustmentSets1(Graph G, Node x, Node y, int numSmallestSizes) {
if (!G.paths().isLegalMpdag()) {
throw new IllegalArgumentException("Graph must be a legal MPDAG.");
}
- Graph G2 = new EdgeListGraph(G);
-
- Set> adjustmentSets = new HashSet<>();
-
- if (G2.isAdjacentTo(X, Y)) {
- if (Edges.isUndirectedEdge(G2.getEdge(X, Y))) {
- Knowledge knowledge = new Knowledge();
- knowledge.setRequired(X.getName(), Y.getName());
- MeekRules meekRules = new MeekRules();
- meekRules.setKnowledge(knowledge);
- G2.removeEdge(X, Y);
- G2.addDirectedEdge(X, Y);
- meekRules.orientImplied(G2);
- }
-
- if (!G2.getEdge(X, Y).pointsTowards(Y)) {
- return adjustmentSets;
- }
-
- G2.removeEdge(X, Y);
- MsepTest msep = new MsepTest(G2);
-
- Set mbX = GraphUtils.markovBlanket(X, G2);
-
- List _mbX = new ArrayList<>(mbX);
- SublistGenerator mbXGenerator = new SublistGenerator(_mbX.size(), _mbX.size());
- int[] choice;
-
- while ((choice = mbXGenerator.next()) != null) {
- List sx = GraphUtils.asList(choice, _mbX);
- if (sx.contains(Y)) {
- continue;
- }
-
- if (msep.isMSeparated(X, Y, new HashSet<>(sx))) {
- adjustmentSets.add(new HashSet<>(sx));
- }
+ Graph G2 = getGraphWithoutXToY(G, x, y);
- adjustmentSets.add(new HashSet<>(sx));
- }
+ // Get the Markov blanket for x in G2.
+ Set mbX = markovBlanket(x, G2);
- Set mbY = GraphUtils.markovBlanket(Y, G2);
+ return getNMinimalSubsets(getGraphWithoutXToY(G, x, y), mbX, x, y, numSmallestSizes);
+ }
- List _mbY = new ArrayList<>(mbY);
- SublistGenerator mbYGenerator = new SublistGenerator(_mbY.size(), _mbY.size());
+ /**
+ * Calculates the adjustment sets of a given graph G between two nodes x and y that are subsets of MB(Y).
+ *
+ * @param G the input graph
+ * @param x the source node
+ * @param y the target node
+ * @param numSmallestSizes the number of smallest adjustment sets to return
+ * @return the adjustment sets as a set of sets of nodes
+ * @throws IllegalArgumentException if the input graph is not a legal MPDAG
+ */
+ public static Set> adjustmentSets2(Graph G, Node x, Node y, int numSmallestSizes) {
+ if (!G.paths().isLegalMpdag()) {
+ throw new IllegalArgumentException("Graph must be a legal MPDAG.");
+ }
- while ((choice = mbYGenerator.next()) != null) {
- List sy = GraphUtils.asList(choice, _mbY);
- if (sy.contains(X)) {
- continue;
- }
+ Graph G2 = getGraphWithoutXToY(G, x, y);
- if (msep.isMSeparated(X, Y, new HashSet<>(sy))) {
- adjustmentSets.add(new HashSet<>(sy));
- }
- }
- }
+ // Get the Markov blanket for x in G2.
+ Set mbX = markovBlanket(y, G2);
- return adjustmentSets;
+ return getNMinimalSubsets(getGraphWithoutXToY(G, x, y), mbX, x, y, numSmallestSizes);
}
/**
* Returns a set of sets of nodes representing adjustment sets between nodes {@code x} and {@code y} in the graph
- * that are subsets of the anteriority for x and y with the numSmallestSizes smallest sizes. This is currently for an
- * MPDAG only.
- *
+ * that are subsets of the anteriority for x and y with the numSmallestSizes smallest sizes. This is currently for
+ * an MPDAG only.
+ *
* Precision: G is a legal MPDAG.
*
* @param x the starting node
@@ -2129,7 +2101,7 @@ public static Set> adjustmentSets1(Graph G, Node X, Node Y) {
* @param numSmallestSizes the number of the smallest sizes for the subsets to return
* @return a set of sets of nodes representing adjustment sets
*/
- public static Set> adjustmentSets2(Graph G, Node x, Node y, int numSmallestSizes) {
+ public static Set> adjustmentSets3(Graph G, Node x, Node y, int numSmallestSizes) {
if (!G.isAdjacentTo(x, y)) {
throw new IllegalArgumentException("Nodes must be adjacent in the graph.");
}
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/Paths.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/Paths.java
index cec60cff5d..ff4f9094cf 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/Paths.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/Paths.java
@@ -272,7 +272,9 @@ public boolean isLegalMpdag() {
// Check maximality...
if (equals) {
Graph __g = new EdgeListGraph(g);
- new MeekRules().orientImplied(__g);
+ MeekRules meekRules = new MeekRules();
+ meekRules.setRevertToUnshieldedColliders(false);
+ meekRules.orientImplied(__g);
return g.equals(__g);
}
@@ -2130,28 +2132,42 @@ public boolean possibleAncestor(Node node1, Node node2) {
}
/**
- * Returns a set of adjustment sets in the modified path-specific directed acyclic graph (mpDAG) between two nodes
- * that are subsets of MB(x) or MB(y).
+ * Returns a set of sets of nodes representing adjustment sets between nodes {@code x} and {@code y} in the graph
+ * that are subsets of MB(x) with the numSmallestSizes smallest sizes.
*
- * @param x the source node in the mpDAG
- * @param y the target node in the mpDAG
- * @return a set of adjustment sets in the mpDAG between the source and target nodes
+ * @param x the starting node
+ * @param y the ending node
+ * @param numSmallestSizes the number of smallest sizes for adjustment sets to return
+ * @return a set of sets of nodes representing adjustment sets
+ */
+ public Set> adjustmentSets1(Node x, Node y, int numSmallestSizes) {
+ return GraphUtils.adjustmentSets1(graph, x, y, numSmallestSizes);
+ }
+
+ /**
+ * Returns a set of sets of nodes representing adjustment sets between nodes {@code x} and {@code y} in the graph
+ * that are subsets of MB(y) x and y with the numSmallestSizes smallest sizes.
+ *
+ * @param x the starting node
+ * @param y the ending node
+ * @param numSmallestSizes the number of smallest sizes for adjustment sets to return
+ * @return a set of sets of nodes representing adjustment sets
*/
- public Set> adjustmentSets1(Node x, Node y) {
- return GraphUtils.adjustmentSets1(graph, x, y);
+ public Set> adjustmentSets2(Node x, Node y, int numSmallestSizes) {
+ return GraphUtils.adjustmentSets2(graph, x, y, numSmallestSizes);
}
/**
* Returns a set of sets of nodes representing adjustment sets between nodes {@code x} and {@code y} in the graph
- * that are subsets of the anteriority of x and y with the n smallest sizes.
+ * that are subsets of the anteriority for x and y with the numSmallestSizes smallest sizes.
*
- * @param x the starting node
- * @param y the ending node
- * @param n the number of smallest sizes for adjustment sets to return
+ * @param x the starting node
+ * @param y the ending node
+ * @param numSmallestSizes the number of smallest sizes for adjustment sets to return
* @return a set of sets of nodes representing adjustment sets
*/
- public Set> adjustmentSets2(Node x, Node y, int n) {
- return GraphUtils.adjustmentSets2(graph, x, y, n);
+ public Set> adjustmentSets3(Node x, Node y, int numSmallestSizes) {
+ return GraphUtils.adjustmentSets3(graph, x, y, numSmallestSizes);
}
/**
From 3d0289a90f27a682c166f54932c63a7e3b183226 Mon Sep 17 00:00:00 2001
From: jdramsey
Date: Tue, 16 Apr 2024 00:30:40 -0400
Subject: [PATCH 010/101] Replace 'cpdagForDag' method with 'dagToCpdag'
The method used for graph transformations, 'cpdagForDag', has been replaced with 'dagToCpdag' across multiple classes. This change is significant in the data models, graph comparison logic and search algorithms, contributing to improved graph-based computations in the system.
---
.../model/CPDAGFromDagGraphWrapper.java | 3 +-
.../model/EdgewiseComparisonModel.java | 2 +-
.../tetradapp/model/Misclassifications.java | 2 +-
.../model/PValueImproverWrapper.java | 2 +-
.../cmu/tetrad/algcomparison/Comparison.java | 6 +-
.../algcomparison/TimeoutComparison.java | 4 +-
.../algcomparison/algorithm/cluster/Bpc.java | 2 +-
.../algcomparison/algorithm/cluster/Fofc.java | 2 +-
.../algcomparison/algorithm/cluster/Ftfc.java | 2 +-
.../algorithm/multi/FgesConcatenated.java | 2 +-
.../algorithm/oracle/cpdag/Cpc.java | 2 +-
.../algorithm/oracle/cpdag/Fas.java | 2 +-
.../oracle/cpdag/FgesMeasurement.java | 2 +-
.../algorithm/oracle/cpdag/Pc.java | 2 +-
.../algorithm/oracle/cpdag/Pcd.java | 2 +-
.../DefiniteDirectedPathPrecision.java | 2 +-
.../statistic/DefiniteDirectedPathRecall.java | 2 +-
.../statistic/NoSemidirectedPrecision.java | 2 +-
.../statistic/NoSemidirectedRecall.java | 2 +-
.../statistic/NumDefinitelyDirected.java | 2 +-
.../NumDefinitelyNotDirectedPaths.java | 2 +-
.../statistic/NumPossiblyDirected.java | 2 +-
.../edu/cmu/tetrad/graph/GraphTransforms.java | 2 +-
.../java/edu/cmu/tetrad/graph/GraphUtils.java | 143 ++--
.../main/java/edu/cmu/tetrad/graph/Paths.java | 19 +-
.../java/edu/cmu/tetrad/search/SpFci.java | 2 +-
.../tetrad/search/utils/GraphSearchUtils.java | 4 +-
.../search/work_in_progress/HbsmsBeam.java | 2 +-
.../search/work_in_progress/HbsmsGes.java | 2 +-
.../tetrad/simulation/GdistanceRandom.java | 4 +-
.../tetrad/study/performance/Comparison.java | 6 +-
.../tetrad/study/performance/Comparison2.java | 12 +-
.../study/performance/PerformanceTests.java | 18 +-
.../edu/pitt/csb/mgm/ExploreIndepTests.java | 9 +-
.../tetrad/test/TestDagInPatternIterator.java | 4 +-
.../java/edu/cmu/tetrad/test/TestFges.java | 10 +-
.../java/edu/cmu/tetrad/test/TestGraph.java | 2 +-
.../edu/cmu/tetrad/test/TestGraphUtils.java | 619 ++++++++++--------
.../java/edu/cmu/tetrad/test/TestGrasp.java | 4 +-
.../test/java/edu/cmu/tetrad/test/TestPc.java | 2 +-
.../edu/cmu/tetrad/test/TestRubenData.java | 2 +-
41 files changed, 507 insertions(+), 410 deletions(-)
diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/CPDAGFromDagGraphWrapper.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/CPDAGFromDagGraphWrapper.java
index bc7e29c5d2..5b2ea14f14 100644
--- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/CPDAGFromDagGraphWrapper.java
+++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/CPDAGFromDagGraphWrapper.java
@@ -21,7 +21,6 @@
package edu.cmu.tetradapp.model;
-import edu.cmu.tetrad.graph.Dag;
import edu.cmu.tetrad.graph.EdgeListGraph;
import edu.cmu.tetrad.graph.Graph;
import edu.cmu.tetrad.graph.GraphTransforms;
@@ -85,7 +84,7 @@ public static CPDAGFromDagGraphWrapper serializableInstance() {
private static Graph getCpdag(Graph graph) {
- return GraphTransforms.cpdagForDag(graph);
+ return GraphTransforms.dagToCpdag(graph);
}
/**
diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/EdgewiseComparisonModel.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/EdgewiseComparisonModel.java
index b1931b998e..a10137cbd9 100644
--- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/EdgewiseComparisonModel.java
+++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/EdgewiseComparisonModel.java
@@ -126,7 +126,7 @@ public static Graph getComparisonGraph(Graph graph, Parameters params) {
return new EdgeListGraph(graph);
} else if ("CPDAG".equals(type)) {
params.set("graphComparisonType", "CPDAG");
- return GraphTransforms.cpdagForDag(graph);
+ return GraphTransforms.dagToCpdag(graph);
} else if ("PAG".equals(type)) {
params.set("graphComparisonType", "PAG");
return GraphTransforms.dagToPag(graph);
diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/Misclassifications.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/Misclassifications.java
index 7c17116aed..543801652f 100644
--- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/Misclassifications.java
+++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/Misclassifications.java
@@ -128,7 +128,7 @@ public static Graph getComparisonGraph(Graph graph, Parameters params) {
return new EdgeListGraph(graph);
} else if ("CPDAG".equals(type)) {
params.set("graphComparisonType", "CPDAG");
- return GraphTransforms.cpdagForDag(graph);
+ return GraphTransforms.dagToCpdag(graph);
} else if ("PAG".equals(type)) {
params.set("graphComparisonType", "PAG");
return GraphTransforms.dagToPag(graph);
diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/PValueImproverWrapper.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/PValueImproverWrapper.java
index 5e101e8960..d6914aab40 100644
--- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/PValueImproverWrapper.java
+++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/PValueImproverWrapper.java
@@ -379,7 +379,7 @@ public void execute() {
LayoutUtil.defaultLayout(this.graph);
}
- setResultGraph(GraphTransforms.cpdagForDag(this.graph));
+ setResultGraph(GraphTransforms.dagToCpdag(this.graph));
}
/**
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/Comparison.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/Comparison.java
index cbc9ede96a..be932d13c5 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/Comparison.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/Comparison.java
@@ -705,7 +705,7 @@ public void saveToFiles(String dataPath, Simulation simulation, Parameters param
if (isSaveCPDAGs()) {
File file3 = new File(dir3, "cpdag." + (j + 1) + ".txt");
- GraphSaveLoadUtils.saveGraph(GraphTransforms.cpdagForDag(graph), file3, false);
+ GraphSaveLoadUtils.saveGraph(GraphTransforms.dagToCpdag(graph), file3, false);
}
if (isSavePags()) {
@@ -806,7 +806,7 @@ public void saveToFilesSingleSimulation(String dataPath, Simulation simulation,
if (isSaveCPDAGs()) {
File file3 = new File(dir3, "cpdag." + (j + 1) + ".txt");
- GraphSaveLoadUtils.saveGraph(GraphTransforms.cpdagForDag(graph), file3, false);
+ GraphSaveLoadUtils.saveGraph(GraphTransforms.dagToCpdag(graph), file3, false);
}
if (isSavePags()) {
@@ -1398,7 +1398,7 @@ private void doRun(List algorithmSimulationWrappers,
if (this.comparisonGraph == ComparisonGraph.true_DAG) {
comparisonGraph = new EdgeListGraph(trueGraph);
} else if (this.comparisonGraph == ComparisonGraph.CPDAG_of_the_true_DAG) {
- comparisonGraph = GraphTransforms.cpdagForDag(trueGraph);
+ comparisonGraph = GraphTransforms.dagToCpdag(trueGraph);
} else if (this.comparisonGraph == ComparisonGraph.PAG_of_the_true_DAG) {
comparisonGraph = GraphTransforms.dagToPag(trueGraph);
} else {
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/TimeoutComparison.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/TimeoutComparison.java
index be34946638..dcfa186a5b 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/TimeoutComparison.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/TimeoutComparison.java
@@ -608,7 +608,7 @@ public void saveToFiles(String dataPath, Simulation simulation, Parameters param
if (isSaveCPDAGs()) {
File file3 = new File(dir3, "pattern." + (j + 1) + ".txt");
- GraphSaveLoadUtils.saveGraph(GraphTransforms.cpdagForDag(graph), file3, false);
+ GraphSaveLoadUtils.saveGraph(GraphTransforms.dagToCpdag(graph), file3, false);
}
if (isSavePags()) {
@@ -1277,7 +1277,7 @@ private void doRun(List algorithmSimulationWrappers,
comparisonGraph = new EdgeListGraph(trueGraph);
} else if (this.comparisonGraph == ComparisonGraph.CPDAG_of_the_true_DAG) {
Graph dag = new EdgeListGraph(trueGraph);
- comparisonGraph = GraphTransforms.cpdagForDag(dag);
+ comparisonGraph = GraphTransforms.dagToCpdag(dag);
} else if (this.comparisonGraph == ComparisonGraph.PAG_of_the_true_DAG) {
Graph trueGraph1 = new EdgeListGraph(trueGraph);
comparisonGraph = GraphTransforms.dagToPag(trueGraph1);
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/cluster/Bpc.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/cluster/Bpc.java
index 9d80408148..95f35b31dd 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/cluster/Bpc.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/cluster/Bpc.java
@@ -128,7 +128,7 @@ public Graph search(DataModel dataModel, Parameters parameters) {
@Override
public Graph getComparisonGraph(Graph graph) {
Graph dag = new EdgeListGraph(graph);
- return GraphTransforms.cpdagForDag(dag);
+ return GraphTransforms.dagToCpdag(dag);
}
/**
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/cluster/Fofc.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/cluster/Fofc.java
index e31ef06c0c..928cb77bd3 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/cluster/Fofc.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/cluster/Fofc.java
@@ -150,7 +150,7 @@ public Graph runSearch(DataModel dataModel, Parameters parameters) {
*/
@Override
public Graph getComparisonGraph(Graph graph) {
- return GraphTransforms.cpdagForDag(graph);
+ return GraphTransforms.dagToCpdag(graph);
}
/**
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/cluster/Ftfc.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/cluster/Ftfc.java
index 03771149a0..339049d9df 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/cluster/Ftfc.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/cluster/Ftfc.java
@@ -94,7 +94,7 @@ public Graph runSearch(DataModel dataSet, Parameters parameters) {
@Override
public Graph getComparisonGraph(Graph graph) {
Graph dag = new EdgeListGraph(graph);
- return GraphTransforms.cpdagForDag(dag);
+ return GraphTransforms.dagToCpdag(dag);
}
/**
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/multi/FgesConcatenated.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/multi/FgesConcatenated.java
index c22cc86216..4564470943 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/multi/FgesConcatenated.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/multi/FgesConcatenated.java
@@ -151,7 +151,7 @@ public Graph getComparisonGraph(Graph graph) {
return new EdgeListGraph(graph);
} else {
Graph dag = new EdgeListGraph(graph);
- return GraphTransforms.cpdagForDag(dag);
+ return GraphTransforms.dagToCpdag(dag);
}
}
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Cpc.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Cpc.java
index 0ba8a9c9c7..35bc0568fd 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Cpc.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Cpc.java
@@ -131,7 +131,7 @@ protected Graph runSearch(DataModel dataModel, Parameters parameters) {
@Override
public Graph getComparisonGraph(Graph graph) {
Graph dag = new EdgeListGraph(graph);
- return GraphTransforms.cpdagForDag(dag);
+ return GraphTransforms.dagToCpdag(dag);
}
/**
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Fas.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Fas.java
index 1b310ecd09..4046960bcc 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Fas.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Fas.java
@@ -103,7 +103,7 @@ protected Graph runSearch(DataModel dataModel, Parameters parameters) {
@Override
public Graph getComparisonGraph(Graph graph) {
Graph dag = new EdgeListGraph(graph);
- return GraphTransforms.cpdagForDag(dag);
+ return GraphTransforms.dagToCpdag(dag);
}
/**
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/FgesMeasurement.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/FgesMeasurement.java
index 2806c4841e..f5da8a961a 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/FgesMeasurement.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/FgesMeasurement.java
@@ -92,7 +92,7 @@ protected Graph runSearch(DataModel dataModel, Parameters parameters) {
@Override
public Graph getComparisonGraph(Graph graph) {
Graph dag = new EdgeListGraph(graph);
- return GraphTransforms.cpdagForDag(dag);
+ return GraphTransforms.dagToCpdag(dag);
}
/**
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Pc.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Pc.java
index 4e09157fab..dcf7573295 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Pc.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Pc.java
@@ -123,7 +123,7 @@ protected Graph runSearch(DataModel dataModel, Parameters parameters) {
@Override
public Graph getComparisonGraph(Graph graph) {
Graph dag = new EdgeListGraph(graph);
- return GraphTransforms.cpdagForDag(dag);
+ return GraphTransforms.dagToCpdag(dag);
}
/**
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Pcd.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Pcd.java
index 0f70156f79..c8111ec037 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Pcd.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Pcd.java
@@ -76,7 +76,7 @@ protected Graph runSearch(DataModel dataModel, Parameters parameters) {
*/
@Override
public Graph getComparisonGraph(Graph graph) {
- return GraphTransforms.cpdagForDag(graph);
+ return GraphTransforms.dagToCpdag(graph);
}
/**
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/DefiniteDirectedPathPrecision.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/DefiniteDirectedPathPrecision.java
index 48824b2afa..c26c1e24d8 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/DefiniteDirectedPathPrecision.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/DefiniteDirectedPathPrecision.java
@@ -46,7 +46,7 @@ public double getValue(Graph trueGraph, Graph estGraph, DataModel dataModel) {
int tp = 0, fp = 0;
List nodes = trueGraph.getNodes();
- Graph cpdag = GraphTransforms.cpdagForDag(trueGraph);
+ Graph cpdag = GraphTransforms.dagToCpdag(trueGraph);
GraphUtils.addPagColoring(estGraph);
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/DefiniteDirectedPathRecall.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/DefiniteDirectedPathRecall.java
index 4d2ea8389e..646ee208b3 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/DefiniteDirectedPathRecall.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/DefiniteDirectedPathRecall.java
@@ -49,7 +49,7 @@ public double getValue(Graph trueGraph, Graph estGraph, DataModel dataModel) {
int tp = 0, fn = 0;
List nodes = trueGraph.getNodes();
- Graph cpdag = GraphTransforms.cpdagForDag(trueGraph);
+ Graph cpdag = GraphTransforms.dagToCpdag(trueGraph);
for (Node x : nodes) {
for (Node y : nodes) {
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/NoSemidirectedPrecision.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/NoSemidirectedPrecision.java
index 4a386e816b..842e15491a 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/NoSemidirectedPrecision.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/NoSemidirectedPrecision.java
@@ -48,7 +48,7 @@ public String getDescription() {
public double getValue(Graph trueGraph, Graph estGraph, DataModel dataModel) {
int tp = 0, fp = 0;
- Graph cpdag = GraphTransforms.cpdagForDag(trueGraph);
+ Graph cpdag = GraphTransforms.dagToCpdag(trueGraph);
List nodes = estGraph.getNodes();
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/NoSemidirectedRecall.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/NoSemidirectedRecall.java
index 5bd95ceaf0..0a60abea55 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/NoSemidirectedRecall.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/NoSemidirectedRecall.java
@@ -48,7 +48,7 @@ public String getDescription() {
public double getValue(Graph trueGraph, Graph estGraph, DataModel dataModel) {
int tp = 0, fn = 0;
- Graph cpdag = GraphTransforms.cpdagForDag(trueGraph);
+ Graph cpdag = GraphTransforms.dagToCpdag(trueGraph);
List nodes = trueGraph.getNodes();
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/NumDefinitelyDirected.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/NumDefinitelyDirected.java
index 6c6650e20a..4115d94f3d 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/NumDefinitelyDirected.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/NumDefinitelyDirected.java
@@ -45,7 +45,7 @@ public String getDescription() {
public double getValue(Graph trueGraph, Graph estGraph, DataModel dataModel) {
int count = 0;
- Graph cpdag = GraphTransforms.cpdagForDag(trueGraph);
+ Graph cpdag = GraphTransforms.dagToCpdag(trueGraph);
for (Edge edge : estGraph.getEdges()) {
if (Edges.isDirectedEdge(edge)) {
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/NumDefinitelyNotDirectedPaths.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/NumDefinitelyNotDirectedPaths.java
index 276d1c8fb6..053c97ebfa 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/NumDefinitelyNotDirectedPaths.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/NumDefinitelyNotDirectedPaths.java
@@ -45,7 +45,7 @@ public String getDescription() {
public double getValue(Graph trueGraph, Graph estGraph, DataModel dataModel) {
int count = 0;
- Graph cpdag = GraphTransforms.cpdagForDag(trueGraph);
+ Graph cpdag = GraphTransforms.dagToCpdag(trueGraph);
for (Edge edge : estGraph.getEdges()) {
if (Edges.isDirectedEdge(edge)) {
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/NumPossiblyDirected.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/NumPossiblyDirected.java
index 84159ae886..832c9767dc 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/NumPossiblyDirected.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/NumPossiblyDirected.java
@@ -45,7 +45,7 @@ public String getDescription() {
public double getValue(Graph trueGraph, Graph estGraph, DataModel dataModel) {
int count = 0;
- Graph cpdag = GraphTransforms.cpdagForDag(trueGraph);
+ Graph cpdag = GraphTransforms.dagToCpdag(trueGraph);
for (Edge edge : estGraph.getEdges()) {
if (Edges.isDirectedEdge(edge)) {
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/GraphTransforms.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/GraphTransforms.java
index 52f1e7871d..73ef541557 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/GraphTransforms.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/GraphTransforms.java
@@ -245,7 +245,7 @@ public static List getAllGraphsByDirectingUndirectedEdges(Graph skeleton)
* @param dag The input DAG.
* @return The CPDAG resulting from applying Meek Rules to the input DAG.
*/
- public static Graph cpdagForDag(Graph dag) {
+ public static Graph dagToCpdag(Graph dag) {
Graph cpdag = new EdgeListGraph(dag);
MeekRules rules = new MeekRules();
rules.setRevertToUnshieldedColliders(true);
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/GraphUtils.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/GraphUtils.java
index 6878a26f54..c8985f5bf2 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/GraphUtils.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/GraphUtils.java
@@ -23,15 +23,11 @@
import edu.cmu.tetrad.data.Knowledge;
import edu.cmu.tetrad.data.KnowledgeEdge;
import edu.cmu.tetrad.graph.Edge.Property;
-import edu.cmu.tetrad.search.utils.FciOrient;
-import edu.cmu.tetrad.search.utils.GraphSearchUtils;
-import edu.cmu.tetrad.search.utils.MeekRules;
-import edu.cmu.tetrad.search.utils.SepsetProducer;
+import edu.cmu.tetrad.search.utils.*;
import edu.cmu.tetrad.util.ChoiceGenerator;
import edu.cmu.tetrad.util.Parameters;
import edu.cmu.tetrad.util.SublistGenerator;
import edu.cmu.tetrad.util.TextTable;
-import org.jetbrains.annotations.NotNull;
import java.text.DecimalFormat;
import java.text.NumberFormat;
@@ -631,15 +627,6 @@ public static List getAmbiguousTriplesFromGraph(Node node, Graph graph)
return ambiguousTriples;
}
- /**
- * getUnderlinedTriplesFromGraph.
- *
- * @param node a {@link edu.cmu.tetrad.graph.Node} object
- * @param graph a {@link edu.cmu.tetrad.graph.Graph} object
- * @return A list of triples of the form <X, Y, Z>, where <X, Y, Z> is a definite noncollider in the
- * given graph.
- */
-
/**
* Retrieves the underlined triples from the given graph that involve the specified node. These are triples that
* represent definite noncolliders in the given graph.
@@ -673,7 +660,7 @@ public static List getUnderlinedTriplesFromGraph(Node node, Graph graph)
}
/**
- * getDottedUnderlinedTriplesFromGraph.
+ * getUnderlinedTriplesFromGraph.
*
* @param node a {@link edu.cmu.tetrad.graph.Node} object
* @param graph a {@link edu.cmu.tetrad.graph.Graph} object
@@ -713,6 +700,15 @@ public static List getDottedUnderlinedTriplesFromGraph(Node node, Graph
return dottedUnderlinedTriples;
}
+ /**
+ * getDottedUnderlinedTriplesFromGraph.
+ *
+ * @param node a {@link edu.cmu.tetrad.graph.Node} object
+ * @param graph a {@link edu.cmu.tetrad.graph.Graph} object
+ * @return A list of triples of the form <X, Y, Z>, where <X, Y, Z> is a definite noncollider in the
+ * given graph.
+ */
+
/**
* Checks if a given graph contains a bidirected edge.
*
@@ -731,7 +727,6 @@ public static boolean containsBidirectedEdge(Graph graph) {
return containsBidirected;
}
-
/**
* Generates a list of triples where a node acts as a collider in a given graph.
*
@@ -1782,8 +1777,6 @@ public static int getIndegree(Graph graph) {
return max;
}
- // Used to find semidirected paths for cycle checking.
-
/**
* Traverses a semi-directed edge to identify the next node in the traversal.
*
@@ -1804,6 +1797,8 @@ public static Node traverseSemiDirected(Node node, Edge edge) {
return null;
}
+ // Used to find semidirected paths for cycle checking.
+
/**
* Returns a comparison graph based on the specified parameters.
*
@@ -1819,7 +1814,7 @@ public static Graph getComparisonGraph(Graph graph, Parameters params) {
return new EdgeListGraph(graph);
} else if ("CPDAG".equals(type)) {
params.set("graphComparisonType", "CPDAG");
- return GraphTransforms.cpdagForDag(graph);
+ return GraphTransforms.dagToCpdag(graph);
} else if ("PAG".equals(type)) {
params.set("graphComparisonType", "PAG");
return GraphTransforms.dagToPag(graph);
@@ -2046,47 +2041,49 @@ public static Set district(Node x, Graph G) {
/**
* Calculates the adjustment sets of a given graph G between two nodes x and y that are subsets of MB(X).
*
- * @param G the input graph
- * @param x the source node
- * @param y the target node
+ * @param G the input graph
+ * @param x the source node
+ * @param y the target node
* @param numSmallestSizes the number of smallest adjustment sets to return
* @return the adjustment sets as a set of sets of nodes
* @throws IllegalArgumentException if the input graph is not a legal MPDAG
*/
- public static Set> adjustmentSets1(Graph G, Node x, Node y, int numSmallestSizes) {
- if (!G.paths().isLegalMpdag()) {
- throw new IllegalArgumentException("Graph must be a legal MPDAG.");
- }
+ public static Set> adjustmentSets1(Graph G, Node x, Node y, int numSmallestSizes, GraphType graphType) {
+ Graph G2 = getGraphWithoutXToY(G, x, y, graphType);
- Graph G2 = getGraphWithoutXToY(G, x, y);
+ if (G2 == null) {
+ return new HashSet<>();
+ }
// Get the Markov blanket for x in G2.
Set mbX = markovBlanket(x, G2);
-
- return getNMinimalSubsets(getGraphWithoutXToY(G, x, y), mbX, x, y, numSmallestSizes);
+ mbX.remove(x);
+ mbX.remove(y);
+ return getNMinimalSubsets(getGraphWithoutXToY(G, x, y, graphType), mbX, x, y, numSmallestSizes);
}
/**
* Calculates the adjustment sets of a given graph G between two nodes x and y that are subsets of MB(Y).
*
- * @param G the input graph
- * @param x the source node
- * @param y the target node
+ * @param G the input graph
+ * @param x the source node
+ * @param y the target node
* @param numSmallestSizes the number of smallest adjustment sets to return
* @return the adjustment sets as a set of sets of nodes
* @throws IllegalArgumentException if the input graph is not a legal MPDAG
*/
- public static Set> adjustmentSets2(Graph G, Node x, Node y, int numSmallestSizes) {
- if (!G.paths().isLegalMpdag()) {
- throw new IllegalArgumentException("Graph must be a legal MPDAG.");
- }
+ public static Set> adjustmentSets2(Graph G, Node x, Node y, int numSmallestSizes, GraphType graphType) {
+ Graph G2 = getGraphWithoutXToY(G, x, y, graphType);
- Graph G2 = getGraphWithoutXToY(G, x, y);
+ if (G2 == null) {
+ return new HashSet<>();
+ }
// Get the Markov blanket for x in G2.
Set mbX = markovBlanket(y, G2);
-
- return getNMinimalSubsets(getGraphWithoutXToY(G, x, y), mbX, x, y, numSmallestSizes);
+ mbX.remove(x);
+ mbX.remove(y);
+ return getNMinimalSubsets(getGraphWithoutXToY(G, x, y, graphType), mbX, x, y, numSmallestSizes);
}
/**
@@ -2101,22 +2098,36 @@ public static Set> adjustmentSets2(Graph G, Node x, Node y, int numSma
* @param numSmallestSizes the number of the smallest sizes for the subsets to return
* @return a set of sets of nodes representing adjustment sets
*/
- public static Set> adjustmentSets3(Graph G, Node x, Node y, int numSmallestSizes) {
- if (!G.isAdjacentTo(x, y)) {
- throw new IllegalArgumentException("Nodes must be adjacent in the graph.");
- }
+ public static Set> adjustmentSets3(Graph G, Node x, Node y, int numSmallestSizes, GraphType graphType) {
+ Graph G2 = getGraphWithoutXToY(G, x, y, graphType);
- if (G.getEdge(x, y).pointsTowards(x)) {
- throw new IllegalArgumentException("Edge must not point toward x.");
+ if (G2 == null) {
+ return new HashSet<>();
}
Set anteriority = G.paths().anteriority(x, y);
- return getNMinimalSubsets(getGraphWithoutXToY(G, x, y), anteriority, x, y, numSmallestSizes);
+ anteriority.remove(x);
+ anteriority.remove(y);
+ return getNMinimalSubsets(getGraphWithoutXToY(G, x, y, graphType), anteriority, x, y, numSmallestSizes);
}
- private static @NotNull Graph getGraphWithoutXToY(Graph G, Node x, Node y) {
+ public static Graph getGraphWithoutXToY(Graph G, Node x, Node y, GraphType graphType) {
+ if (graphType == GraphType.CPDAG) {
+ return getGraphWithoutXToYMpdag(G, x, y);
+ } else if (graphType == GraphType.PAG) {
+ return getGraphWithoutXToYPag(G, x, y);
+ } else {
+ throw new IllegalArgumentException("Graph must be a legal MPDAG, PAG, or MAG.");
+ }
+ }
+
+ private static Graph getGraphWithoutXToYMpdag(Graph G, Node x, Node y) {
Graph G2 = new EdgeListGraph(G);
+ if (!G2.isAdjacentTo(x, y)) {
+ return null;
+ }
+
if (Edges.isUndirectedEdge(G2.getEdge(x, y))) {
Knowledge knowledge = new Knowledge();
knowledge.setRequired(x.getName(), y.getName());
@@ -2131,6 +2142,40 @@ public static Set