/** * Transforms a maximally directed pattern (PDAG) represented in graph <code>g</code> into an * arbitrary DAG 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. R. Silva, June 2004 */ public static void pdagToDag(Graph g) { Graph p = new EdgeListGraph(g); List<Edge> undirectedEdges = new ArrayList<Edge>(); for (Edge edge : g.getEdges()) { if (edge.getEndpoint1() == Endpoint.TAIL && edge.getEndpoint2() == Endpoint.TAIL && !undirectedEdges.contains(edge)) { undirectedEdges.add(edge); } } g.removeEdges(undirectedEdges); List<Node> pNodes = p.getNodes(); do { Node x = null; for (Node pNode : pNodes) { x = pNode; if (p.getChildren(x).size() > 0) { continue; } Set<Node> neighbors = new HashSet<Node>(); for (Edge edge : p.getEdges()) { if (edge.getNode1() == x || edge.getNode2() == x) { if (edge.getEndpoint1() == Endpoint.TAIL && edge.getEndpoint2() == Endpoint.TAIL) { if (edge.getNode1() == x) { neighbors.add(edge.getNode2()); } else { neighbors.add(edge.getNode1()); } } } } if (neighbors.size() > 0) { Collection<Node> parents = p.getParents(x); Set<Node> all = new HashSet<Node>(neighbors); all.addAll(parents); if (!GraphUtils.isClique(all, p)) { continue; } } for (Node neighbor : neighbors) { Node node1 = g.getNode(neighbor.getName()); Node node2 = g.getNode(x.getName()); g.addDirectedEdge(node1, node2); } p.removeNode(x); break; } pNodes.remove(x); } while (pNodes.size() > 0); }
private boolean dConnected(Graph graph, String x, String y, String... z) { Node _x = graph.getNode(x); Node _y = graph.getNode(y); List<Node> _z = new ArrayList<Node>(); for (String name : z) { _z.add(graph.getNode(name)); } return graph.isDConnectedTo(_x, _y, _z); }
public static void arrangeByKnowledgeTiers(Graph graph, Knowledge knowledge) { if (knowledge.getNumTiers() == 0) { throw new IllegalArgumentException("There are no Tiers to arrange."); } List<Node> nodes = graph.getNodes(); List<String> varNames = new ArrayList<String>(); int ySpace = 500 / knowledge.getNumTiers(); ySpace = ySpace < 50 ? 50 : ySpace; for (Node node1 : nodes) { varNames.add(node1.getName()); } List<String> notInTier = knowledge.getVarsNotInTier(varNames); int x = 0; int y = 50 - ySpace; if (notInTier.size() > 0) { y += ySpace; for (String name : notInTier) { x += 90; Node node = graph.getNode(name); if (node != null) { node.setCenterX(x); node.setCenterY(y); } } } for (int i = 0; i < knowledge.getNumTiers(); i++) { List<String> tier = knowledge.getTier(i); y += ySpace; x = -25; for (String name : tier) { x += 90; Node node = graph.getNode(name); if (node != null) { node.setCenterX(x); node.setCenterY(y); } } } }
private Graph changeLatentNames(Graph full, Clusters measurements, List<String> latentVarList) { Graph g2 = null; try { g2 = (Graph) new MarshalledObject(full).get(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } for (int i = 0; i < measurements.getNumClusters(); i++) { List<String> d = measurements.getCluster(i); String latentName = latentVarList.get(i); for (Node node : full.getNodes()) { if (!(node.getNodeType() == NodeType.LATENT)) { continue; } List<Node> _children = full.getChildren(node); _children.removeAll(ReidentifyVariables.getLatents(full)); List<String> childNames = getNames(_children); if (new HashSet<String>(childNames).equals(new HashSet<String>(d))) { g2.getNode(node.getName()).setName(latentName); } } } return g2; }
// Trying to trip up the breadth first algorithm. public void testDSeparation3() { Graph graph = GraphConverter.convert("x-->s1,x-->s2,s1-->s3,s3-->s2,s3<--y"); assertTrue( graph.isDSeparatedFrom(graph.getNode("x"), graph.getNode("y"), new ArrayList<Node>())); graph = GraphConverter.convert("1-->2,2<--4,2-->7,2-->3"); assertTrue( graph.isDSeparatedFrom(graph.getNode("4"), graph.getNode("1"), new ArrayList<Node>())); graph = GraphConverter.convert("X1-->X5,X1-->X6,X2-->X3,X4-->X6,X5-->X3,X6-->X5,X7-->X3"); assertTrue(dConnected(graph, "X2", "X4", "X3", "X6")); graph = GraphConverter.convert("X1<--X2,X1<--X3,X2-->X3,X3<--X4"); assertTrue(dConnected(graph, "X1", "X4", "X3")); graph = GraphConverter.convert("X2-->X7,X3-->X2,X5-->X1,X5-->X2,X6-->X1,X7-->X6,X2->X4"); assertTrue(dConnected(graph, "X1", "X3")); graph = GraphConverter.convert("1-->3,1-->4,2-->5,4-->5,4-->7,6-->5,7-->3"); assertTrue(dConnected(graph, "1", "4")); }
/** * Build a graph given an HMM. The graph will not be surrounded by dummy nodes. The number of * nodes in the graph is the number of emitting states in the hmm plus one, to account for a * final, non-emitting state. * * @param hmm the HMM * @return the graph */ private Graph buildModelGraph(SenoneHMM hmm) { Graph graph = new Graph(); Node prevNode; Node stateNode = null; float[][] tmat = hmm.getTransitionMatrix(); prevNode = new Node(NodeType.DUMMY); graph.addNode(prevNode); graph.setInitialNode(prevNode); // 'hmm.getOrder() + 1' to account for final, non-emitting state. for (int i = 0; i < hmm.getOrder() + 1; i++) { /* create a new node for the next hmmState */ stateNode = new Node(NodeType.STATE, hmm.getUnit().getName()); stateNode.setObject(hmm.getState(i)); graph.addNode(stateNode); /* Link the new node into the graph */ if (i == 0) { graph.linkNodes(prevNode, stateNode); } for (int j = 0; j <= i; j++) { // System.out.println("TMAT: " + j + " " + i + " " + // tmat[j][i]); if (tmat[j][i] != LogMath.LOG_ZERO) { // 'j + 1' to account for the initial dummy node graph.linkNodes(graph.getNode(j + 1), stateNode); } } prevNode = stateNode; } /* All words are done. Just add the final dummy */ // stateNode = new Node(NodeType.DUMMY); // graph.linkNodes(prevNode, stateNode); graph.setFinalNode(stateNode); return graph; }
/** * 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); } } }
private void addRequiredEdges(Graph graph) { if (true) return; if (knowledgeEmpty()) return; for (Iterator<KnowledgeEdge> it = getKnowledge().requiredEdgesIterator(); it.hasNext(); ) { KnowledgeEdge next = it.next(); Node nodeA = graph.getNode(next.getFrom()); Node nodeB = graph.getNode(next.getTo()); if (!graph.isAncestorOf(nodeB, nodeA)) { graph.removeEdges(nodeA, nodeB); graph.addDirectedEdge(nodeA, nodeB); TetradLogger.getInstance() .log("insertedEdges", "Adding edge by knowledge: " + graph.getEdge(nodeA, nodeB)); } } for (Edge edge : graph.getEdges()) { final String A = edge.getNode1().getName(); final String B = edge.getNode2().getName(); if (knowledge.isForbidden(A, B)) { Node nodeA = edge.getNode1(); Node nodeB = edge.getNode2(); if (nodeA != null && nodeB != null && graph.isAdjacentTo(nodeA, nodeB) && !graph.isChildOf(nodeA, nodeB)) { if (!graph.isAncestorOf(nodeA, nodeB)) { graph.removeEdges(nodeA, nodeB); graph.addDirectedEdge(nodeB, nodeA); TetradLogger.getInstance() .log("insertedEdges", "Adding edge by knowledge: " + graph.getEdge(nodeB, nodeA)); } } if (!graph.isChildOf(nodeA, nodeB) && getKnowledge().isForbidden(nodeA.getName(), nodeB.getName())) { if (!graph.isAncestorOf(nodeA, nodeB)) { graph.removeEdges(nodeA, nodeB); graph.addDirectedEdge(nodeB, nodeA); TetradLogger.getInstance() .log("insertedEdges", "Adding edge by knowledge: " + graph.getEdge(nodeB, nodeA)); } } } else if (knowledge.isForbidden(B, A)) { Node nodeA = edge.getNode2(); Node nodeB = edge.getNode1(); if (nodeA != null && nodeB != null && graph.isAdjacentTo(nodeA, nodeB) && !graph.isChildOf(nodeA, nodeB)) { if (!graph.isAncestorOf(nodeA, nodeB)) { graph.removeEdges(nodeA, nodeB); graph.addDirectedEdge(nodeB, nodeA); TetradLogger.getInstance() .log("insertedEdges", "Adding edge by knowledge: " + graph.getEdge(nodeB, nodeA)); } } if (!graph.isChildOf(nodeA, nodeB) && getKnowledge().isForbidden(nodeA.getName(), nodeB.getName())) { if (!graph.isAncestorOf(nodeA, nodeB)) { graph.removeEdges(nodeA, nodeB); graph.addDirectedEdge(nodeB, nodeA); TetradLogger.getInstance() .log("insertedEdges", "Adding edge by knowledge: " + graph.getEdge(nodeB, nodeA)); } } } } }
/** Do an actual deletion (Definition 13 from Chickering, 2002). */ private void delete(Node x, Node y, List<Node> subset, Graph graph, double bump) { Edge trueEdge = null; if (trueGraph != null) { Node _x = trueGraph.getNode(x.getName()); Node _y = trueGraph.getNode(y.getName()); trueEdge = trueGraph.getEdge(_x, _y); } if (log && verbose) { Edge oldEdge = graph.getEdge(x, y); String label = trueGraph != null && trueEdge != null ? "*" : ""; TetradLogger.getInstance() .log( "deletedEdges", (graph.getNumEdges() - 1) + ". DELETE " + oldEdge + " " + subset + " (" + bump + ") " + label); out.println( (graph.getNumEdges() - 1) + ". DELETE " + oldEdge + " " + subset + " (" + bump + ") " + label); } else { int numEdges = graph.getNumEdges() - 1; if (numEdges % 50 == 0) out.println(numEdges); } graph.removeEdge(x, y); for (Node h : subset) { Edge oldEdge = graph.getEdge(y, h); graph.removeEdge(y, h); graph.addDirectedEdge(y, h); if (log) { TetradLogger.getInstance() .log("directedEdges", "--- Directing " + oldEdge + " to " + graph.getEdge(y, h)); } if (verbose) { out.println("--- Directing " + oldEdge + " to " + graph.getEdge(y, h)); } if (Edges.isUndirectedEdge(graph.getEdge(x, h))) { if (!graph.isAdjacentTo(x, h)) throw new IllegalArgumentException("Not adjacent: " + x + ", " + h); oldEdge = graph.getEdge(x, h); graph.removeEdge(x, h); graph.addDirectedEdge(x, h); if (log) { TetradLogger.getInstance() .log("directedEdges", "--- Directing " + oldEdge + " to " + graph.getEdge(x, h)); } if (verbose) { out.println("--- Directing " + oldEdge + " to " + graph.getEdge(x, h)); } } } }
// serial. private void insert(Node x, Node y, List<Node> t, Graph graph, double bump) { if (graph.isAdjacentTo(x, y)) { return; // The initial graph may already have put this edge in the graph. // throw new IllegalArgumentException(x + " and " + y + " are already adjacent in // the graph."); } Edge trueEdge = null; if (trueGraph != null) { Node _x = trueGraph.getNode(x.getName()); Node _y = trueGraph.getNode(y.getName()); trueEdge = trueGraph.getEdge(_x, _y); } graph.addDirectedEdge(x, y); if (log) { String label = trueGraph != null && trueEdge != null ? "*" : ""; TetradLogger.getInstance() .log( "insertedEdges", graph.getNumEdges() + ". INSERT " + graph.getEdge(x, y) + " " + t + " " + bump + " " + label); } else { int numEdges = graph.getNumEdges() - 1; if (verbose) { if (numEdges % 50 == 0) out.println(numEdges); } } if (verbose) { String label = trueGraph != null && trueEdge != null ? "*" : ""; out.println( graph.getNumEdges() + ". INSERT " + graph.getEdge(x, y) + " " + t + " " + bump + " " + label); } else { int numEdges = graph.getNumEdges() - 1; if (verbose) { if (numEdges % 50 == 0) out.println(numEdges); } } for (Node _t : t) { Edge oldEdge = graph.getEdge(_t, y); if (oldEdge == null) throw new IllegalArgumentException("Not adjacent: " + _t + ", " + y); graph.removeEdge(_t, y); graph.addDirectedEdge(_t, y); if (log && verbose) { TetradLogger.getInstance() .log("directedEdges", "--- Directing " + oldEdge + " to " + graph.getEdge(_t, y)); out.println("--- Directing " + oldEdge + " to " + graph.getEdge(_t, y)); } } }
private void createGraph() { graph = new Graph(); String[] columns = Arrays.copyOf(assayTable[0], assayTable[0].length, String[].class); int index = 0; ProcessNode lastProcess = null; NodeWithComments lastMaterialOrData = null; NodeWithComments lastSample = null; ISAFactorValue lastFactorValue = null; ProtocolExecutionNode lastProtocolExecutionNode = null; List<ProtocolExecutionNode> protocolExecutionNodes = new ArrayList<ProtocolExecutionNode>(); for (String column : columns) { if (column.matches(Date.REGEXP)) { Date date = new Date(index, column); if (lastProtocolExecutionNode != null) { lastProtocolExecutionNode.addDate(date); } } else if (column.matches(Performer.REGEXP)) { Performer performer = new Performer(index, column); if (lastProtocolExecutionNode != null) { lastProtocolExecutionNode.addPerformer(performer); } } else if (column.matches(ProtocolExecutionNode.REGEXP)) { ProtocolExecutionNode protocolExecutionNode = new ProtocolExecutionNode(index, column); protocolExecutionNodes.add(protocolExecutionNode); lastProtocolExecutionNode = protocolExecutionNode; if (lastMaterialOrData != null) { protocolExecutionNode.setInputNode(lastMaterialOrData); } graph.addNode(protocolExecutionNode); } else if (column.matches(ProcessNode.REGEXP)) { ProcessNode processNode = new ProcessNode(index, column); graph.addNode(processNode); if (lastMaterialOrData != null) { // but it could be a DataNode rather than a material node... do I need a new object? // processNode.setInputNode( // new MaterialNode(lastMaterialOrData.getIndex(), lastMaterialOrData.getName())); processNode.setInputNode(lastMaterialOrData); } lastProcess = processNode; if (lastProcess != null) { lastProcess.addProtocolExecutionNodes(protocolExecutionNodes); protocolExecutionNodes = new ArrayList<ProtocolExecutionNode>(); } } else if (column.contains(ISADataNode.CONTAINS) && !column.contains("Comment")) { NodeWithComments dataNode = new DataNode(index, column); graph.addNode(dataNode); lastMaterialOrData = dataNode; if (lastProcess != null) { lastProcess.setOutputNode(dataNode); lastProcess = null; } else if (lastProtocolExecutionNode != null) { lastProtocolExecutionNode.setOutputNode(dataNode); lastProtocolExecutionNode = null; } if (lastMaterialOrData != null && lastProcess == null && lastProtocolExecutionNode != null) { lastProtocolExecutionNode.setOutputNode(dataNode); protocolExecutionNodes = new ArrayList<ProtocolExecutionNode>(); } } else if (column.matches(ISAMaterialAttribute.REGEXP)) { ISAMaterialAttribute materialAttribute = new MaterialAttribute(index, column); if (lastMaterialOrData != null && lastMaterialOrData instanceof MaterialNode) { ((MaterialNode) graph.getNode(lastMaterialOrData.getIndex())) .addMaterialAttribute(materialAttribute); } } else if (column.matches(MaterialNode.REGEXP)) { NodeWithComments materialNode = null; if (column.matches(ISASampleNode.REGEXP)) { materialNode = new SampleNode(index, column); lastSample = materialNode; } else { materialNode = new MaterialNode(index, column); } // if there is a previous material node // and no process node, add a dummy process node if (lastMaterialOrData != null && lastProcess == null && lastProtocolExecutionNode != null) { lastProtocolExecutionNode.setOutputNode(materialNode); protocolExecutionNodes = new ArrayList<ProtocolExecutionNode>(); } graph.addNode(materialNode); lastMaterialOrData = materialNode; if (lastProcess != null) { lastProcess.setOutputNode(materialNode); lastProcess = null; } } else if (column.matches(ISAFactorValue.REGEXP)) { ISAFactorValue factorValue = new FactorValue(index, column); lastFactorValue = factorValue; if (lastSample != null && lastSample instanceof SampleNode) { ((SampleNode) graph.getNode(lastSample.getIndex())).addFactorValue(factorValue); } } else if (column.matches(ISAUnit.REGEXP)) { ISAUnit unit = new Unit(index, column); if (lastFactorValue != null) { lastFactorValue.setUnit(unit); } } else if (column.matches(ProcessParameter.REGEXP)) { ProcessParameter parameter = new ProcessParameter(index, column); if (lastProtocolExecutionNode != null) { ((ProcessNode) graph.getNode(lastProtocolExecutionNode.getIndex())) .addParameter(parameter); } } else if (column.matches(CommentNode.REGEXP)) { CommentNode commentNode = new CommentNode(index, column); if (lastProcess != null && lastMaterialOrData != null && lastProtocolExecutionNode != null) { // lastProcess greater index if (lastProcess.getIndex() > lastMaterialOrData.getIndex() && lastProcess.getIndex() > lastProtocolExecutionNode.getIndex()) { lastProcess.addComment(commentNode); } else if (lastMaterialOrData.getIndex() > lastProcess.getIndex() && lastMaterialOrData.getIndex() > lastProtocolExecutionNode.getIndex()) { lastMaterialOrData.addComment(commentNode); } else if (lastProtocolExecutionNode.getIndex() > lastProcess.getIndex() && lastProtocolExecutionNode.getIndex() > lastMaterialOrData.getIndex()) { lastProtocolExecutionNode.addComment(commentNode); } } else { // one of them is null if (lastProcess != null && lastMaterialOrData != null) { if (lastProcess.getIndex() > lastMaterialOrData.getIndex()) { lastProcess.addComment(commentNode); } else { lastMaterialOrData.addComment(commentNode); } } else if (lastProcess != null && lastProtocolExecutionNode != null) { if (lastProcess.getIndex() > lastProtocolExecutionNode.getIndex()) { lastProcess.addComment(commentNode); } else { lastProtocolExecutionNode.addComment(commentNode); } } else if (lastMaterialOrData != null && lastProtocolExecutionNode != null) { if (lastMaterialOrData.getIndex() > lastProtocolExecutionNode.getIndex()) { lastMaterialOrData.addComment(commentNode); } else { lastProtocolExecutionNode.addComment(commentNode); } } else { // only one is not null if (lastMaterialOrData != null) { lastMaterialOrData.addComment(commentNode); } else if (lastProcess != null) { lastProcess.addComment(commentNode); } else if (lastProtocolExecutionNode != null) { lastProtocolExecutionNode.addComment(commentNode); } } } } index++; } }