code: ///////////////////////////////////////////////////////////////////////////////
  // 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 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.IKnowledge;
  import edu.cmu.tetrad.data.Knowledge2;
  import edu.cmu.tetrad.graph.EdgeListGraphSingleConnections;
  import edu.cmu.tetrad.graph.Endpoint;
  import edu.cmu.tetrad.graph.Graph;
  import edu.cmu.tetrad.graph.Node;
  import edu.cmu.tetrad.util.TetradLogger;
  
  import java.util.ArrayList;
  import java.util.List;
  
  
  /**
   * Extends Erin Korber's implementation of the Fast Causal Inference algorithm (found in FCI.java) with Jiji Zhang's
   * Augmented FCI rules (found in sec. 4.1 of Zhang's 2006 PhD dissertation, "Causal Inference and Reasoning in Causally
   * Insufficient Systems").
   * <p/>
   * This class is based off a copy of FCI.java taken from the repository on 2008/12/16, revision 7306. The extension is
   * done by extending doFinalOrientation() with methods for Zhang's rules R5-R10 which implements the augmented search.
   * (By a remark of Zhang's, the rule applications can be staged in this way.)
   * </p>
   * Converts a MAG to a PAG_of_the_true_DAG. (Not well-tested.)
   *
   * @author Erin Korber, June 2004
   * @author Alex Smith, December 2008
   * @author Joseph Ramsey
   * @author Choh-Man Teng
   */
  public final class MagToPag {
  
      private final EdgeListGraphSingleConnections mag;
      private final IndTestDSep dsep;
      /**
       * The PAG_of_the_true_DAG being constructed.
       */
      private Graph graph;
  
      /**
       * The background knowledge.
       */
      private IKnowledge knowledge = new Knowledge2();
  
      /**
       * The variables to search over (optional)
       */
      private List<Node> variables = new ArrayList<>();
  
      /**
       * flag for complete rule set, true if should use complete rule set, false otherwise.
       */
      private boolean completeRuleSetUsed = false;
  
      /**
       * The maximum length for any discriminating path. -1 if unlimited; otherwise, a positive integer.
       */
      private int maxPathLength = -1;
  
      /**
       * The depth for the fast adjacency search.
       */
      private int depth = -1;
  
      /**
       * The logger to use.
       */
      private TetradLogger logger = TetradLogger.getInstance();
  
      /**
       * True iff verbose output should be printed.
       */
      private boolean verbose = false;
  
      //============================CONSTRUCTORS============================//
  
      /**
       * Constructs a new FCI search for the given independence test and background knowledge.
       */
      public MagToPag(Graph mag) {
          this.mag = new EdgeListGraphSingleConnections(mag);
          this.variables.addAll(mag.getNodes());
          this.dsep = new IndTestDSep(mag);
      }
  
      //========================PUBLIC METHODS==========================//
  
      public int getDepth() {
          return depth;
      }
  
      public void setDepth(int depth) {
          if (depth < -1) {
              throw new IllegalArgumentException(
                      "Depth must be -1 (unlimited) or >= 0: " + depth);
          }
  
          this.depth = depth;
      }
  
      public Graph convert() {
          logger.log("info", "Starting DAG to PAG_of_the_true_DAG.");
  
          setMaxPathLength(maxPathLength);
  
          Graph graph = new EdgeListGraphSingleConnections(mag);
          graph.reorientAllWith(Endpoint.CIRCLE);
  
          FciOrient fciOrient = new FciOrient(new DagSepsets(mag));
          fciOrient.setCompleteRuleSetUsed(completeRuleSetUsed);
          return fciOrient.orient(graph);
      }
  
  
      public IKnowledge getKnowledge() {
          return knowledge;
      }
  
      public void setKnowledge(IKnowledge knowledge) {
          if (knowledge == null) {
              throw new NullPointerException();
          }
  
          this.knowledge = knowledge;
      }
  
      /**
       * @return true if Zhang's complete rule set should be used, false if only R1-R4 (the rule set of the original FCI)
       * should be used. False by default.
       */
      public boolean isCompleteRuleSetUsed() {
          return completeRuleSetUsed;
      }
  
      /**
       * @param completeRuleSetUsed set to true if Zhang's complete rule set should be used, false if only R1-R4 (the rule
       *                            set of the original FCI) should be used. False by default.
       */
      public void setCompleteRuleSetUsed(boolean completeRuleSetUsed) {
          this.completeRuleSetUsed = completeRuleSetUsed;
      }
  
      public void setMaxPathLength(int maxPathLength) {
          if (maxPathLength < -1) {
              throw new IllegalArgumentException("Max path length must be -1 (unlimited) or >= 0: " + maxPathLength);
          }
  
          this.maxPathLength = maxPathLength == -1
                  ? Integer.MAX_VALUE : maxPathLength;
      }
  
      /**
       * True iff verbose output should be printed.
       */
      public boolean isVerbose() {
          return verbose;
      }
  
      public void setVerbose(boolean verbose) {
          this.verbose = verbose;
      }
  
  }
  
  
  
  
  