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.tetradapp.session;
import edu.cmu.tetrad.graph.Node;
import edu.cmu.tetrad.graph.NodeType;
import edu.cmu.tetrad.graph.NodeVariableType;
import edu.cmu.tetrad.util.*;
import javax.swing.*;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serial;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.rmi.MarshalledObject;
import java.util.*;
/**
*
* Represents a node in a session for a model in a particular class. The sets of possible model classes for this node
* are given in the constructors of the model classes for the node. Parents (also SessionNodes) may be added to this
* node provided some combination of the parents' model classes serves a partial argument set to some constructor of the
* one of this node's model classes. To put it slightly differently, parents can be added to this node one at a time,
* though at any step along the way it ought to be possible (perhaps by adding more parent nodes) to use the parent
* models to construct a model of one of the legal types for this node.> 0
*
* To retrieve the list of classes for which models may be created, call the getConsistentModelClasses
* . To construct a model for a particular model choice, call
* createModel method for the desired class. If the model has a
* parameterizing object, this object may be passed in using the
* createParameterizedModel method. For parameterized models, the
* model object is treated simply as an additional parent to the model and therefore must appear as an argument to one
* of the constructors of the model.> 0
*
* This node keeps track of its parents and its children and keeps these two sets of SessionNodes in sync.> 0
*
* @author josephramsey
* @version $Id: $Id
* @see Session
* @see SessionListener
* @see SessionAdapter
* @see SessionEvent
*/
public class SessionNode implements Node {
@Serial
private static final long serialVersionUID = 23L;
/**
* A map from model classes to parameter objects.
*/
private final Map paramMap = new HashMap<>();
/**
* The parameters for this node.
*/
private final Parameters parameters = new Parameters();
/**
* The attributes of this node.
*/
private final Map attributes = new HashMap<>();
/**
* The (optional) name of this session node.
*/
private String boxType;
/**
* The display name of the session node.
*/
private String displayName;
/**
* The possible classes this SessionNode can use to construct models.
*/
private Class[] modelClasses;
/**
* The class of the last model created.
*/
private Class lastModelClass;
/**
* When a model is created, we keep a reference to its param types in order to determine, should the need arise,
* whether one of the objects used to create the model has been destroyed.
*/
private Class[] modelParamTypes;
/**
* The model itself. Once this is created, another model cannot be created until this one is explicitly destroyed.
*/
private SessionModel model;
/**
* Stores a reference to the previous model so that information from it can be used to initialize a new model.
*/
private SessionModel oldModel;
/**
* Stores a clone of the model being edited, in case the user wants to cancel.
*/
private transient SessionModel savedModel;
/**
* The set of parents of this node--a Set of SessionNodes. Must be kept in sync with sets of children in the parent
* nodes.
*/
private Set parents = new HashSet<>();
/**
* The set of children of this node--a Set of SessionNodes. Must be kept in sync with sets of parents in the child
* nodes.
*/
private Set children = new HashSet<>();
/**
* True iff the next edge should not be added. (Included for GUI user control.) Reset to true every time an edge is
* added; edge adds must be disallowed individually. To disallow the next edge add, set to false.
*/
private boolean nextEdgeAddAllowed = true;
/**
* The number of times this session node should be executed (in depth first order) in a simulation
* edu.cmu.tetrad.study.
*/
private int repetition = 1;
/**
* Support for firing SessionEvent's.
*/
private transient SessionSupport sessionSupport;
/**
* Handles incoming session events, basically by redirecting to any listeners of this session.
*/
private transient SessionHandler sessionHandler;
/**
* The logger configuration for this node.
*/
private TetradLoggerConfig loggerConfig;
/**
* Node variable type (domain, interventional status, interventional value..) of this node variable
*/
private NodeVariableType nodeVariableType = NodeVariableType.DOMAIN;
private boolean selectionBias;
//==========================CONSTRUCTORS===========================//
/**
* Creates a new session node capable of implementing the given model class.
*
* @param modelClass a {@link java.lang.Class} object
*/
public SessionNode(Class modelClass) {
this("???", modelClass.getName(), new Class[]{modelClass});
}
/**
* Creates a new session node with the given name, capable of implementing the given model class.
*
* @param boxType The name of the box type--for instance, "Graph."
* @param displayName The name of this particular session node. Any non-null string.
* @param modelClass A single model class associated with this session node.
*/
public SessionNode(String boxType, String displayName, Class modelClass) {
this(boxType, displayName, new Class[]{modelClass});
}
/**
* Creates a new session node with the given name capable of implementing the given model classes.
*
* @param modelClasses an array of {@link java.lang.Class} objects
*/
public SessionNode(Class[] modelClasses) {
this("???", "???", modelClasses);
}
/**
* Creates a new session node with the given name capable of implementing the given model classes. When models are
* created, they will be of one of these classes. Reflection will be used to create the models by matching the
* models of the parent Session Nodes to constructor arguments of the class given as argument to the
* createModel method, which must itself be one of these model classes.
*
* @param boxType The name of the box type--for instance, "Graph."
* @param displayName The name of this particular session node. Any non-null string.
* @param modelClasses An array of model classes associated with this session node.
*/
public SessionNode(String boxType, String displayName,
Class[] modelClasses) {
setBoxType(boxType);
setDisplayName(displayName);
if (modelClasses == null) {
throw new NullPointerException();
}
for (int i = 0; i < modelClasses.length; i++) {
if (modelClasses[i] == null) {
throw new NullPointerException(
"Model class null: index + " + i);
}
if (!(SessionModel.class.isAssignableFrom(modelClasses[i]))) {
throw new ClassCastException(
"Model class must implement SessionModel: "
+ modelClasses[i]);
}
}
this.boxType = boxType;
this.displayName = displayName;
this.modelClasses = modelClasses;
// ModificationRegistery.registerModel(this);
}
/**
* Generates a simple exemplar of this class to test serialization.
*
* @return a {@link SessionNode} object
*/
public static SessionNode serializableInstance() {
return new SessionNode(Type1.class);
}
//==========================PUBLIC METHODS============================//
/**
* Adds a parent to this node provided the resulting set of parents taken together provides some combination of
* possible model classes that can be used as a constructor to some one of the model classes for this node.
*
* @param parent a {@link SessionNode} object
* @return a boolean
*/
public boolean addParent(SessionNode parent) {
if (this.parents.contains(parent)) {
return false;
}
if (parent == this) {
return false;
}
// Construct a list of the parents of this node
// (SessionNode's) together with the new putative parent.
List newParents = new ArrayList<>(this.parents);
newParents.add(parent);
for (Class modelClass : this.modelClasses) {
// Put all of the model classes of the nodes into a
// single two-dimensional array. At the same time,
// construct an int[] array containing the number of
// model classes for each node. Use this int[] array
// to construct a generator for all the combinations
// of model nodes.
Class[][] parentClasses = new Class[newParents.size()][];
int[] numModels = new int[newParents.size()];
for (int j = 0; j < newParents.size(); j++) {
SessionNode node = newParents.get(j);
parentClasses[j] = node.getModelClasses();
numModels[j] = parentClasses[j].length;
}
if (isConsistentModelClass(modelClass, parentClasses, false, null)) {
this.parents.add(parent);
parent.addChild(this);
parent.addSessionListener(getSessionHandler());
getSessionSupport().fireParentAdded(parent, this);
return true;
}
}
return false;
}
/**
*
isConsistentParent.
*
* @param parent a {@link SessionNode} object
* @return a boolean
*/
public boolean isConsistentParent(SessionNode parent) {
return isConsistentParent(parent, null);
}
/**
*
isConsistentParent.
*
* @param parent a {@link SessionNode} object
* @param existingNodes a {@link java.util.List} object
* @return a boolean
*/
public boolean isConsistentParent(SessionNode parent, List existingNodes) {
if (this.parents.contains(parent)) {
return false;
}
if (parent == this) {
return false;
}
// Construct a list of the parents of this node
// (SessionNode's) together with the new putative parent.
List newParents = new ArrayList<>(this.parents);
newParents.add(parent);
Class[] thisClass = new Class[1];
if (getModel() != null) {
thisClass[0] = getModel().getClass();
}
for (Class modelClass : getModel() != null ? thisClass : this.modelClasses) {
// Put all of the model classes of the nodes into a
// single two-dimensional array. At the same time,
// construct an int[] array containing the number of
// model classes for each node. Use this int[] array
// to construct a generator for all the combinations
// of model nodes.
Class[][] parentClasses = new Class[newParents.size()][];
for (int j = 0; j < newParents.size(); j++) {
SessionNode node = newParents.get(j);
parentClasses[j] = node.getModelClasses();
}
if (isConsistentModelClass(modelClass, parentClasses, false, existingNodes)) {
return true;
}
}
return false;
}
/**
* Same as addParent except tests if this has already been created. If so the user is asked whether to add parent
* and update parent's desendents or to cancel the operation.
*
* @param parent a {@link SessionNode} object
* @return a boolean
*/
public boolean addParent2(SessionNode parent) {
if (this.parents.contains(parent)) {
return false;
}
if (parent == this) {
return false;
}
// Construct a list of the parents of this node
// (SessionNode's) together with the new putative parent.
List newParents = new ArrayList<>(this.parents);
newParents.add(parent);
for (Class modelClass : this.modelClasses) {
// Put all of the model classes of the nodes into a
// single two-dimensional array. At the same time,
// construct an int[] array containing the number of
// model classes for each node. Use this int[] array
// to construct a generator for all the combinations
// of model nodes.
Class[][] parentClasses = new Class[newParents.size()][];
int[] numModels = new int[newParents.size()];
for (int j = 0; j < newParents.size(); j++) {
SessionNode node = newParents.get(j);
parentClasses[j] = node.getModelClasses();
numModels[j] = parentClasses[j].length;
}
if (isConsistentModelClass(modelClass, parentClasses, false, null)) {
if (this.getModel() == null) {
this.parents.add(parent);
parent.addChild(this);
parent.addSessionListener(getSessionHandler());
getSessionSupport().fireParentAdded(parent, this);
return true;
} else {
// Allows nextEdgeAllowed to be set to false if the next
// edge should not be added.
this.sessionSupport.fireAddingEdge();
if (isNextEdgeAddAllowed()) {
// Must reset nextEdgeAllowed to true.
setNextEdgeAddAllowed(true);
this.parents.add(parent);
parent.addChild(this);
parent.addSessionListener(getSessionHandler());
getSessionSupport().fireParentAdded(parent, this);
// Destroys model & downstream models.
destroyModel();
return true;
} else {
return false;
}
}
}
}
return false;
}
/**
* Removes a parent from the node.
*
* @param parent a {@link SessionNode} object
* @return a boolean
*/
public boolean removeParent(SessionNode parent) {
if (this.parents.contains(parent)) {
this.parents.remove(parent);
parent.removeChild(this);
parent.removeSessionListener(getSessionHandler());
getSessionSupport().fireParentRemoved(parent, this);
return true;
}
return false;
}
/**
*
Getter for the field parents.
*
* @return the set of parents.
*/
public Set getParents() {
return new HashSet<>(this.parents);
}
/**
*
getNumParents.
*
* @return the number of parents.
*/
public int getNumParents() {
return this.parents.size();
}
/**
* Adds a child to the node, provided this node can be added as a parent to the child node.
*
* @param child a {@link SessionNode} object
* @return a boolean
*/
public boolean addChild(SessionNode child) {
if (!this.children.contains(child)) {
child.addParent(this);
if (child.containsParent(this)) {
this.children.add(child);
return true;
}
}
return false;
}
/**
*
containsChild.
*
* @param child a {@link SessionNode} object
* @return true iff the given node is child of this node.
*/
public boolean containsChild(SessionNode child) {
return this.children.contains(child);
}
/**
* Removes a child from the node.
*
* @param child a {@link SessionNode} object
* @return a boolean
*/
public boolean removeChild(SessionNode child) {
if (this.children.contains(child)) {
child.removeParent(this);
if (!child.containsParent(this)) {
this.children.remove(child);
return true;
}
}
return false;
}
/**
*
Getter for the field children.
*
* @return the set of children.
*/
public Set getChildren() {
return new HashSet<>(this.children);
}
/**
*
getNumChildren.
*
* @return the number of children.
*/
public int getNumChildren() {
return this.children.size();
}
/**
* Creates a model, provided the class of the model can be uniquely determined without any further hints. If a model
* was created previously, the previous model class is used. If there is only one consistent model class, than that
* model class is used. Otherwise, an exception is thrown.
*
* @param simulation a boolean
* @return true iff this node contains a model when this method completes.
* @throws java.lang.RuntimeException if the model could not be created.
*/
public boolean createModel(boolean simulation) {
if (getModel() == null) {
if (this.lastModelClass != null) {
try {
createModel(this.lastModelClass, simulation);
} catch (Exception e) {
// Allows creation of models downstream to continue
// once BayesPM is changed to SemPm... jdramsey 3/30/2005
getSessionSupport().fireModelUnclear(this);
}
} else {
getSessionSupport().fireModelUnclear(this);
}
}
return getModel() != null;
}
/**
* Creates a model based on the specified model class and simulation flag.
*
* @param modelClass the class representing the model to be created
* @param simulation a flag indicating if the model should be created for simulation
* @throws Exception if the model class is not among the possible model classes or if the model cannot be created
*/
public void createModel(Class> modelClass, boolean simulation)
throws Exception {
if (!Arrays.asList(this.modelClasses).contains(modelClass)) {
throw new IllegalArgumentException("Class not among possible "
+ "model classes: " + modelClass);
}
this.loggerConfig = getLoggerConfig(modelClass);
TetradLogger.getInstance().setTetradLoggerConfig(this.loggerConfig);
String message1 = "\n========LOGGING " + getDisplayName()
+ "\n";
TetradLogger.getInstance().log(message1);
// Collect up the parentModels from the parents. If any model is
// null, throw an exception.
List