All Downloads are FREE. Search and download functionalities are using the official Maven repository.

edu.cmu.tetrad.search.utils.DagIterator Maven / Gradle / Ivy

There is a newer version: 7.6.4
Show newest version
///////////////////////////////////////////////////////////////////////////////
// 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.tetrad.search.utils;

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 java.util.LinkedList;

/**
 * Given a graph, lists all DAGs that result from directing the undirected edges in that graph every possible way. Uses
 * a Meek-algorithm-type method.
 *
 * @author josephramsey
 */
public class DagIterator {

    /**
     * The stack of graphs, with annotations as to the arbitrary undirected edges chosen in them and whether or not
     * these edges have already been oriented left and/or right.
     */
    private final LinkedList decoratedGraphs = new LinkedList<>();
    private Graph storedDag;

    /**
     * The given CPDAG must be a CPDAG. If it does not consist entirely of directed and undirected edges and if it is
     * not acyclic, it is rejected.
     *
     * @throws IllegalArgumentException if the CPDAG is not a CPDAG.
     */
    public DagIterator(Graph CPDAG) {

        for (Edge edge : CPDAG.getEdges()) {
            if (Edges.isDirectedEdge(edge) || Edges.isUndirectedEdge(edge)) {
                continue;
            }

            throw new IllegalArgumentException("The graph may consist only of " +
                    "directed and undirected edges: " + edge);
        }

        this.decoratedGraphs.add(new DecoratedGraph(CPDAG));
    }

    /**
     * Successive calls to this method return successive DAGs in the CPDAG, in a more or less natural enumeration of
     * them in which an arbitrary undirected edge is picked, oriented one way, Meek rules applied, then a remaining
     * unoriented edge is picked, oriented one way, and so on, until a DAG is obtained, and then by backtracking the
     * other orientation of each chosen edge is tried. Nonrecursive, obviously.
     * 

* * @return a Graph instead of a DAG because sometimes, due to faulty patterns, a cyclic graph is produced, and the * end-user may need to decide what to do with it. The simplest thing is to construct a DAG (Dag(graph)) and catch * an exception. */ public Graph next() { if (this.storedDag != null) { Graph temp = this.storedDag; this.storedDag = null; return temp; } if (this.decoratedGraphs.isEmpty()) { return null; } // If it's a DAG if (!this.decoratedGraphs.getLast().hasUndirectedEdge()) { // Go back to the lastmost decorated graph whose successor is // oriented right, and add a graph with that oriented left. while (true) { if (this.decoratedGraphs.isEmpty()) { return null; } DecoratedGraph graph = this.decoratedGraphs.removeLast(); if (graph.hasUndirectedEdge() && !graph.wasDirectedRight()) { throw new IllegalStateException(); } if (this.decoratedGraphs.isEmpty() && !graph.hasUndirectedEdge()) { return new EdgeListGraph(graph.getGraph()); } if (graph.wasDirectedRight() && !graph.wasDirectedLeft()) { this.decoratedGraphs.add(graph); DecoratedGraph graph1 = graph.directLeft(); if (graph1 == null) { continue; } this.decoratedGraphs.add(graph1); break; } } } // Apply right orientations and Meek orientations until there's a DAG. while (this.decoratedGraphs.getLast().hasUndirectedEdge()) { DecoratedGraph graph = this.decoratedGraphs.getLast().directRight(); if (graph == null) { continue; } this.decoratedGraphs.add(graph); } // Return the DAG. return new EdgeListGraph(this.decoratedGraphs.getLast().getGraph()); } /** * @return true just in case there is still a DAG remaining in the enumeration of DAGs for this pattern. */ public boolean hasNext() { if (this.storedDag == null) { this.storedDag = next(); } return this.storedDag != null; } private static class DecoratedGraph { private Graph graph; private Edge edge; private boolean wasDirectedRight; private boolean wasDirectedLeft; public DecoratedGraph(Graph graph) { this.setGraph(graph); this.edge = findUndirectedEdge(graph); } private Edge findUndirectedEdge(Graph graph) { for (Edge edge : graph.getEdges()) { if (Edges.isUndirectedEdge(edge)) { return edge; } } return null; } private boolean hasUndirectedEdge() { return this.edge != null; } public Graph getGraph() { return this.graph; } public void setGraph(Graph graph) { this.graph = graph; } public Edge getEdge() { return this.edge; } public void setEdge(Edge edge) { this.edge = edge; } public boolean wasDirectedRight() { return this.wasDirectedRight; } public boolean wasDirectedLeft() { return this.wasDirectedLeft; } public DecoratedGraph directLeft() { if (this.edge == null) { throw new IllegalArgumentException(); } if (this.graph.paths().isAncestorOf(this.edge.getNode1(), this.edge.getNode2()) && !this.graph.paths().isAncestorOf(this.edge.getNode2(), this.edge.getNode1())) { this.wasDirectedLeft = true; return directRight(); } if (!this.wasDirectedLeft) { Graph graph = new EdgeListGraph(this.graph); graph.removeEdge(this.edge.getNode1(), this.edge.getNode2()); graph.addDirectedEdge(this.edge.getNode2(), this.edge.getNode1()); // System.out.println("Orienting " + graph.getEdge(edge.getNode1(), edge.getNode2())); this.wasDirectedLeft = true; return new DecoratedGraph(graph); } return null; } public DecoratedGraph directRight() { if (this.edge == null) { throw new IllegalArgumentException(); } if (this.graph.paths().isAncestorOf(this.edge.getNode2(), this.edge.getNode1()) && !this.graph.paths().isAncestorOf(this.edge.getNode1(), this.edge.getNode2())) { this.wasDirectedRight = true; return directLeft(); } if (!this.wasDirectedRight) { Graph graph = new EdgeListGraph(this.graph); graph.removeEdge(this.edge.getNode1(), this.edge.getNode2()); graph.addDirectedEdge(this.edge.getNode1(), this.edge.getNode2()); // System.out.println("Orienting " + graph.getEdge(edge.getNode1(), edge.getNode2())); this.wasDirectedRight = true; return new DecoratedGraph(graph); } return null; } public String toString() { return this.graph.toString(); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy