public static boolean meekR1Locally2( Graph graph, Knowledge knowledge, IndependenceTest test, int depth) { List<Node> nodes = graph.getNodes(); boolean changed = true; while (changed) { changed = false; for (Node a : nodes) { List<Node> adjacentNodes = graph.getAdjacentNodes(a); if (adjacentNodes.size() < 2) { continue; } ChoiceGenerator cg = new ChoiceGenerator(adjacentNodes.size(), 2); int[] combination; while ((combination = cg.next()) != null) { Node b = adjacentNodes.get(combination[0]); Node c = adjacentNodes.get(combination[1]); // Skip triples that are shielded. if (graph.isAdjacentTo(b, c)) { continue; } if (graph.getEndpoint(b, a) == Endpoint.ARROW && graph.isUndirectedFromTo(a, c)) { if (existsLocalSepsetWithoutDet(b, a, c, test, graph, depth)) { continue; } if (isArrowpointAllowed(a, c, knowledge)) { graph.setEndpoint(a, c, Endpoint.ARROW); TetradLogger.getInstance() .edgeOriented(SearchLogUtils.edgeOrientedMsg("Meek R1", graph.getEdge(a, c))); changed = true; } } else if (graph.getEndpoint(c, a) == Endpoint.ARROW && graph.isUndirectedFromTo(a, b)) { if (existsLocalSepsetWithoutDet(b, a, c, test, graph, depth)) { continue; } if (isArrowpointAllowed(a, b, knowledge)) { graph.setEndpoint(a, b, Endpoint.ARROW); TetradLogger.getInstance() .edgeOriented(SearchLogUtils.edgeOrientedMsg("Meek R1", graph.getEdge(a, b))); changed = true; } } } } } return changed; }
/** Orients according to background knowledge */ private void fciOrientbk(IKnowledge bk, Graph graph, List<Node> variables) { logger.log("info", "Starting BK Orientation."); for (Iterator<KnowledgeEdge> it = bk.forbiddenEdgesIterator(); it.hasNext(); ) { KnowledgeEdge edge = it.next(); // match strings to variables in the graph. Node from = SearchGraphUtils.translate(edge.getFrom(), variables); Node to = SearchGraphUtils.translate(edge.getTo(), variables); if (from == null || to == null) { continue; } if (graph.getEdge(from, to) == null) { continue; } // Orient to*->from graph.setEndpoint(to, from, Endpoint.ARROW); graph.setEndpoint(from, to, Endpoint.CIRCLE); changeFlag = true; logger.log( "knowledgeOrientation", SearchLogUtils.edgeOrientedMsg("Knowledge", graph.getEdge(from, to))); } for (Iterator<KnowledgeEdge> it = bk.requiredEdgesIterator(); it.hasNext(); ) { KnowledgeEdge edge = it.next(); // match strings to variables in this graph Node from = SearchGraphUtils.translate(edge.getFrom(), variables); Node to = SearchGraphUtils.translate(edge.getTo(), variables); if (from == null || to == null) { continue; } if (graph.getEdge(from, to) == null) { continue; } graph.setEndpoint(to, from, Endpoint.TAIL); graph.setEndpoint(from, to, Endpoint.ARROW); changeFlag = true; logger.log( "knowledgeOrientation", SearchLogUtils.edgeOrientedMsg("Knowledge", graph.getEdge(from, to))); } logger.log("info", "Finishing BK Orientation."); }
/** Orients according to background knowledge. */ public static void pcOrientbk(Knowledge bk, Graph graph, List<Node> nodes) { TetradLogger.getInstance().log("info", "Staring BK Orientation."); for (Iterator<KnowledgeEdge> it = bk.forbiddenEdgesIterator(); it.hasNext(); ) { KnowledgeEdge edge = it.next(); // match strings to variables in the graph. Node from = translate(edge.getFrom(), nodes); Node to = translate(edge.getTo(), nodes); if (from == null || to == null) { continue; } if (graph.getEdge(from, to) == null) { continue; } // Orient to-->from graph.removeEdge(from, to); graph.addDirectedEdge(from, to); graph.setEndpoint(from, to, Endpoint.TAIL); graph.setEndpoint(to, from, Endpoint.ARROW); TetradLogger.getInstance() .edgeOriented(SearchLogUtils.edgeOrientedMsg("Knowledge", graph.getEdge(to, from))); } for (Iterator<KnowledgeEdge> it = bk.requiredEdgesIterator(); it.hasNext(); ) { KnowledgeEdge edge = it.next(); // match strings to variables in this graph Node from = translate(edge.getFrom(), nodes); Node to = translate(edge.getTo(), nodes); if (from == null || to == null) { continue; } if (graph.getEdge(from, to) == null) { continue; } // Orient from-->to graph.setEndpoint(to, from, Endpoint.TAIL); graph.setEndpoint(from, to, Endpoint.ARROW); TetradLogger.getInstance() .edgeOriented(SearchLogUtils.edgeOrientedMsg("Knowledge", graph.getEdge(from, to))); } TetradLogger.getInstance().log("info", "Finishing BK Orientation."); }
/** * Performs step C of the algorithm, as indicated on page xxx of CPS, with the modification that * X--W--Y is oriented as X-->W<--Y if W is *determined by* the sepset of (X, Y), rather than W * just being *in* the sepset of (X, Y). */ public static void pcdOrientC( SepsetMap set, IndependenceTest test, Knowledge knowledge, Graph graph) { TetradLogger.getInstance().log("info", "Staring Collider Orientation:"); List<Node> nodes = graph.getNodes(); for (Node y : nodes) { List<Node> adjacentNodes = graph.getAdjacentNodes(y); if (adjacentNodes.size() < 2) { continue; } ChoiceGenerator cg = new ChoiceGenerator(adjacentNodes.size(), 2); int[] combination; while ((combination = cg.next()) != null) { Node x = adjacentNodes.get(combination[0]); Node z = adjacentNodes.get(combination[1]); // Skip triples that are shielded. if (graph.isAdjacentTo(x, z)) { continue; } List<Node> sepset = set.get(x, z); if (sepset == null) { continue; } List<Node> augmentedSet = new LinkedList<Node>(sepset); augmentedSet.add(y); if (test.determines(sepset, y)) { continue; } // if (!test.splitDetermines(sepset, x, z) && test.splitDetermines(augmentedSet, x, z)) { continue; } if (!isArrowpointAllowed(x, y, knowledge) || !isArrowpointAllowed(z, y, knowledge)) { continue; } graph.setEndpoint(x, y, Endpoint.ARROW); graph.setEndpoint(z, y, Endpoint.ARROW); TetradLogger.getInstance() .log("colliderOriented", SearchLogUtils.colliderOrientedMsg(x, y, z)); } } TetradLogger.getInstance().log("info", "Finishing Collider Orientation."); }
private void calcStats() { // Graph resultGraph = getAlgorithmRunner().getResultGraph(); IGesRunner runner = (IGesRunner) getAlgorithmRunner(); if (runner.getTopGraphs().isEmpty()) { throw new IllegalArgumentException( "No patterns were recorded. Please adjust the number of " + "patterns to store."); } Graph resultGraph = runner.getTopGraphs().get(runner.getIndex()).getGraph(); if (getAlgorithmRunner().getDataModel() instanceof DataSet) { // resultGraph may be the output of a PC search. // Such graphs sometimes contain doubly directed edges. // /We converte such edges to directed edges here. // For the time being an orientation is arbitrarily selected. Set<Edge> allEdges = resultGraph.getEdges(); for (Edge edge : allEdges) { if (edge.getEndpoint1() == Endpoint.ARROW && edge.getEndpoint2() == Endpoint.ARROW) { // Option 1 orient it from node1 to node2 resultGraph.setEndpoint(edge.getNode1(), edge.getNode2(), Endpoint.ARROW); // Option 2 remove such edges: resultGraph.removeEdge(edge); } } Pattern pattern = new Pattern(resultGraph); PatternToDag ptd = new PatternToDag(pattern); Graph dag = ptd.patternToDagMeekRules(); DataSet dataSet = (DataSet) getAlgorithmRunner().getDataModel(); String report; if (dataSet.isContinuous()) { report = reportIfContinuous(dag, dataSet); } else if (dataSet.isDiscrete()) { report = reportIfDiscrete(dag, dataSet); } else { throw new IllegalArgumentException(""); } JScrollPane dagWorkbenchScroll = dagWorkbenchScroll(dag); modelStatsText.setLineWrap(true); modelStatsText.setWrapStyleWord(true); modelStatsText.setText(report); removeStatsTabs(); tabbedPane.addTab("DAG in pattern", dagWorkbenchScroll); tabbedPane.addTab("DAG Model Statistics", modelStatsText); } }
/** Meek's rule R3. If a--b, a--c, a--d, c-->b, c-->b, then orient a-->b. */ public static boolean meekR3(Graph graph, Knowledge knowledge) { List<Node> nodes = graph.getNodes(); boolean changed = false; for (Node a : nodes) { List<Node> adjacentNodes = graph.getAdjacentNodes(a); if (adjacentNodes.size() < 3) { continue; } for (Node b : adjacentNodes) { List<Node> otherAdjacents = new LinkedList<Node>(adjacentNodes); otherAdjacents.remove(b); if (!graph.isUndirectedFromTo(a, b)) { continue; } ChoiceGenerator cg = new ChoiceGenerator(otherAdjacents.size(), 2); int[] combination; while ((combination = cg.next()) != null) { Node c = otherAdjacents.get(combination[0]); Node d = otherAdjacents.get(combination[1]); if (graph.isAdjacentTo(c, d)) { continue; } if (!graph.isUndirectedFromTo(a, c)) { continue; } if (!graph.isUndirectedFromTo(a, d)) { continue; } if (graph.isDirectedFromTo(c, b) && graph.isDirectedFromTo(d, b)) { if (isArrowpointAllowed(a, b, knowledge)) { graph.setEndpoint(a, b, Endpoint.ARROW); TetradLogger.getInstance() .edgeOriented(SearchLogUtils.edgeOrientedMsg("Meek R3", graph.getEdge(a, b))); changed = true; break; } } } } } return changed; }
/** If */ public static boolean meekR2(Graph graph, Knowledge knowledge) { List<Node> nodes = graph.getNodes(); boolean changed = false; for (Node a : nodes) { List<Node> adjacentNodes = graph.getAdjacentNodes(a); if (adjacentNodes.size() < 2) { continue; } ChoiceGenerator cg = new ChoiceGenerator(adjacentNodes.size(), 2); int[] combination; while ((combination = cg.next()) != null) { Node b = adjacentNodes.get(combination[0]); Node c = adjacentNodes.get(combination[1]); if (graph.isDirectedFromTo(b, a) && graph.isDirectedFromTo(a, c) && graph.isUndirectedFromTo(b, c)) { if (isArrowpointAllowed(b, c, knowledge)) { graph.setEndpoint(b, c, Endpoint.ARROW); TetradLogger.getInstance() .edgeOriented(SearchLogUtils.edgeOrientedMsg("Meek R2", graph.getEdge(b, c))); } } else if (graph.isDirectedFromTo(c, a) && graph.isDirectedFromTo(a, b) && graph.isUndirectedFromTo(c, b)) { if (isArrowpointAllowed(c, b, knowledge)) { graph.setEndpoint(c, b, Endpoint.ARROW); TetradLogger.getInstance() .edgeOriented(SearchLogUtils.edgeOrientedMsg("Meek R2", graph.getEdge(c, b))); } } } } return changed; }
private void addColliders( Graph graph, final SepsetProducer sepsetProducer, IKnowledge knowledge) { final Map<Triple, Double> collidersPs = findCollidersUsingSepsets(sepsetProducer, graph, verbose, knowledge); List<Triple> colliders = new ArrayList<>(collidersPs.keySet()); Collections.shuffle(colliders); Collections.sort( colliders, new Comparator<Triple>() { public int compare(Triple o1, Triple o2) { return -Double.compare(collidersPs.get(o1), collidersPs.get(o2)); } }); if (trueDag != null) { for (Triple collider : colliders) { Node a = collider.getX(); Node b = collider.getY(); Node c = collider.getZ(); List<Node> sep = trueDag.getSepset(a, c); System.out.println( "JJJ " + collider + " collider = " + (sep != null && !sep.contains(b)) + " p = " + collidersPs.get(collider)); } } for (Triple collider : colliders) { Node a = collider.getX(); Node b = collider.getY(); Node c = collider.getZ(); if (!(isArrowpointAllowed(a, b, knowledge) && isArrowpointAllowed(c, b, knowledge))) { continue; } if (!graph.getEdge(a, b).pointsTowards(a) && !graph.getEdge(b, c).pointsTowards(c)) { graph.setEndpoint(a, b, Endpoint.ARROW); graph.setEndpoint(c, b, Endpoint.ARROW); } } }
/** * Step C of PC; orients colliders using specified sepset. That is, orients x *-* y *-* z as x *-> * y <-* z just in case y is in Sepset({x, z}). */ public static void orientCollidersUsingSepsets(SepsetMap set, Knowledge knowledge, Graph graph) { TetradLogger.getInstance().log("info", "Starting Collider Orientation:"); // verifySepsetIntegrity(set, graph); List<Node> nodes = graph.getNodes(); for (Node a : nodes) { List<Node> adjacentNodes = graph.getAdjacentNodes(a); if (adjacentNodes.size() < 2) { continue; } ChoiceGenerator cg = new ChoiceGenerator(adjacentNodes.size(), 2); int[] combination; while ((combination = cg.next()) != null) { Node b = adjacentNodes.get(combination[0]); Node c = adjacentNodes.get(combination[1]); // Skip triples that are shielded. if (graph.isAdjacentTo(b, c)) { continue; } List<Node> sepset = set.get(b, c); if (sepset != null && !sepset.contains(a) && isArrowpointAllowed(b, a, knowledge) && isArrowpointAllowed(c, a, knowledge)) { graph.setEndpoint(b, a, Endpoint.ARROW); graph.setEndpoint(c, a, Endpoint.ARROW); TetradLogger.getInstance() .log("colliderOriented", SearchLogUtils.colliderOrientedMsg(b, a, c, sepset)); } } } TetradLogger.getInstance().log("info", "Finishing Collider Orientation."); }
public static void orientCollidersLocally( Knowledge knowledge, Graph graph, IndependenceTest test, int depth, Set<Node> nodesToVisit) { TetradLogger.getInstance().log("info", "Starting Collider Orientation:"); if (nodesToVisit == null) { nodesToVisit = new HashSet<Node>(graph.getNodes()); } for (Node a : nodesToVisit) { List<Node> adjacentNodes = graph.getAdjacentNodes(a); if (adjacentNodes.size() < 2) { continue; } ChoiceGenerator cg = new ChoiceGenerator(adjacentNodes.size(), 2); int[] combination; while ((combination = cg.next()) != null) { Node b = adjacentNodes.get(combination[0]); Node c = adjacentNodes.get(combination[1]); // Skip triples that are shielded. if (graph.isAdjacentTo(b, c)) { continue; } if (isArrowpointAllowed1(b, a, knowledge) && isArrowpointAllowed1(c, a, knowledge)) { if (!existsLocalSepsetWith(b, a, c, test, graph, depth)) { graph.setEndpoint(b, a, Endpoint.ARROW); graph.setEndpoint(c, a, Endpoint.ARROW); TetradLogger.getInstance() .log("colliderOriented", SearchLogUtils.colliderOrientedMsg(b, a, c)); } } } } TetradLogger.getInstance().log("info", "Finishing Collider Orientation."); }
/** * Transforms a DAG represented in graph <code>graph</code> into a maximally directed pattern * (PDAG) by modifying <code>g</code> itself. Based on the algorithm described in Chickering * (2002) "Optimal structure identification with greedy search" Journal of Machine Learning * Research. It works for both BayesNets and SEMs. R. Silva, June 2004 */ public static void dagToPdag(Graph graph) { // do topological sort on the nodes Graph graphCopy = new EdgeListGraph(graph); Node orderedNodes[] = new Node[graphCopy.getNodes().size()]; int count = 0; while (graphCopy.getNodes().size() > 0) { Set<Node> exogenousNodes = new HashSet<Node>(); for (Node next : graphCopy.getNodes()) { if (graphCopy.isExogenous(next)) { exogenousNodes.add(next); orderedNodes[count++] = graph.getNode(next.getName()); } } graphCopy.removeNodes(new ArrayList<Node>(exogenousNodes)); } // ordered edges - improvised, inefficient implementation count = 0; Edge edges[] = new Edge[graph.getNumEdges()]; boolean edgeOrdered[] = new boolean[graph.getNumEdges()]; Edge orderedEdges[] = new Edge[graph.getNumEdges()]; for (Edge edge : graph.getEdges()) { edges[count++] = edge; } for (int i = 0; i < edges.length; i++) { edgeOrdered[i] = false; } while (count > 0) { for (Node orderedNode : orderedNodes) { for (int k = orderedNodes.length - 1; k >= 0; k--) { for (int q = 0; q < edges.length; q++) { if (!edgeOrdered[q] && edges[q].getNode1() == orderedNodes[k] && edges[q].getNode2() == orderedNode) { edgeOrdered[q] = true; orderedEdges[orderedEdges.length - count] = edges[q]; count--; } } } } } // label edges boolean compelledEdges[] = new boolean[graph.getNumEdges()]; boolean reversibleEdges[] = new boolean[graph.getNumEdges()]; for (int i = 0; i < graph.getNumEdges(); i++) { compelledEdges[i] = false; reversibleEdges[i] = false; } for (int i = 0; i < graph.getNumEdges(); i++) { if (compelledEdges[i] || reversibleEdges[i]) { continue; } Node x = orderedEdges[i].getNode1(); Node y = orderedEdges[i].getNode2(); for (int j = 0; j < orderedEdges.length; j++) { if (orderedEdges[j].getNode2() == x && compelledEdges[j]) { Node w = orderedEdges[j].getNode1(); if (!graph.isParentOf(w, y)) { for (int k = 0; k < orderedEdges.length; k++) { if (orderedEdges[k].getNode2() == y) { compelledEdges[k] = true; break; } } } else { for (int k = 0; k < orderedEdges.length; k++) { if (orderedEdges[k].getNode1() == w && orderedEdges[k].getNode2() == y) { compelledEdges[k] = true; break; } } } } if (compelledEdges[i]) { break; } } if (compelledEdges[i]) { continue; } boolean foundZ = false; for (Edge orderedEdge : orderedEdges) { Node z = orderedEdge.getNode1(); if (z != x && orderedEdge.getNode2() == y && !graph.isParentOf(z, x)) { compelledEdges[i] = true; for (int k = i + 1; k < graph.getNumEdges(); k++) { if (orderedEdges[k].getNode2() == y && !reversibleEdges[k]) { compelledEdges[k] = true; } } foundZ = true; break; } } if (!foundZ) { reversibleEdges[i] = true; for (int j = i + 1; j < orderedEdges.length; j++) { if (!compelledEdges[j] && orderedEdges[j].getNode2() == y) { reversibleEdges[j] = true; } } } } // undirect edges that are reversible for (int i = 0; i < reversibleEdges.length; i++) { if (reversibleEdges[i]) { graph.setEndpoint(orderedEdges[i].getNode1(), orderedEdges[i].getNode2(), Endpoint.TAIL); graph.setEndpoint(orderedEdges[i].getNode2(), orderedEdges[i].getNode1(), Endpoint.TAIL); } } }
//////////////////////////////////////////// // RFCI Algorithm 4.4 (Colombo et al, 2012) // Orient colliders //////////////////////////////////////////// private void ruleR0_RFCI(List<Node[]> rTuples) { List<Node[]> lTuples = new ArrayList<Node[]>(); List<Node> nodes = graph.getNodes(); /////////////////////////////// // process tuples in rTuples while (!rTuples.isEmpty()) { Node[] thisTuple = rTuples.remove(0); Node i = thisTuple[0]; Node j = thisTuple[1]; Node k = thisTuple[2]; final List<Node> nodes1 = getSepset(i, k); if (nodes1 == null) continue; List<Node> sepSet = new ArrayList<Node>(nodes1); sepSet.remove(j); boolean independent1 = false; if (knowledge.noEdgeRequired(i.getName(), j.getName())) // if BK allows { try { independent1 = independenceTest.isIndependent(i, j, sepSet); } catch (Exception e) { independent1 = true; } } boolean independent2 = false; if (knowledge.noEdgeRequired(j.getName(), k.getName())) // if BK allows { try { independent2 = independenceTest.isIndependent(j, k, sepSet); } catch (Exception e) { independent2 = true; } } if (!independent1 && !independent2) { lTuples.add(thisTuple); } else { // set sepSets to minimal separating sets if (independent1) { setMinSepSet(sepSet, i, j); graph.removeEdge(i, j); } if (independent2) { setMinSepSet(sepSet, j, k); graph.removeEdge(j, k); } // add new unshielded tuples to rTuples for (Node thisNode : nodes) { List<Node> adjacentNodes = graph.getAdjacentNodes(thisNode); if (independent1) // <i, ., j> { if (adjacentNodes.contains(i) && adjacentNodes.contains(j)) { Node[] newTuple = {i, thisNode, j}; rTuples.add(newTuple); } } if (independent2) // <j, ., k> { if (adjacentNodes.contains(j) && adjacentNodes.contains(k)) { Node[] newTuple = {j, thisNode, k}; rTuples.add(newTuple); } } } // remove tuples involving either (if independent1) <i, j> // or (if independent2) <j, k> from rTuples Iterator<Node[]> iter = rTuples.iterator(); while (iter.hasNext()) { Node[] curTuple = iter.next(); if ((independent1 && (curTuple[1] == i) && ((curTuple[0] == j) || (curTuple[2] == j))) || (independent2 && (curTuple[1] == k) && ((curTuple[0] == j) || (curTuple[2] == j))) || (independent1 && (curTuple[1] == j) && ((curTuple[0] == i) || (curTuple[2] == i))) || (independent2 && (curTuple[1] == j) && ((curTuple[0] == k) || (curTuple[2] == k)))) { iter.remove(); } } // remove tuples involving either (if independent1) <i, j> // or (if independent2) <j, k> from lTuples iter = lTuples.iterator(); while (iter.hasNext()) { Node[] curTuple = iter.next(); if ((independent1 && (curTuple[1] == i) && ((curTuple[0] == j) || (curTuple[2] == j))) || (independent2 && (curTuple[1] == k) && ((curTuple[0] == j) || (curTuple[2] == j))) || (independent1 && (curTuple[1] == j) && ((curTuple[0] == i) || (curTuple[2] == i))) || (independent2 && (curTuple[1] == j) && ((curTuple[0] == k) || (curTuple[2] == k)))) { iter.remove(); } } } } /////////////////////////////////////////////////////// // orient colliders (similar to original FCI ruleR0) for (Node[] thisTuple : lTuples) { Node i = thisTuple[0]; Node j = thisTuple[1]; Node k = thisTuple[2]; List<Node> sepset = getSepset(i, k); if (sepset == null) { continue; } if (!sepset.contains(j) && graph.isAdjacentTo(i, j) && graph.isAdjacentTo(j, k)) { if (!isArrowpointAllowed(i, j)) { continue; } if (!isArrowpointAllowed(k, j)) { continue; } graph.setEndpoint(i, j, Endpoint.ARROW); graph.setEndpoint(k, j, Endpoint.ARROW); printWrongColliderMessage(i, j, k, "R0_RFCI"); } } }