/** * Sets the covariance for the a<->b edge to the given covariance, if within range. Otherwise does * nothing. * * @param a a <-> b * @param b a <-> b * @param covar The covariance of a <-> b. * @return true if the coefficent was set (i.e. was within range), false if not. */ public boolean setErrorCovariance(Node a, Node b, final double covar) { Edge edge = Edges.bidirectedEdge(semGraph.getExogenous(a), semGraph.getExogenous(b)); if (edgeParameters.get(edge) == null) { throw new IllegalArgumentException("Not a covariance parameter in this model: " + edge); } if (editingEdge == null || !edge.equals(editingEdge)) { range = getParameterRange(edge); editingEdge = edge; } if (covar > range.getLow() && covar < range.getHigh()) { edgeParameters.put(edge, covar); return true; } else { return false; } // if (!paramInBounds(edge, coef)) { // edgeParameters.put(edge, d); // return false; // } // // edgeParameters.put(edge, coef); // return true; // if (!paramInBounds(edge, covar)) { // edgeParameters.put(edge, d); // return false; // } // // edgeParameters.put(edge, covar); // return true; }
public TimeLagGraphWrapper(GraphWrapper graphWrapper) { if (graphWrapper == null) { throw new NullPointerException("No graph wrapper."); } TimeLagGraph graph = new TimeLagGraph(); Graph _graph = graphWrapper.getGraph(); for (Node node : _graph.getNodes()) { Node _node = node.like(node.getName() + ":0"); _node.setNodeType(node.getNodeType()); graph.addNode(_node); } for (Edge edge : _graph.getEdges()) { if (!Edges.isDirectedEdge(edge)) { throw new IllegalArgumentException(); } Node from = edge.getNode1(); Node to = edge.getNode2(); Node _from = graph.getNode(from.getName(), 1); Node _to = graph.getNode(to.getName(), 0); graph.addDirectedEdge(_from, _to); } this.graph = graph; }
/** * Sets the coefficient for the a->b edge to the given coefficient, if within range. Otherwise * does nothing. * * @param a a -> b * @param b a -> b * @param coef The coefficient of a -> b. * @return true if the coefficent was set (i.e. was within range), false if not. */ public boolean setEdgeCoefficient(Node a, Node b, final double coef) { Edge edge = Edges.directedEdge(a, b); if (edgeParameters.get(edge) == null) { throw new NullPointerException("Not a coefficient parameter in this model: " + edge); } if (editingEdge == null || !edge.equals(editingEdge)) { range = getParameterRange(edge); editingEdge = edge; } if (coef > range.getLow() && coef < range.getHigh()) { edgeParameters.put(edge, coef); return true; } return false; // if (!paramInBounds(edge, coef)) { // edgeParameters.put(edge, d); // return false; // } // // edgeParameters.put(edge, coef); // return true; }
public Graph orient() { Graph skeleton = GraphUtils.undirectedGraph(getPattern()); Graph graph = new EdgeListGraph(skeleton.getNodes()); List<Node> nodes = skeleton.getNodes(); // Collections.shuffle(nodes); if (isR1Done()) { ruleR1(skeleton, graph, nodes); } for (Edge edge : skeleton.getEdges()) { if (!graph.isAdjacentTo(edge.getNode1(), edge.getNode2())) { graph.addUndirectedEdge(edge.getNode1(), edge.getNode2()); } } if (isR2Done()) { ruleR2(skeleton, graph); } if (isMeekDone()) { new MeekRules().orientImplied(graph); } return graph; }
private Graph condense(Graph mimStructure, Graph mimbuildStructure) { // System.out.println("Uncondensed: " + mimbuildStructure); Map<Node, Node> substitutions = new HashMap<Node, Node>(); for (Node node : mimbuildStructure.getNodes()) { for (Node _node : mimStructure.getNodes()) { if (node.getName().startsWith(_node.getName())) { substitutions.put(node, _node); break; } substitutions.put(node, node); } } HashSet<Node> nodes = new HashSet<Node>(substitutions.values()); Graph graph = new EdgeListGraph(new ArrayList<Node>(nodes)); for (Edge edge : mimbuildStructure.getEdges()) { Node node1 = substitutions.get(edge.getNode1()); Node node2 = substitutions.get(edge.getNode2()); if (node1 == node2) continue; if (graph.isAdjacentTo(node1, node2)) continue; graph.addEdge(new Edge(node1, node2, edge.getEndpoint1(), edge.getEndpoint2())); } // System.out.println("Condensed: " + graph); return graph; }
public boolean containsParameter(Edge edge) { if (Edges.isBidirectedEdge(edge)) { edge = Edges.bidirectedEdge( semGraph.getExogenous(edge.getNode1()), semGraph.getExogenous(edge.getNode2())); } return edgeParameters.keySet().contains(edge); }
public void setParameterValue(Edge edge, double value) { if (Edges.isDirectedEdge(edge)) { setEdgeCoefficient(edge.getNode1(), edge.getNode2(), value); } else if (Edges.isBidirectedEdge(edge)) { setErrorCovariance(edge.getNode1(), edge.getNode2(), value); } else { throw new IllegalArgumentException( "Only directed and bidirected edges are supported: " + edge); } }
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); } }
public boolean isViolatedBy(Graph graph) { for (Edge edge : graph.getEdges()) { if (!edge.isDirected()) { continue; } Node from = Edges.getDirectedEdgeTail(edge); Node to = Edges.getDirectedEdgeHead(edge); if (isForbidden(from.getName(), to.getName())) { return true; } } return false; }
/** * Forward equivalence search. * * @param graph The graph in the state prior to the forward equivalence search. */ private void fes(Graph graph, List<Node> nodes) { TetradLogger.getInstance().log("info", "** FORWARD EQUIVALENCE SEARCH"); lookupArrows = new HashMap<OrderedPair, Set<Arrow>>(); initializeArrowsForward(nodes); while (!sortedArrows.isEmpty()) { Arrow arrow = sortedArrows.first(); sortedArrows.remove(arrow); Node x = arrow.getX(); Node y = arrow.getY(); clearArrow(x, y); if (graph.isAdjacentTo(x, y)) { continue; } if (!validInsert(x, y, arrow.getHOrT(), arrow.getNaYX(), graph)) { continue; } List<Node> t = arrow.getHOrT(); double bump = arrow.getBump(); Set<Edge> edges = graph.getEdges(); insert(x, y, t, graph, bump); score += bump; rebuildPattern(graph); // Try to avoid duplicating scoring calls. First clear out all of the edges that need to be // changed, // then change them, checking to see if they're already been changed. I know, roundabout, but // there's // a performance boost. for (Edge edge : graph.getEdges()) { if (!edges.contains(edge)) { reevaluateForward(graph, nodes, edge.getNode1(), edge.getNode2()); } } storeGraph(graph); } }
public static Graph weightedRandomGraph(int n, int e) { List<Node> nodes = new ArrayList<Node>(); for (int i = 0; i < n; i++) nodes.add(new GraphNode("X" + i)); Graph graph = new EdgeListGraph(nodes); for (int e0 = 0; e0 < e; e0++) { int i1 = weightedRandom(nodes, graph); // int i2 = RandomUtil.getInstance().nextInt(n); int i2 = weightedRandom(nodes, graph); if (!(shortestPath(nodes.get(i1), nodes.get(i2), graph) < 9)) { e0--; continue; } if (i1 == i2) { e0--; continue; } Edge edge = Edges.undirectedEdge(nodes.get(i1), nodes.get(i2)); if (graph.containsEdge(edge)) { e0--; continue; } graph.addEdge(edge); } for (Edge edge : graph.getEdges()) { Node n1 = edge.getNode1(); Node n2 = edge.getNode2(); if (!graph.isAncestorOf(n2, n1)) { graph.removeEdge(edge); graph.addDirectedEdge(n1, n2); } else { graph.removeEdge(edge); graph.addDirectedEdge(n2, n1); } } return graph; }
private void ruleR2(Graph skeleton, Graph graph) { Set<Edge> edgeList1 = skeleton.getEdges(); // Collections.shuffle(edgeList1); for (Edge adj : edgeList1) { Node x = adj.getNode1(); Node y = adj.getNode2(); if (!isR2Orient2Cycles() && isTwoCycle(graph, x, y)) { continue; } if (!isTwoCycle(graph, x, y) && !isUndirected(graph, x, y)) { continue; } resolveOneEdgeMax(graph, x, y, isStrongR2(), new EdgeListGraph(graph)); } }
/** Get all nodes that are connected to Y by an undirected edge and not adjacent to X. */ private static List<Node> getTNeighbors(Node x, Node y, Graph graph) { List<Edge> yEdges = graph.getEdges(y); List<Node> tNeighbors = new ArrayList<Node>(); for (Edge edge : yEdges) { if (!Edges.isUndirectedEdge(edge)) { continue; } Node z = edge.getDistalNode(y); if (graph.isAdjacentTo(z, x)) { continue; } tNeighbors.add(z); } return tNeighbors; }
/** * Find all nodes that are connected to Y by an undirected edge that are adjacent to X (that is, * by undirected or directed edge). */ private static List<Node> getNaYX(Node x, Node y, Graph graph) { List<Edge> yEdges = graph.getEdges(y); List<Node> nayx = new ArrayList<Node>(); for (Edge edge : yEdges) { if (!Edges.isUndirectedEdge(edge)) { continue; } Node z = edge.getDistalNode(y); if (!graph.isAdjacentTo(z, x)) { continue; } nayx.add(z); } return nayx; }
private void initializeArrowsBackward(Graph graph) { sortedArrows.clear(); lookupArrows.clear(); for (Edge edge : graph.getEdges()) { Node x = edge.getNode1(); Node y = edge.getNode2(); if (!knowledgeEmpty()) { if (!getKnowledge().noEdgeRequired(x.getName(), y.getName())) { continue; } } if (Edges.isDirectedEdge(edge)) { calculateArrowsBackward(x, y, graph); } else { calculateArrowsBackward(x, y, graph); calculateArrowsBackward(y, x, graph); } } }
private Graph pickDag(Graph graph) { SearchGraphUtils.basicPattern(graph, false); addRequiredEdges(graph); boolean containsUndirected; do { containsUndirected = false; for (Edge edge : graph.getEdges()) { if (Edges.isUndirectedEdge(edge)) { containsUndirected = true; graph.removeEdge(edge); Edge _edge = Edges.directedEdge(edge.getNode1(), edge.getNode2()); graph.addEdge(_edge); } } meekOrient(graph, getKnowledge()); } while (containsUndirected); return graph; }
/** * @return The edge coefficient matrix of the model, a la SemIm. Note that this will normally need * to be transposed, since [a][b] is the edge coefficient for a-->b, not b-->a. Sorry. * History. THESE ARE PARAMETERS OF THE MODEL--THE ONLY PARAMETERS. */ public TetradMatrix edgeCoef() { List<Node> variableNodes = getVariableNodes(); TetradMatrix edgeCoef = new TetradMatrix(variableNodes.size(), variableNodes.size()); for (Edge edge : edgeParameters.keySet()) { if (Edges.isBidirectedEdge(edge)) { continue; } Node a = edge.getNode1(); Node b = edge.getNode2(); int aindex = variableNodes.indexOf(a); int bindex = variableNodes.indexOf(b); double coef = edgeParameters.get(edge); edgeCoef.set(aindex, bindex, coef); } return edgeCoef; }
/** * 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); } } }
/** Get a graph and direct only the unshielded colliders. */ public static void basicPattern(Graph graph) { Set<Edge> undirectedEdges = new HashSet<Edge>(); NEXT_EDGE: for (Edge edge : graph.getEdges()) { Node head = null, tail = null; if (edge.getEndpoint1() == Endpoint.ARROW && edge.getEndpoint2() == Endpoint.TAIL) { head = edge.getNode1(); tail = edge.getNode2(); } else if (edge.getEndpoint2() == Endpoint.ARROW && edge.getEndpoint1() == Endpoint.TAIL) { head = edge.getNode2(); tail = edge.getNode1(); } if (head != null) { for (Node node : graph.getParents(head)) { if (node != tail && !graph.isAdjacentTo(tail, node)) { continue NEXT_EDGE; } } undirectedEdges.add(edge); } } for (Edge nextUndirected : undirectedEdges) { Node node1 = nextUndirected.getNode1(), node2 = nextUndirected.getNode2(); graph.removeEdge(nextUndirected); graph.addUndirectedEdge(node1, node2); } }
/** * 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 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)); } } } } }
/** * @param edge a->b or a<->b. * @return the range of the covariance parameter for a->b or a<->b. */ public ParameterRange getParameterRange(Edge edge) { if (Edges.isBidirectedEdge(edge)) { edge = Edges.bidirectedEdge( semGraph.getExogenous(edge.getNode1()), semGraph.getExogenous(edge.getNode2())); } if (!(edgeParameters.keySet().contains(edge))) { throw new IllegalArgumentException("Not an edge in this model: " + edge); } double initial = edgeParameters.get(edge); if (initial == Double.NEGATIVE_INFINITY) { initial = Double.MIN_VALUE; } else if (initial == Double.POSITIVE_INFINITY) { initial = Double.MAX_VALUE; } double value = initial; // look upward for a point that fails. double high = value + 1; while (paramInBounds(edge, high)) { high = value + 2 * (high - value); if (high == Double.POSITIVE_INFINITY) { break; } } // find the boundary using binary search. double rangeHigh; if (high == Double.POSITIVE_INFINITY) { rangeHigh = high; } else { double low = value; while (high - low > 1e-10) { double midpoint = (high + low) / 2.0; if (paramInBounds(edge, midpoint)) { low = midpoint; } else { high = midpoint; } } rangeHigh = (high + low) / 2.0; } // look downard for a point that fails. double low = value - 1; while (paramInBounds(edge, low)) { low = value - 2 * (value - low); if (low == Double.NEGATIVE_INFINITY) { break; } } double rangeLow; if (low == Double.NEGATIVE_INFINITY) { rangeLow = low; } else { // find the boundary using binary search. high = value; while (high - low > 1e-10) { double midpoint = (high + low) / 2.0; if (paramInBounds(edge, midpoint)) { high = midpoint; } else { low = midpoint; } } rangeLow = (high + low) / 2.0; } if (Edges.isDirectedEdge(edge)) { edgeParameters.put(edge, initial); } else if (Edges.isBidirectedEdge(edge)) { edgeParameters.put(edge, initial); } return new ParameterRange(edge, value, rangeLow, rangeHigh); }
/** Generates a simple exemplar of this class to test serialization. */ public static ParameterRange serializableInstance() { return new ParameterRange(Edge.serializableInstance(), 1.0, 1.0, 1.0); }