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

edu.cmu.tetrad.search.Cpc 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;

import edu.cmu.tetrad.data.Knowledge;
import edu.cmu.tetrad.graph.Edge;
import edu.cmu.tetrad.graph.Graph;
import edu.cmu.tetrad.graph.GraphUtils;
import edu.cmu.tetrad.graph.Triple;
import edu.cmu.tetrad.search.utils.PcCommon;
import edu.cmu.tetrad.search.utils.SepsetMap;
import edu.cmu.tetrad.util.MillisecondTimes;
import edu.cmu.tetrad.util.TetradLogger;

import java.util.HashSet;
import java.util.Set;

/**
 * 

Implements a convervative version of PC, in which the Markov condition is assumed but faithfulness is tested * locally. The reference is here:

* *

Ramsey, J., Zhang, J., & Spirtes, P. L. (2012). Adjacency-faithfulness and conservative causal inference. * arXiv preprint arXiv:1206.6843.

* *

Conservative triple orientation is a method for orienting unshielded triples X*-*Y*-*Z as one of the following: * (a) Collider, X->Y<-Z, (b) Noncollider, X-->Y-->Z, or X<-Y<-Z, or X<-Y->Z, (c) ambiguous between (a) or (b). One does * this by conditioning on subsets of adj(X) or adj(Z). One first checks conditional independence of X and Z conditional * on each of these subsets, then lists all of these subsets conditional on which X and Z are *independent*, then looks * thoough this list to see if Y is in them. If Y is in all of these subset, the triple is judged to be a noncollider; * if it is in none of these subsets, the triple is judged to be a collider, and if it is in some of these subsets and * not in others of the subsets, then it is judged to be ambiguous.

* *

Ambiguous triple are marked in the final graph using an underline, and the final graph is called an "e-pattern", * and represents a collection of CPDAGs. To find an element of this collection, one first needs to choose for each * ambiguous triple whether it should be a collider or a noncollider and then run the Meek rules given the result of * these decisions.

* *

See setter methods for "knobs" you can turn to control the output of PC and their defaults.

* * *

This class is configured to respect knowledge of forbidden and required edges, including knowledge of temporal * tiers.

* * @author josephramsey (this version). * @see Pc * @see Knowledge * @see edu.cmu.tetrad.search.utils.MeekRules */ public final class Cpc implements IGraphSearch { private final IndependenceTest independenceTest; private final TetradLogger logger = TetradLogger.getInstance(); private Knowledge knowledge = new Knowledge(); private Graph graph; private long elapsedTime; private Set colliderTriples; private Set noncolliderTriples; private Set ambiguousTriples; private SepsetMap sepsets; private int depth = 1000; private boolean stable = true; private boolean meekPreventCycles = true; private PcCommon.ConflictRule conflictRule = PcCommon.ConflictRule.PRIORITIZE_EXISTING; private boolean verbose = false; private PcCommon.PcHeuristicType pcHeuristicType = PcCommon.PcHeuristicType.NONE; /** * Constructs a CPC algorithm that uses the given independence test as oracle. This does not make a copy of the * independence test, for fear of duplicating the data set! * * @param independenceTest The test to user for oracle conditional independence information. */ public Cpc(IndependenceTest independenceTest) { if (independenceTest == null) { throw new NullPointerException(); } this.independenceTest = independenceTest; } /** * Runs CPC starting with a fully connected graph over all the variables in the domain of the independence test. See * PC for caveats. The number of possible cycles and bidirected edges is far less with CPC than with PC. * * @return The e-pattern for the search, which is a graphical representation of a set of possible CPDAGs. */ public Graph search() { this.logger.log("info", "Starting CPC algorithm"); this.logger.log("info", "Independence test = " + getIndependenceTest() + "."); this.ambiguousTriples = new HashSet<>(); this.colliderTriples = new HashSet<>(); this.noncolliderTriples = new HashSet<>(); Fas fas = new Fas(getIndependenceTest()); long startTime = MillisecondTimes.timeMillis(); fas.setKnowledge(getKnowledge()); fas.setDepth(getDepth()); fas.setVerbose(this.verbose); // Note that we are ignoring the sepset map returned by this method // on purpose; it is not used in this search. this.graph = fas.search(); this.sepsets = fas.getSepsets(); PcCommon search = new PcCommon(independenceTest); search.setDepth(depth); search.setConflictRule(conflictRule); search.setPcHeuristicType(pcHeuristicType); search.setMeekPreventCycles(meekPreventCycles); search.setKnowledge(this.knowledge); if (stable) { search.setFasType(PcCommon.FasType.STABLE); } else { search.setFasType(PcCommon.FasType.REGULAR); } search.setColliderDiscovery(PcCommon.ColliderDiscovery.CONSERVATIVE); search.setConflictRule(conflictRule); search.setVerbose(verbose); this.graph = search.search(); this.sepsets = fas.getSepsets(); long endTime = MillisecondTimes.timeMillis(); this.elapsedTime = endTime - startTime; TetradLogger.getInstance().log("info", "Elapsed time = " + (this.elapsedTime) / 1000. + " s"); TetradLogger.getInstance().log("info", "Finishing CPC algorithm."); this.colliderTriples = search.getColliderTriples(); this.noncolliderTriples = search.getNoncolliderTriples(); this.ambiguousTriples = search.getAmbiguousTriples(); logTriples(); TetradLogger.getInstance().flush(); return this.graph; } /** * Sets to true just in case edges will not be added if they would create cycles. * * @param meekPreventCycles True, if so. */ public void meekPreventCycles(boolean meekPreventCycles) { this.meekPreventCycles = meekPreventCycles; } /** * Returns the elapsed time of search in milliseconds, after search() has been run. * * @return This time. */ public long getElapsedTime() { return this.elapsedTime; } /** * Returns the knowledge specification used in the search. Non-null. * * @return this knowledge. */ public Knowledge getKnowledge() { return this.knowledge; } /** * Sets the knowledge specification used in the search. Non-null. * * @param knowledge This knowledge. */ public void setKnowledge(Knowledge knowledge) { this.knowledge = knowledge; } /** * Rreturn the independence test used in the search, set in the constructor. * * @return This. */ public IndependenceTest getIndependenceTest() { return this.independenceTest; } /** * Returns the depth of the search--that is, the maximum number of variables conditioned on in any conditional * independence test. * * @return This. */ public int getDepth() { return this.depth; } /** * Sets the maximum number of variables conditioned on in any conditional independence test. If set to -1, the value * of 1000 will be used. May not be set to Integer.MAX_VALUE, due to a Java bug on multicore systems. * * @param depth This maximum. */ public void setDepth(int depth) { if (depth < -1) { throw new IllegalArgumentException("Depth must be -1 or >= 0: " + depth); } if (depth == Integer.MAX_VALUE) { throw new IllegalArgumentException("Depth must not be Integer.MAX_VALUE, " + "due to a known bug."); } this.depth = depth; } /** * Returns the set of ambiguous triples found during the most recent run of the algorithm. Non-null after a call to * search(). * * @return This set. */ public Set getAmbiguousTriples() { return new HashSet<>(this.ambiguousTriples); } /** * Returns the edges in the search graph as a set of undirected edges. * * @return These edges. */ public Set getAdjacencies() { return new HashSet<>(GraphUtils.undirectedGraph(this.graph).getEdges()); } /** * Returns a map for x _||_ y | z1,..,zn from {x, y} to {z1,...,zn}. * * @return This map. */ public SepsetMap getSepsets() { return this.sepsets; } /** * The graph that's constructed during the search. * * @return This graph. */ public Graph getGraph() { return this.graph; } /** * Sets whether verbose output should be printed. * * @param verbose True, if so. */ public void setVerbose(boolean verbose) { this.verbose = verbose; } /** *

Sets whether the stable adjacency search should be used. Default is false. Default is false. See the * following reference for this:

* *

Colombo, D., & Maathuis, M. H. (2014). Order-independent constraint-based causal structure learning. J. Mach. * Learn. Res., 15(1), 3741-3782.

* * @param stable True iff the case. */ public void setStable(boolean stable) { this.stable = stable; } /** * Sets which conflict rule to use for resolving collider orientation conflicts. * * @param conflictRule The rule. * @see edu.cmu.tetrad.search.utils.PcCommon.ConflictRule */ public void setConflictRule(PcCommon.ConflictRule conflictRule) { this.conflictRule = conflictRule; } /** * Sets the PC heuristic type. Default = NONE. * * @param pcHeuristicType The type. * @see edu.cmu.tetrad.search.utils.PcCommon.PcHeuristicType */ public void setPcHeuristicType(PcCommon.PcHeuristicType pcHeuristicType) { this.pcHeuristicType = pcHeuristicType; } private void logTriples() { TetradLogger.getInstance().log("info", "\nCollider triples:"); for (Triple triple : this.colliderTriples) { TetradLogger.getInstance().log("info", "Collider: " + triple); } TetradLogger.getInstance().log("info", "\nNoncollider triples:"); for (Triple triple : this.noncolliderTriples) { TetradLogger.getInstance().log("info", "Noncollider: " + triple); } TetradLogger.getInstance().log("info", "\nAmbiguous triples (i.e. list of triples for which " + "\nthere is ambiguous data about whether they are colliders or not):"); for (Triple triple : getAmbiguousTriples()) { TetradLogger.getInstance().log("info", "Ambiguous: " + triple); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy