Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
///////////////////////////////////////////////////////////////////////////////
// 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.work_in_progress;
import edu.cmu.tetrad.data.Knowledge;
import edu.cmu.tetrad.graph.*;
import edu.cmu.tetrad.search.IndependenceTest;
import edu.cmu.tetrad.util.ChoiceGenerator;
import edu.cmu.tetrad.util.TetradLogger;
import java.util.*;
/**
* Implements the "fast adjacency search" used in several causal algorithm in this package. In the fast adjacency
* search, at a given stage of the search, an edge X*-*Y is removed from the graph if X _||_ Y | S, where S is a subset
* of size d either of adj(X) or of adj(Y), where d is the depth of the search. The fast adjacency search performs this
* procedure for each pair of adjacent edges in the graph and for each depth d = 0, 1, 2, ..., d1, where d1 is either
* the maximum depth or else the first such depth at which no edges can be removed. The interpretation of this adjacency
* search is different for different algorithm, depending on the assumptions of the algorithm. A mapping from {x, y} to
* S({x, y}) is returned for edges x *-* y that have been removed.
*
* @author josephramsey.
*/
public class VcFas {
/**
* The search graph. It is assumed going in that all of the true adjacencies of x are in this graph for every node
* x. It is hoped (i.e. true in the large sample limit) that true adjacencies are never removed.
*/
private final Graph graph;
/**
* The independence test. This should be appropriate to the types
*/
private final IndependenceTest test;
/**
* The logger, by default the empty logger.
*/
private final TetradLogger logger = TetradLogger.getInstance();
private final Map> apparentlyNonadjacencies = new HashMap<>();
/**
* Specification of which edges are forbidden or required.
*/
private Knowledge knowledge = new Knowledge();
/**
* The maximum number of variables conditioned on in any conditional independence test. If the depth is -1, it will
* be taken to be the maximum value, which is 1000. Otherwise, it should be set to a non-negative integer.
*/
private int depth = 1000;
/**
* The number of independence tests.
*/
private int numIndependenceTests;
/**
* The depth 0 graph, specified initially.
*/
private Graph externalGraph;
/**
* True iff verbose output should be printed.
*/
private boolean verbose;
//==========================CONSTRUCTORS=============================//
public VcFas(IndependenceTest test) {
this.graph = new EdgeListGraph(test.getVariables());
this.test = test;
}
//==========================PUBLIC METHODS===========================//
/**
* Discovers all adjacencies in data. The procedure is to remove edges in the graph which connect pairs of
* variables which are independent conditional on some other set of variables in the graph (the "sepset"). These are
* removed in tiers. First, edges which are independent conditional on zero other variables are removed, then edges
* which are independent conditional on one other variable are removed, then two, then three, and so on, until no
* more edges can be removed from the graph. The edges which remain in the graph after this procedure are the
* adjacencies in the data.
*
* @return a SepSet, which indicates which variables are independent conditional on which other variables
*/
public Graph search() {
this.logger.log("info", "Starting Fast Adjacency Search.");
this.graph.removeEdges(this.graph.getEdges());
// sepset = new SepsetMap();
int _depth = this.depth;
if (_depth == -1) {
_depth = 1000;
}
Map> adjacencies = new HashMap<>();
List nodes = this.graph.getNodes();
for (Node node : nodes) {
adjacencies.put(node, new TreeSet<>());
}
for (int d = 0; d <= _depth; d++) {
boolean more;
if (d == 0) {
more = searchAtDepth0(nodes, this.test, adjacencies);
} else {
more = searchAtDepth(nodes, this.test, adjacencies, d);
}
if (!more) {
break;
}
}
// System.out.println("Finished with search, constructing Graph...");
for (int i = 0; i < nodes.size(); i++) {
for (int j = i + 1; j < nodes.size(); j++) {
Node x = nodes.get(i);
Node y = nodes.get(j);
if (adjacencies.get(x).contains(y)) {
this.graph.addUndirectedEdge(x, y);
}
}
}
// System.out.println("Finished constructing Graph.");
this.logger.log("info", "Finishing Fast Adjacency Search.");
return this.graph;
}
public int getDepth() {
return this.depth;
}
public void setDepth(int depth) {
if (depth < -1) {
throw new IllegalArgumentException(
"Depth must be -1 (unlimited) or >= 0.");
}
this.depth = depth;
}
public Knowledge getKnowledge() {
return this.knowledge;
}
public void setKnowledge(Knowledge knowledge) {
if (knowledge == null) {
throw new NullPointerException("Cannot set knowledge to null");
}
this.knowledge = knowledge;
}
//==============================PRIVATE METHODS======================/
private boolean searchAtDepth0(List nodes, IndependenceTest test, Map> adjacencies) {
Set empty = Collections.emptySet();
for (int i = 0; i < nodes.size(); i++) {
if ((i + 1) % 100 == 0) System.out.println("Node # " + (i + 1));
Node x = nodes.get(i);
for (int j = i + 1; j < nodes.size(); j++) {
Node y = nodes.get(j);
if (this.externalGraph != null) {
Node x2 = this.externalGraph.getNode(x.getName());
Node y2 = this.externalGraph.getNode(y.getName());
if (!this.externalGraph.isAdjacentTo(x2, y2)) {
continue;
}
}
boolean independent;
try {
this.numIndependenceTests++;
independent = test.checkIndependence(x, y, empty).isIndependent();
} catch (Exception e) {
e.printStackTrace();
independent = false;
}
boolean noEdgeRequired =
this.knowledge.noEdgeRequired(x.getName(), y.getName());
if (independent && noEdgeRequired) {
getApparentlyNonadjacencies().put(Edges.undirectedEdge(x, y), empty);
} else if (!forbiddenEdge(x, y)) {
adjacencies.get(x).add(y);
adjacencies.get(y).add(x);
}
}
}
return freeDegree(nodes, adjacencies) > 0;
}
private int freeDegree(List nodes, Map> adjacencies) {
int max = 0;
for (Node x : nodes) {
Set opposites = adjacencies.get(x);
for (Node y : opposites) {
Set adjx = new HashSet<>(opposites);
adjx.remove(y);
if (adjx.size() > max) {
max = adjx.size();
}
}
}
return max;
}
private boolean forbiddenEdge(Node x, Node y) {
String name1 = x.getName();
String name2 = y.getName();
if (this.knowledge.isForbidden(name1, name2) &&
this.knowledge.isForbidden(name2, name1)) {
this.logger.log("edgeRemoved", "Removed " + Edges.undirectedEdge(x, y) + " because it was " +
"forbidden by background knowledge.");
return true;
}
return false;
}
private boolean searchAtDepth(List nodes, IndependenceTest test, Map> adjacencies, int depth) {
int count = 0;
for (Node x : nodes) {
if (++count % 100 == 0) System.out.println("count " + count + " of " + nodes.size());
List adjx = new ArrayList<>(adjacencies.get(x));
EDGE:
for (Node y : adjx) {
List _adjx = new ArrayList<>(adjacencies.get(x));
_adjx.remove(y);
List ppx = possibleParents(x, _adjx, this.knowledge);
if (ppx.size() >= depth) {
ChoiceGenerator cg = new ChoiceGenerator(ppx.size(), depth);
int[] choice;
while ((choice = cg.next()) != null) {
Set condSet = GraphUtils.asSet(choice, ppx);
boolean independent;
try {
this.numIndependenceTests++;
independent = test.checkIndependence(x, y, condSet).isIndependent();
} catch (Exception e) {
independent = false;
}
boolean noEdgeRequired =
this.knowledge.noEdgeRequired(x.getName(), y.getName());
if (independent && noEdgeRequired) {
adjacencies.get(x).remove(y);
adjacencies.get(y).remove(x);
getApparentlyNonadjacencies().put(Edges.undirectedEdge(x, y), condSet);
continue EDGE;
}
}
}
}
}
return freeDegree(nodes, adjacencies) > depth;
}
private List possibleParents(Node x, List adjx,
Knowledge knowledge) {
List possibleParents = new LinkedList<>();
String _x = x.getName();
for (Node z : adjx) {
String _z = z.getName();
if (possibleParentOf(_z, _x, knowledge)) {
possibleParents.add(z);
}
}
return possibleParents;
}
private boolean possibleParentOf(String z, String x, Knowledge knowledge) {
return !knowledge.isForbidden(z, x) && !knowledge.isRequired(x, z);
}
public int getNumIndependenceTests() {
return this.numIndependenceTests;
}
public Map> getApparentlyNonadjacencies() {
return this.apparentlyNonadjacencies;
}
public void setExternalGraph(Graph externalGraph) {
this.externalGraph = externalGraph;
}
public boolean isVerbose() {
return this.verbose;
}
public void setVerbose(boolean verbose) {
this.verbose = verbose;
}
public List getNodes() {
return this.test.getVariables();
}
}