diff --git a/data-reader/pom.xml b/data-reader/pom.xml index b18df6845f..696dd77b99 100644 --- a/data-reader/pom.xml +++ b/data-reader/pom.xml @@ -5,7 +5,7 @@ io.github.cmu-phil tetrad - 7.6.1 + 7.6.2-SNAPSHOT data-reader @@ -13,8 +13,8 @@ UTF-8 - 1.8 - 1.8 + 17 + 17 @@ -24,8 +24,8 @@ maven-compiler-plugin 3.11.0 - 1.8 - 1.8 + 17 + 17 diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/ContinuousData.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/ContinuousData.java index ac78ff2ba3..47e19a5c5b 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/ContinuousData.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/ContinuousData.java @@ -25,8 +25,18 @@ */ public interface ContinuousData extends Data { + /** + * Get the data columns. + * + * @return the data columns. + */ DataColumn[] getDataColumns(); + /** + * Get the data. + * + * @return the data. + */ double[][] getData(); } diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/DataColumn.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/DataColumn.java index 93e4367813..c8759b5b59 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/DataColumn.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/DataColumn.java @@ -28,35 +28,35 @@ public interface DataColumn { /** * Get the column's name. * - * @return + * @return the column's name. */ String getName(); /** * Get the column's number. * - * @return + * @return the column's number. */ int getColumnNumber(); /** * True if this column was not read in from source such as file. * - * @return + * @return true if this column was not read in from source such as file. */ boolean isGenerated(); /** * True if the datatype is discrete. * - * @return + * @return true if the datatype is discrete. */ boolean isDiscrete(); /** * Set true for discrete datatype. * - * @param discrete + * @param discrete true for discrete datatype. */ void setDiscrete(boolean discrete); diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/DataColumns.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/DataColumns.java index 13470ed23f..c9ddc90fdc 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/DataColumns.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/DataColumns.java @@ -38,6 +38,13 @@ public final class DataColumns { private DataColumns() { } + /** + * Update data columns with metadata. + * + * @param dataColumns data columns + * @param metadata metadata + * @return updated data columns + */ public static DataColumn[] update(DataColumn[] dataColumns, Metadata metadata) { Map columnMetadataMap = DataColumns.getColumnMetadataMap(metadata); diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/DataFileReader.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/DataFileReader.java index 84bd8fdfae..1c8dc2a12e 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/DataFileReader.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/DataFileReader.java @@ -31,16 +31,52 @@ */ public abstract class DataFileReader implements DataReader { + /** + * The buffer size for reading data file. + */ protected static final int BUFFER_SIZE = 1024 * 1024; + /** + * The newline character. + */ protected static final byte LINE_FEED = '\n'; + + /** + * The carriage return character. + */ protected static final byte CARRIAGE_RETURN = '\r'; + + /** + * The space character. + */ protected static final byte SPACE_CHAR = Delimiter.SPACE.getByteValue(); + + /** + * The data file. + */ protected final Path dataFile; + + /** + * The delimiter. + */ protected final Delimiter delimiter; + + /** + * The quote character. + */ protected byte quoteCharacter; + + /** + * The comment marker. + */ protected String commentMarker; + /** + * Constructor. + * + * @param dataFile the data file + * @param delimiter the delimiter + */ public DataFileReader(Path dataFile, Delimiter delimiter) { this.dataFile = dataFile; this.delimiter = delimiter; @@ -52,7 +88,7 @@ public DataFileReader(Path dataFile, Delimiter delimiter) { * Counts number of column from the first non-blank line. * * @return the number of column from the first non-blank line - * @throws IOException + * @throws IOException if an I/O error occurs */ protected int countNumberOfColumns() throws IOException { int count = 0; @@ -148,7 +184,7 @@ protected int countNumberOfColumns() throws IOException { * Counts number of non-blank lines. * * @return the number of non-blank and non-commented lines - * @throws IOException + * @throws IOException if an I/O error occurs */ protected int countNumberOfLines() throws IOException { int count = 0; @@ -214,6 +250,11 @@ protected int countNumberOfLines() throws IOException { return count; } + /** + * Sets the quote character. + * + * @param quoteCharacter the quote character + */ @Override public void setQuoteCharacter(char quoteCharacter) { this.quoteCharacter = Character.isDefined(quoteCharacter) @@ -221,6 +262,11 @@ public void setQuoteCharacter(char quoteCharacter) { : (byte) -1; } + /** + * Sets the comment marker. + * + * @param commentMarker the comment marker + */ @Override public void setCommentMarker(String commentMarker) { this.commentMarker = (commentMarker == null) diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/DataReader.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/DataReader.java index eca120b5b5..010c999fe8 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/DataReader.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/DataReader.java @@ -28,14 +28,14 @@ public interface DataReader { /** * Set the character that is used to group multiple words as one. * - * @param quoteCharacter + * @param quoteCharacter the quote character. */ void setQuoteCharacter(char quoteCharacter); /** * Set the value to indicate a line is a comment to be ignored. * - * @param commentMarker + * @param commentMarker the comment marker. */ void setCommentMarker(String commentMarker); diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/DataReaderException.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/DataReaderException.java index 97ab03732f..8750ca886b 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/DataReaderException.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/DataReaderException.java @@ -18,6 +18,8 @@ */ package edu.pitt.dbmi.data.reader; +import java.io.Serial; + /** * Nov 6, 2018 2:26:59 PM * @@ -25,6 +27,7 @@ */ public class DataReaderException extends RuntimeException { + @Serial private static final long serialVersionUID = 1123054334542973950L; /** diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/DatasetFileReader.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/DatasetFileReader.java index fe451b58ce..44d64b2372 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/DatasetFileReader.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/DatasetFileReader.java @@ -27,14 +27,28 @@ */ public abstract class DatasetFileReader extends DataFileReader implements DatasetReader { + /** + * The missing data marker. + */ protected String missingDataMarker; + /** + * Constructor. + * + * @param dataFile the data file + * @param delimiter the delimiter + */ public DatasetFileReader(Path dataFile, Delimiter delimiter) { super(dataFile, delimiter); this.missingDataMarker = ""; } + /** + * Get the missing data marker. + * + * @param missingDataMarker the missing data marker + */ @Override public void setMissingDataMarker(String missingDataMarker) { this.missingDataMarker = (missingDataMarker == null) diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/DatasetReader.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/DatasetReader.java index dd3d1cf3a1..a74daf92dc 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/DatasetReader.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/DatasetReader.java @@ -25,14 +25,20 @@ */ public interface DatasetReader extends DataReader { + /** + * The missing data marker for continuous data. + */ double CONTINUOUS_MISSING_VALUE = Double.NaN; + /** + * The missing data marker for discrete data. + */ int DISCRETE_MISSING_VALUE = -99; /** * Set the value to indicate missing data. * - * @param missingDataMarker + * @param missingDataMarker the missing data marker. */ void setMissingDataMarker(String missingDataMarker); diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/Delimiter.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/Delimiter.java index 7f38b8159e..fae0c50f5b 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/Delimiter.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/Delimiter.java @@ -25,32 +25,80 @@ */ public enum Delimiter { + /** + * The tab delimiter. + */ TAB("tab", '\t'), + + /** + * The space delimiter. + */ SPACE("space", ' '), + + /** + * The whitespace delimiter. + */ WHITESPACE("whitespace", ' '), + + /** + * The comma delimiter. + */ COMMA("comma", ','), + + /** + * The colon delimiter. + */ COLON("colon", ':'), + + /** + * The semicolon delimiter. + */ SEMICOLON("semicolon", ';'), + + /** + * The pipe delimiter. + */ PIPE("pipe", '|'); private final String name; private final char value; private final byte byteValue; + /** + * Constructor. + * + * @param name the name of the delimiter. + * @param value the value of the delimiter. + */ Delimiter(String name, char value) { this.name = name; this.value = value; this.byteValue = (byte) value; } + /** + * Get the name of the delimiter. + * + * @return the name of the delimiter. + */ public String getName() { return this.name; } + /** + * Get the value of the delimiter. + * + * @return the value of the delimiter. + */ public char getValue() { return this.value; } + /** + * Get the byte value of the delimiter. + * + * @return the byte value of the delimiter. + */ public byte getByteValue() { return this.byteValue; } diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/DiscreteData.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/DiscreteData.java index e2ca7bbeb8..8fa7fb3074 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/DiscreteData.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/DiscreteData.java @@ -25,8 +25,18 @@ */ public interface DiscreteData extends Data { + /** + * Get the discrete data columns. + * + * @return the discrete data columns. + */ DiscreteDataColumn[] getDataColumns(); + /** + * Get the discrete data. + * + * @return the discrete data. + */ int[][] getData(); } diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/DiscreteDataColumn.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/DiscreteDataColumn.java index 4f496e66c9..6b3e56a2f0 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/DiscreteDataColumn.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/DiscreteDataColumn.java @@ -27,14 +27,38 @@ */ public interface DiscreteDataColumn { + /** + * Get the encode value. + * + * @param value the value. + * @return the encode value. + */ Integer getEncodeValue(String value); + /** + * Recategorize the data. + */ void recategorize(); + /** + * Get the categories. + * + * @return the categories. + */ List getCategories(); + /** + * Get the data column. + * + * @return the data column. + */ DataColumn getDataColumn(); + /** + * Set the value. + * + * @param value the value. + */ void setValue(String value); } diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/MixedData.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/MixedData.java index 0d160d8cc1..463a59fdf9 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/MixedData.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/MixedData.java @@ -25,12 +25,32 @@ */ public interface MixedData extends Data { + /** + * Get the number of rows. + * + * @return the number of rows. + */ int getNumOfRows(); + /** + * Get the data columns. + * + * @return the data columns. + */ DiscreteDataColumn[] getDataColumns(); + /** + * Get the continuous data. + * + * @return the continuous data. + */ double[][] getContinuousData(); + /** + * Get the discrete data. + * + * @return the discrete data. + */ int[][] getDiscreteData(); } diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/covariance/CovarianceData.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/covariance/CovarianceData.java index 205c80833f..19cd379949 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/covariance/CovarianceData.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/covariance/CovarianceData.java @@ -29,10 +29,19 @@ */ public interface CovarianceData extends Data { + /** + * @return the number of cases in the data. + */ int getNumberOfCases(); + /** + * @return the number of variables in the data. + */ List getVariables(); + /** + * @return the data in a 2D array. + */ double[][] getData(); } diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/covariance/CovarianceDataReader.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/covariance/CovarianceDataReader.java index 13418c4582..81b6cc3bc6 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/covariance/CovarianceDataReader.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/covariance/CovarianceDataReader.java @@ -29,6 +29,12 @@ */ public interface CovarianceDataReader extends DataReader { + /** + * Reads in the covariance data. + * + * @return the covariance data. + * @throws IOException if an I/O error occurs. + */ CovarianceData readInData() throws IOException; } diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/covariance/LowerCovarianceDataFileReader.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/covariance/LowerCovarianceDataFileReader.java index a418bf6783..c08a072884 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/covariance/LowerCovarianceDataFileReader.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/covariance/LowerCovarianceDataFileReader.java @@ -37,12 +37,22 @@ */ public class LowerCovarianceDataFileReader extends DataFileReader implements CovarianceDataReader { -// private static final Logger LOGGER = LoggerFactory.getLogger(LowerCovarianceDataFileReader.class); - + /** + * Constructs a lower triangular covariance data file reader. + * + * @param dataFile the data file. + * @param delimiter the delimiter. + */ public LowerCovarianceDataFileReader(Path dataFile, Delimiter delimiter) { super(dataFile, delimiter); } + /** + * Reads in the covariance data. + * + * @return the covariance data. + * @throws IOException if an I/O error occurs. + */ @Override public CovarianceData readInData() throws IOException { int numOfCases = getNumberOfCases(); @@ -513,21 +523,28 @@ private LowerCovarianceData(int numberOfCases, List variables, double[][ this.data = data; } + /** + * @return the number of cases in the data. + */ @Override public int getNumberOfCases() { return this.numberOfCases; } + /** + * @return the number of variables in the data. + */ @Override public List getVariables() { return this.variables; } + /** + * @return the data in a 2D array. + */ @Override public double[][] getData() { return this.data; } - } - } diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/metadata/ColumnMetadata.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/metadata/ColumnMetadata.java index b7f165acae..b925b3d7ad 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/metadata/ColumnMetadata.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/metadata/ColumnMetadata.java @@ -27,53 +27,113 @@ */ public class ColumnMetadata { + /** + * The name of the column. + */ private String name; + /** + * Indicates whether the column is discrete. + */ private boolean discrete; + /** + * The column number. + */ @JsonIgnore private int columnNumber; + /** + * Default constructor. + */ public ColumnMetadata() { this.discrete = true; } + /** + * Constructor. + * + * @param name the name of the column. + * @param discrete indicates whether the column is discrete. + */ public ColumnMetadata(String name, boolean discrete) { this.name = name; this.discrete = discrete; } + /** + * Constructor. + * + * @param name the name of the column. + * @param columnNumber the column number. + * @param discrete indicates whether the column is discrete. + */ public ColumnMetadata(String name, int columnNumber, boolean discrete) { this.name = name; this.columnNumber = columnNumber; this.discrete = discrete; } + /** + * Return a string representation of the column metadata. + * + * @return a string representation of the column metadata. + */ @Override public String toString() { return "ColumnMetadata{" + "name=" + this.name + ", discrete=" + this.discrete + ", columnNumber=" + this.columnNumber + '}'; } + /** + * Return the name of the column. + * + * @return the name of the column. + */ public String getName() { return this.name; } + /** + * Set the name of the column. + * + * @param name the name of the column. + */ public void setName(String name) { this.name = name; } + /** + * Return whether the column is discrete. + * + * @return whether the column is discrete. + */ public boolean isDiscrete() { return this.discrete; } + /** + * Set whether the column is discrete. + * + * @param discrete whether the column is discrete. + */ public void setDiscrete(boolean discrete) { this.discrete = discrete; } + /** + * Return the column number. + * + * @return the column number. + */ public int getColumnNumber() { return this.columnNumber; } + /** + * Set the column number. + * + * @param columnNumber the column number. + */ public void setColumnNumber(int columnNumber) { this.columnNumber = columnNumber; } diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/metadata/InterventionalColumn.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/metadata/InterventionalColumn.java index b437402a58..aebfc66993 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/metadata/InterventionalColumn.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/metadata/InterventionalColumn.java @@ -33,31 +33,65 @@ public class InterventionalColumn { @JsonProperty("status") private ColumnMetadata statusColumn; + /** + * Default constructor. + */ public InterventionalColumn() { } + /** + * Constructor. + * + * @param valueColumn The value column. + * @param statusColumn The status column. + */ public InterventionalColumn(ColumnMetadata valueColumn, ColumnMetadata statusColumn) { this.valueColumn = valueColumn; this.statusColumn = statusColumn; } + /** + * Returns a string representation of this object. + * + * @return a string representation of this object. + */ @Override public String toString() { return "InterventionalColumn{" + "valueColumn=" + this.valueColumn + ", statusColumn=" + this.statusColumn + '}'; } + /** + * Returns the value column. + * + * @return the value column. + */ public ColumnMetadata getValueColumn() { return this.valueColumn; } + /** + * Sets the value column. + * + * @param valueColumn the value column. + */ public void setValueColumn(ColumnMetadata valueColumn) { this.valueColumn = valueColumn; } + /** + * Returns the status column. + * + * @return the status column. + */ public ColumnMetadata getStatusColumn() { return this.statusColumn; } + /** + * Sets the status column. + * + * @param statusColumn the status column. + */ public void setStatusColumn(ColumnMetadata statusColumn) { this.statusColumn = statusColumn; } diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/metadata/Metadata.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/metadata/Metadata.java index 9f888ce669..dd268afcfa 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/metadata/Metadata.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/metadata/Metadata.java @@ -36,9 +36,18 @@ public class Metadata { @JsonProperty("interventions") private List interventionalColumns = new LinkedList<>(); + /** + * Default constructor. + */ public Metadata() { } + /** + * Constructor. + * + * @param domainColumnns The domain columns. + * @param interventionalColumns The interventional columns. + */ public Metadata(List domainColumnns, List interventionalColumns) { if (domainColumnns != null) { this.domainColumnns.addAll(domainColumnns); @@ -48,25 +57,49 @@ public Metadata(List domainColumnns, List } } + /** + * Returns a string representation of this object. + * + * @return a string representation of this object. + */ @Override public String toString() { return "Metadata{" + "domainColumnns=" + this.domainColumnns + ", interventionalColumns=" + this.interventionalColumns + '}'; } + /** + * Returns the domain columns. + * + * @return the domain columns. + */ public List getDomainColumnns() { return this.domainColumnns; } + /** + * Sets the domain columns. + * + * @param domainColumnns the domain columns. + */ public void setDomainColumnns(List domainColumnns) { this.domainColumnns = domainColumnns; } + /** + * Returns the interventional columns. + * + * @return the interventional columns. + */ public List getInterventionalColumns() { return this.interventionalColumns; } + /** + * Sets the interventional columns. + * + * @param interventionalColumns the interventional columns. + */ public void setInterventionalColumns(List interventionalColumns) { this.interventionalColumns = interventionalColumns; } - } diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/metadata/MetadataFileReader.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/metadata/MetadataFileReader.java index bfb1e7ccf4..6e275dd59f 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/metadata/MetadataFileReader.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/metadata/MetadataFileReader.java @@ -32,12 +32,26 @@ */ public class MetadataFileReader implements MetadataReader { + /** + * The metadata file. + */ protected final Path metadataFile; + /** + * Constructor. + * + * @param metadataFile The metadata file. + */ public MetadataFileReader(Path metadataFile) { this.metadataFile = metadataFile; } + /** + * Reads in the metadata. + * + * @return the metadata. + * @throws IOException if an I/O error occurs. + */ @Override public Metadata read() throws IOException { try (BufferedReader reader = Files.newBufferedReader(this.metadataFile)) { diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/metadata/MetadataFileWriter.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/metadata/MetadataFileWriter.java index cc34664e7d..ab123207f5 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/metadata/MetadataFileWriter.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/metadata/MetadataFileWriter.java @@ -34,6 +34,13 @@ */ public class MetadataFileWriter implements MetadataWriter { + /** + * Writes the metadata as a string. + * + * @param metadata The metadata. + * @return the metadata as a string. + * @throws JsonProcessingException if an error occurs while processing the JSON. + */ @Override public String writeAsString(Metadata metadata) throws JsonProcessingException { return new ObjectMapper() @@ -42,6 +49,13 @@ public String writeAsString(Metadata metadata) throws JsonProcessingException { .writeValueAsString(metadata); } + /** + * Writes the metadata to a file. + * + * @param metadata The metadata. + * @param outputFile The output file. + * @throws IOException if an I/O error occurs. + */ @Override public void write(Metadata metadata, Path outputFile) throws IOException { ObjectWriter writer = new ObjectMapper().writer().withDefaultPrettyPrinter(); @@ -53,5 +67,4 @@ public void write(Metadata metadata, Path outputFile) throws IOException { Files.write(outputFile, writer.writeValueAsBytes(metadata), StandardOpenOption.CREATE); } } - } diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/metadata/MetadataReader.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/metadata/MetadataReader.java index e4b8a3cee9..5a09df5570 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/metadata/MetadataReader.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/metadata/MetadataReader.java @@ -27,6 +27,12 @@ */ public interface MetadataReader { + /** + * Reads in the metadata. + * + * @return the metadata. + * @throws IOException if an I/O error occurs. + */ Metadata read() throws IOException; } diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/metadata/MetadataWriter.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/metadata/MetadataWriter.java index b5614f333a..431d3244dc 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/metadata/MetadataWriter.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/metadata/MetadataWriter.java @@ -30,8 +30,22 @@ */ public interface MetadataWriter { + /** + * Writes the metadata as a string. + * + * @param metadata The metadata. + * @return the metadata as a string. + * @throws JsonProcessingException if an error occurs while processing the JSON. + */ String writeAsString(Metadata metadata) throws JsonProcessingException; + /** + * Writes the metadata to the output file. + * + * @param metadata The metadata. + * @param outputFile The output file. + * @throws IOException if an error occurs while writing the metadata. + */ void write(Metadata metadata, Path outputFile) throws IOException; } diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/preview/AbstractDataPreviewer.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/preview/AbstractDataPreviewer.java index 391bce36f5..39ca3f13a6 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/preview/AbstractDataPreviewer.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/preview/AbstractDataPreviewer.java @@ -27,23 +27,52 @@ */ public abstract class AbstractDataPreviewer { + /** + * The line feed character. + */ protected static final byte LINE_FEED = '\n'; + + /** + * The carriage return character. + */ protected static final byte CARRIAGE_RETURN = '\r'; + /** + * The ellipsis character. + */ protected static final String ELLIPSIS = "..."; + /** + * The data file. + */ protected final Path dataFile; + /** + * Constructor. + * + * @param dataFile The data file. + */ public AbstractDataPreviewer(Path dataFile) { this.dataFile = dataFile; } + /** + * Check the number of characters parameter. + * + * @param numOfCharacters The number of characters. + */ protected void checkCharacterNumberParameter(int numOfCharacters) { if (numOfCharacters < 0) { throw new IllegalArgumentException("Parameter numOfCharacters must be positive integer."); } } + /** + * Check the line number parameters. + * + * @param fromLine The starting line number. + * @param toLine The ending line number. + */ protected void checkLineNumberParameter(int fromLine, int toLine) { if (fromLine < 0) { throw new IllegalArgumentException("Parameter fromLine must be positive integer."); diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/preview/BasicDataPreviewer.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/preview/BasicDataPreviewer.java index d1b9efdfc8..b86c196e0a 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/preview/BasicDataPreviewer.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/preview/BasicDataPreviewer.java @@ -38,14 +38,26 @@ */ public class BasicDataPreviewer extends AbstractDataPreviewer implements DataPreviewer { -// private static final Logger LOGGER = LoggerFactory.getLogger(BasicDataPreviewer.class); - + /** + * Constructor. + * + * @param dataFile The data file. + */ public BasicDataPreviewer(Path dataFile) { super(dataFile); } + /** + * Get the previews of the data file. + * + * @param fromLine The starting line number. + * @param toLine The ending line number. + * @param numOfCharacters The number of characters to preview. + * @return the previews. + * @throws IOException if an I/O error occurs. + */ @Override - public List getPreviews(int fromLine, int toLine, int numOfCharacters) throws IOException { + public List getPreviews(int fromLine, int toLine, int numOfCharacters) throws IOException { // parameter validations checkLineNumberParameter(fromLine, toLine); checkCharacterNumberParameter(numOfCharacters); @@ -63,6 +75,15 @@ public List getPreviews(int fromLine, int toLine, int numOfCharacters) t return linePreviews; } + /** + * Get the previews of the data file. + * + * @param fromLine the starting line number + * @param toLine the ending line number + * @param numOfCharacters the number of characters to preview + * @param list the list to store the previews + * @throws IOException if an I/O error occurs + */ protected void getPreviews(int fromLine, int toLine, int numOfCharacters, List list) throws IOException { try (FileChannel fc = new RandomAccessFile(this.dataFile.toFile(), "r").getChannel()) { long fileSize = fc.size(); diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/preview/DataPreviewer.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/preview/DataPreviewer.java index 4960c6bd77..2e2889ba08 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/preview/DataPreviewer.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/preview/DataPreviewer.java @@ -28,6 +28,15 @@ */ public interface DataPreviewer { + /** + * Get the previews of the data file. + * + * @param fromLine The starting line number. + * @param toLine The ending line number. + * @param numOfCharacters The number of characters to preview. + * @return the previews. + * @throws IOException if an I/O error occurs. + */ List getPreviews(int fromLine, int toLine, int numOfCharacters) throws IOException; } diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/AbstractTabularColumnFileReader.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/AbstractTabularColumnFileReader.java index ac163c3f66..0a112e1392 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/AbstractTabularColumnFileReader.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/AbstractTabularColumnFileReader.java @@ -37,10 +37,23 @@ */ public abstract class AbstractTabularColumnFileReader extends DataFileReader { + /** + * Constructor. + * + * @param dataFile The data file. + * @param delimiter The delimiter. + */ public AbstractTabularColumnFileReader(Path dataFile, Delimiter delimiter) { super(dataFile, delimiter); } + /** + * Get the column numbers for the specified column names. + * + * @param columnNames the column names + * @return the column numbers + * @throws IOException if an I/O error occurs + */ protected int[] toColumnNumbers(Set columnNames) throws IOException { List colNums = new LinkedList<>(); @@ -157,6 +170,13 @@ protected int[] toColumnNumbers(Set columnNames) throws IOException { return colNums.stream().mapToInt(e -> e).toArray(); } + /** + * Strip the specified character from the word. + * + * @param word the word + * @param character the character to strip + * @return the word with the specified character stripped + */ protected String stripCharacter(String word, byte character) { StringBuilder dataBuilder = new StringBuilder(); for (byte currChar : word.getBytes()) { diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/ContinuousTabularData.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/ContinuousTabularData.java index fd6ce19f81..b1e729cbca 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/ContinuousTabularData.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/ContinuousTabularData.java @@ -31,16 +31,32 @@ public class ContinuousTabularData implements ContinuousData { private final DataColumn[] dataColumns; private final double[][] data; + /** + * Constructor. + * + * @param dataColumns The data columns. + * @param data The data. + */ public ContinuousTabularData(DataColumn[] dataColumns, double[][] data) { this.dataColumns = dataColumns; this.data = data; } + /** + * Get the data columns. + * + * @return the data columns. + */ @Override public DataColumn[] getDataColumns() { return this.dataColumns; } + /** + * Get the data. + * + * @return the data. + */ @Override public double[][] getData() { return this.data; diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/ContinuousTabularDatasetFileReader.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/ContinuousTabularDatasetFileReader.java index a3f9038e96..6cb85a1f09 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/ContinuousTabularDatasetFileReader.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/ContinuousTabularDatasetFileReader.java @@ -38,6 +38,12 @@ public class ContinuousTabularDatasetFileReader extends DatasetFileReader implem private boolean hasHeader; private char quoteChar; + /** + * Constructor. + * + * @param dataFile The data file. + * @param delimiter The delimiter. + */ public ContinuousTabularDatasetFileReader(Path dataFile, Delimiter delimiter) { super(dataFile, delimiter); this.hasHeader = this.hasHeader = true; diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/DiscreteTabularDataColumn.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/DiscreteTabularDataColumn.java index d0b33f5bc1..d1cd36a2e7 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/DiscreteTabularDataColumn.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/DiscreteTabularDataColumn.java @@ -34,21 +34,40 @@ public class DiscreteTabularDataColumn implements DiscreteDataColumn { private final Map values; private List categories; + /** + * Constructor. + * + * @param dataColumn The data column. + */ public DiscreteTabularDataColumn(DataColumn dataColumn) { this.dataColumn = dataColumn; this.values = new TreeMap<>(); } + /** + * Returns a string representation of the object. + * + * @return a string representation of the object. + */ @Override public String toString() { return "DiscreteTabularDataColumn{" + "dataColumn=" + this.dataColumn + ", values=" + this.values + ", categories=" + this.categories + '}'; } + /** + * Gets the encode value of the given value. + * + * @param value The value. + * @return the encode value of the given value. + */ @Override public Integer getEncodeValue(String value) { return this.values.get(value); } + /** + * Does a recategorization of the data column. + */ @Override public void recategorize() { Set keyset = this.values.keySet(); @@ -60,20 +79,40 @@ public void recategorize() { } } + /** + * Gets the value of the given encode value. + * + * @param value The encode value. + */ @Override public void setValue(String value) { this.values.put(value, null); } + /** + * Gets the data column. + * + * @return the data column. + */ @Override public DataColumn getDataColumn() { return this.dataColumn; } + /** + * Gets the values as a map + * + * @return the values. + */ public Map getValues() { return this.values; } + /** + * Gets the categories. + * + * @return the categories. + */ @Override public List getCategories() { return (this.categories == null) @@ -81,6 +120,11 @@ public List getCategories() { : this.categories; } + /** + * Sets the categories. + * + * @param categories the categories. + */ public void setCategories(List categories) { this.categories = categories; } diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/MixedTabularData.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/MixedTabularData.java index 61d749c26c..8971b663b7 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/MixedTabularData.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/MixedTabularData.java @@ -33,6 +33,14 @@ public class MixedTabularData implements MixedData { private final double[][] continuousData; private final int[][] discreteData; + /** + * Constructor. + * + * @param numOfRows the number of rows. + * @param dataColumns the data columns. + * @param continuousData the continuous data. + * @param discreteData the discrete data. + */ public MixedTabularData(int numOfRows, DiscreteDataColumn[] dataColumns, double[][] continuousData, int[][] discreteData) { this.numOfRows = numOfRows; this.dataColumns = dataColumns; @@ -40,21 +48,41 @@ public MixedTabularData(int numOfRows, DiscreteDataColumn[] dataColumns, double[ this.discreteData = discreteData; } + /** + * Get the number of rows. + * + * @return the number of rows. + */ @Override public int getNumOfRows() { return this.numOfRows; } + /** + * Get the data columns. + * + * @return the data columns. + */ @Override public DiscreteDataColumn[] getDataColumns() { return this.dataColumns; } + /** + * Get the continuous data. + * + * @return the continuous data. + */ @Override public double[][] getContinuousData() { return this.continuousData; } + /** + * Get the discrete data. + * + * @return the discrete data. + */ @Override public int[][] getDiscreteData() { return this.discreteData; diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/MixedTabularDataColumn.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/MixedTabularDataColumn.java index 36797fe03a..0b22eb7071 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/MixedTabularDataColumn.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/MixedTabularDataColumn.java @@ -36,16 +36,32 @@ public class MixedTabularDataColumn implements DiscreteDataColumn { private final Map values; private List categories; + /** + * Constructor. + * + * @param dataColumn The data column. + */ public MixedTabularDataColumn(DataColumn dataColumn) { this.dataColumn = dataColumn; this.values = dataColumn.isDiscrete() ? new TreeMap<>() : null; } + /** + * Returns a string representation of the object. + * + * @return a string representation of the object. + */ @Override public String toString() { return "MixedTabularDataColumn{" + "dataColumn=" + this.dataColumn + ", values=" + this.values + ", categories=" + this.categories + '}'; } + /** + * Gets the encode value of the given value. + * + * @param value The value. + * @return the encode value of the given value. + */ @Override public Integer getEncodeValue(String value) { return (this.values == null) @@ -53,6 +69,9 @@ public Integer getEncodeValue(String value) { : this.values.get(value); } + /** + * Does a recategorization of the data column. + */ @Override public void recategorize() { if (this.values != null) { @@ -66,6 +85,11 @@ public void recategorize() { } } + /** + * Sets the value. + * + * @param value The value. + */ @Override public void setValue(String value) { if (this.values != null) { @@ -73,15 +97,30 @@ public void setValue(String value) { } } + /** + * Gets the data column. + * + * @return the data column. + */ @Override public DataColumn getDataColumn() { return this.dataColumn; } + /** + * Gets the values as a map. + * + * @return the values. + */ public Map getValues() { return this.values; } + /** + * Gets the categories. + * + * @return the categories. + */ @Override public List getCategories() { return (this.categories == null) ? Collections.EMPTY_LIST : this.categories; diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/MixedTabularDatasetFileReader.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/MixedTabularDatasetFileReader.java index 21e52ae86c..c8f1bbf019 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/MixedTabularDatasetFileReader.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/MixedTabularDatasetFileReader.java @@ -37,6 +37,13 @@ public class MixedTabularDatasetFileReader extends DatasetFileReader implements private boolean hasHeader; private char quoteChar; + /** + * Constructor. + * + * @param dataFile The data file. + * @param delimiter The delimiter. + * @param numberOfDiscreteCategories The number of discrete categories. + */ public MixedTabularDatasetFileReader(Path dataFile, Delimiter delimiter, int numberOfDiscreteCategories) { super(dataFile, delimiter); this.numberOfDiscreteCategories = numberOfDiscreteCategories; @@ -44,11 +51,22 @@ public MixedTabularDatasetFileReader(Path dataFile, Delimiter delimiter, int num this.quoteChar = '"'; } + /** + * Reads in the data. + * + * @return The data. + * @throws IOException If an I/O error occurs. + */ @Override public Data readInData() throws IOException { return readInData(Collections.EMPTY_SET); } + /** + * @param namesOfColumnsToExclude the names of columns to exclude + * @return The data. + * @throws IOException If an I/O error occurs. + */ @Override public Data readInData(Set namesOfColumnsToExclude) throws IOException { TabularColumnReader columnReader = new TabularColumnFileReader(this.dataFile, this.delimiter); @@ -70,6 +88,13 @@ public Data readInData(Set namesOfColumnsToExclude) throws IOException { return toMixedData(dataReader.read(dataColumns, this.hasHeader)); } + /** + * Reads in the data. + * + * @param columnsToExclude the columns to exclude + * @return The data. + * @throws IOException If an I/O error occurs. + */ @Override public Data readInData(int[] columnsToExclude) throws IOException { TabularColumnReader columnReader = new TabularColumnFileReader(this.dataFile, this.delimiter); @@ -141,11 +166,21 @@ private Data toMixedData(Data data) { } } + /** + * Sets whether the data file has a header. + * + * @param hasHeader Whether the data file has a header. + */ @Override public void setHasHeader(boolean hasHeader) { this.hasHeader = hasHeader; } + /** + * Sets the quote character. + * + * @param quoteCharacter The quote character. + */ @Override public void setQuoteCharacter(char quoteCharacter) { this.quoteChar = quoteCharacter; diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/TabularColumnFileReader.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/TabularColumnFileReader.java index 7053a73d91..c1231e58db 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/TabularColumnFileReader.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/TabularColumnFileReader.java @@ -40,17 +40,36 @@ */ public final class TabularColumnFileReader extends AbstractTabularColumnFileReader implements TabularColumnReader { -// private static final Logger LOGGER = LoggerFactory.getLogger(TabularColumnFileReader.class); - + /** + * Constructor. + * + * @param dataFile The data file. + * @param delimiter The delimiter. + */ public TabularColumnFileReader(Path dataFile, Delimiter delimiter) { super(dataFile, delimiter); } + /** + * Reads in the data columns. + * + * @param isDiscrete Whether the data is discrete. + * @return The data columns. + * @throws IOException If an I/O error occurs. + */ @Override public DataColumn[] readInDataColumns(boolean isDiscrete) throws IOException { return readInDataColumns(Collections.EMPTY_SET, isDiscrete); } + /** + * Reads in the data columns. + * + * @param namesOfColumnsToExclude the names of columns to exclude + * @param isDiscrete Whether the data is discrete. + * @return The data columns. + * @throws IOException If an I/O error occurs. + */ @Override public DataColumn[] readInDataColumns(Set namesOfColumnsToExclude, boolean isDiscrete) throws IOException { if (namesOfColumnsToExclude == null || namesOfColumnsToExclude.isEmpty()) { @@ -78,6 +97,14 @@ public DataColumn[] readInDataColumns(Set namesOfColumnsToExclude, boole } } + /** + * Reads in the data columns. + * + * @param columnsToExclude the columns to exclude + * @param isDiscrete Whether the data is discrete. + * @return The data columns. + * @throws IOException If an I/O error occurs. + */ @Override public DataColumn[] readInDataColumns(int[] columnsToExclude, boolean isDiscrete) throws IOException { int numOfCols = countNumberOfColumns(); @@ -87,6 +114,14 @@ public DataColumn[] readInDataColumns(int[] columnsToExclude, boolean isDiscrete return getColumns(validColsToExclude, isDiscrete); } + /** + * Generates the data columns. + * + * @param columnsToExclude the columns to exclude + * @param isDiscrete Whether the data is discrete. + * @return The data columns. + * @throws IOException If an I/O error occurs. + */ @Override public DataColumn[] generateColumns(int[] columnsToExclude, boolean isDiscrete) throws IOException { List columns = new LinkedList<>(); diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/TabularColumnReader.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/TabularColumnReader.java index 363a2ab877..5d7a58b0d6 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/TabularColumnReader.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/TabularColumnReader.java @@ -31,12 +31,43 @@ */ public interface TabularColumnReader extends DataReader { + /** + * Read in the data columns. + * + * @param isDiscrete whether the data is discrete. + * @return the data columns. + * @throws IOException if an I/O error occurs. + */ DataColumn[] readInDataColumns(boolean isDiscrete) throws IOException; + /** + * Read in the data columns. + * + * @param namesOfColumnsToExclude the names of columns to exclude. + * @param isDiscrete whether the data is discrete. + * @return the data columns. + * @throws IOException if an I/O error occurs. + */ DataColumn[] readInDataColumns(Set namesOfColumnsToExclude, boolean isDiscrete) throws IOException; + /** + * Read in the data columns. + * + * @param columnsToExclude the columns to exclude. + * @param isDiscrete whether the data is discrete. + * @return the data columns. + * @throws IOException if an I/O error occurs. + */ DataColumn[] readInDataColumns(int[] columnsToExclude, boolean isDiscrete) throws IOException; + /** + * Generate the data columns. + * + * @param isDiscrete whether the data is discrete. + * @param columnsToExclude the columns to exclude. + * @return the data columns. + * @throws IOException if an I/O error occurs. + */ DataColumn[] generateColumns(int[] columnsToExclude, boolean isDiscrete) throws IOException; } diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/TabularDataColumn.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/TabularDataColumn.java index 8eacaa114d..7b7f78d9ff 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/TabularDataColumn.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/TabularDataColumn.java @@ -32,12 +32,27 @@ public class TabularDataColumn implements DataColumn { private final boolean generated; private boolean discrete; + /** + * Constructor. + * + * @param name the name of the column. + * @param columnNumber the column number. + * @param generated whether the column is generated. + */ public TabularDataColumn(String name, int columnNumber, boolean generated) { this.name = name; this.columnNumber = columnNumber; this.generated = generated; } + /** + * Constructor. + * + * @param name the name of the column. + * @param columnNumber the column number. + * @param generated whether the column is generated. + * @param discrete whether the column is discrete. + */ public TabularDataColumn(String name, int columnNumber, boolean generated, boolean discrete) { this.name = name; this.columnNumber = columnNumber; @@ -45,31 +60,61 @@ public TabularDataColumn(String name, int columnNumber, boolean generated, boole this.discrete = discrete; } + /** + * Returns a string representation of the object. + * + * @return a string representation of the object. + */ @Override public String toString() { return "TabularDataColumn{" + "name=" + this.name + ", columnNumber=" + this.columnNumber + ", generated=" + this.generated + ", discrete=" + this.discrete + '}'; } + /** + * Get the name of the column. + * + * @return the name of the column. + */ @Override public String getName() { return this.name; } + /** + * Get the column number. + * + * @return the column number. + */ @Override public int getColumnNumber() { return this.columnNumber; } + /** + * Is the column generated? + * + * @return true if the column is generated, false otherwise. + */ @Override public boolean isGenerated() { return this.generated; } + /** + * Is the column discrete? + * + * @return true if the column is discrete, false otherwise. + */ @Override public boolean isDiscrete() { return this.discrete; } + /** + * Set the discrete status of the column. + * + * @param discrete true if the column is discrete, false otherwise. + */ @Override public void setDiscrete(boolean discrete) { this.discrete = discrete; diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/TabularDataFileReader.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/TabularDataFileReader.java index 4963ebadd6..7b25a54a8d 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/TabularDataFileReader.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/TabularDataFileReader.java @@ -38,12 +38,24 @@ */ public final class TabularDataFileReader extends DatasetFileReader implements TabularDataReader { -// private static final Logger LOGGER = LoggerFactory.getLogger(TabularDataFileReader.class); - + /** + * Constructor. + * + * @param dataFile The data file. + * @param delimiter The delimiter. + */ public TabularDataFileReader(Path dataFile, Delimiter delimiter) { super(dataFile, delimiter); } + /** + * Reads in the data. + * + * @param dataColumns the data columns. + * @param numberOfCategories maximum number of categories to be considered discrete + * @param hasHeader whether the data file has a header + * @throws IOException if an I/O error occurs. + */ @Override public void determineDiscreteDataColumns(DataColumn[] dataColumns, int numberOfCategories, boolean hasHeader) throws IOException { int numOfColsInDataFile = 0; @@ -318,8 +330,7 @@ public Data read(DataColumn[] dataColumns, boolean hasHeader, Metadata metadata) Data data = read(dataColumns, hasHeader); if (metadata != null) { - if (data instanceof ContinuousData) { - ContinuousData continuousData = (ContinuousData) data; + if (data instanceof ContinuousData continuousData) { double[][] contData = continuousData.getData(); metadata.getInterventionalColumns().forEach(column -> { ColumnMetadata valCol = column.getValueColumn(); @@ -337,8 +348,7 @@ public Data read(DataColumn[] dataColumns, boolean hasHeader, Metadata metadata) } } }); - } else if (data instanceof DiscreteData) { - DiscreteData verticalDiscreteData = (DiscreteData) data; + } else if (data instanceof DiscreteData verticalDiscreteData) { int[][] discreteData = verticalDiscreteData.getData(); metadata.getInterventionalColumns().forEach(column -> { ColumnMetadata valCol = column.getValueColumn(); @@ -356,8 +366,7 @@ public Data read(DataColumn[] dataColumns, boolean hasHeader, Metadata metadata) } } }); - } else if (data instanceof MixedTabularData) { - MixedTabularData mixedTabularData = (MixedTabularData) data; + } else if (data instanceof MixedTabularData mixedTabularData) { double[][] continuousData = mixedTabularData.getContinuousData(); int[][] discreteData = mixedTabularData.getDiscreteData(); metadata.getInterventionalColumns().forEach(column -> { @@ -570,7 +579,6 @@ private void readInMixedData(DiscreteDataColumn[] dataColumns, boolean hasHeader // ensure we have enough data if (columnIndex < numOfColsInDataFile) { String errMsg = String.format("Insufficient data on line %d. Extracted %d value(s) but expected %d.", lineNum, columnIndex, numOfColsInDataFile); -// TabularDataFileReader.LOGGER.error(errMsg); throw new DataReaderException(errMsg); } @@ -707,7 +715,6 @@ private void readInMixedData(DiscreteDataColumn[] dataColumns, boolean hasHeader // ensure we have enough data if (columnIndex < numOfColsInDataFile) { String errMsg = String.format("Insufficient data on line %d. Extracted %d value(s) but expected %d.", lineNum, columnIndex, numOfColsInDataFile); -// TabularDataFileReader.LOGGER.error(errMsg); throw new DataReaderException(errMsg); } } @@ -1298,7 +1305,7 @@ private void readInDiscreteCategorizes(DiscreteDataColumn[] dataColumns, boolean if (dataColumn.getColumnNumber() == colNum) { if (dataColumn.isDiscrete()) { String value = dataBuilder.toString().trim(); - if (value.length() > 0 && !value.equals(this.missingDataMarker)) { + if (!value.isEmpty() && !value.equals(this.missingDataMarker)) { discreteDataColumn.setValue(value); } } @@ -1309,7 +1316,6 @@ private void readInDiscreteCategorizes(DiscreteDataColumn[] dataColumns, boolean // ensure we have enough data if (columnIndex < numOfColsInDataFile) { String errMsg = String.format("Insufficient data on line %d. Extracted %d value(s) but expected %d.", lineNum, columnIndex, numOfColsInDataFile); -// TabularDataFileReader.LOGGER.error(errMsg); throw new DataReaderException(errMsg); } } @@ -1371,7 +1377,7 @@ private void readInDiscreteCategorizes(DiscreteDataColumn[] dataColumns, boolean if (dataColumn.getColumnNumber() == colNum) { if (dataColumn.isDiscrete()) { String value = dataBuilder.toString().trim(); - if (value.length() > 0 && !value.equals(this.missingDataMarker)) { + if (!value.isEmpty() && !value.equals(this.missingDataMarker)) { discreteDataColumn.setValue(value); } } @@ -1403,7 +1409,7 @@ private void readInDiscreteCategorizes(DiscreteDataColumn[] dataColumns, boolean if (dataColumn.getColumnNumber() == colNum) { if (dataColumn.isDiscrete()) { String value = dataBuilder.toString().trim(); - if (value.length() > 0 && !value.equals(this.missingDataMarker)) { + if (!value.isEmpty() && !value.equals(this.missingDataMarker)) { discreteDataColumn.setValue(value); } } diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/TabularDataReader.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/TabularDataReader.java index cc3c5dee66..518c93f544 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/TabularDataReader.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/TabularDataReader.java @@ -37,15 +37,32 @@ public interface TabularDataReader extends DatasetReader { * number of categories of a column is equal to or less than the given number of categories, it will be considered * to have discrete data. Else, it is considered to have continuous data. * - * @param dataColumns + * @param dataColumns the data columns * @param numberOfCategories maximum number of categories to be considered discrete - * @param hasHeader - * @throws IOException + * @param hasHeader whether the data has a header + * @throws IOException if an I/O error occurs */ void determineDiscreteDataColumns(DataColumn[] dataColumns, int numberOfCategories, boolean hasHeader) throws IOException; + /** + * Read the data. + * + * @param dataColumns the data columns + * @param hasHeader whether the data has a header + * @return the data + * @throws IOException if an I/O error occurs + */ Data read(DataColumn[] dataColumns, boolean hasHeader) throws IOException; + /** + * Read the data. + * + * @param dataColumns the data columns + * @param hasHeader whether the data has a header + * @param metadata the metadata + * @return the data + * @throws IOException if an I/O error occurs + */ Data read(DataColumn[] dataColumns, boolean hasHeader, Metadata metadata) throws IOException; } diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/TabularDatasetReader.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/TabularDatasetReader.java index 8b02026994..c437738929 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/TabularDatasetReader.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/TabularDatasetReader.java @@ -31,12 +31,37 @@ */ public interface TabularDatasetReader extends DatasetReader { + /** + * Read in the data. + * + * @return The data. + * @throws IOException If an I/O error occurs. + */ Data readInData() throws IOException; + /** + * Read in the data. + * + * @param namesOfColumnsToExclude the names of columns to exclude. + * @return The data. + * @throws IOException If an I/O error occurs. + */ Data readInData(Set namesOfColumnsToExclude) throws IOException; + /** + * Read in the data. + * + * @param columnsToExclude the columns to exclude. + * @return The data. + * @throws IOException If an I/O error occurs. + */ Data readInData(int[] columnsToExclude) throws IOException; + /** + * Set whether the data has a header. + * + * @param hasHeader whether the data has a header. + */ void setHasHeader(boolean hasHeader); } diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/VerticalDiscreteTabularData.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/VerticalDiscreteTabularData.java index b0634088f4..4d23024cbb 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/VerticalDiscreteTabularData.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/VerticalDiscreteTabularData.java @@ -31,16 +31,32 @@ public class VerticalDiscreteTabularData implements DiscreteData { private final DiscreteDataColumn[] dataColumns; private final int[][] data; + /** + * Constructor. + * + * @param dataColumns the data columns. + * @param data the data. + */ public VerticalDiscreteTabularData(DiscreteDataColumn[] dataColumns, int[][] data) { this.dataColumns = dataColumns; this.data = data; } + /** + * Gets the data columns. + * + * @return the data columns. + */ @Override public DiscreteDataColumn[] getDataColumns() { return this.dataColumns; } + /** + * Gets the data. + * + * @return the data. + */ @Override public int[][] getData() { return this.data; diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/VerticalDiscreteTabularDatasetFileReader.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/VerticalDiscreteTabularDatasetFileReader.java index 4271f0151e..77b31d045e 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/VerticalDiscreteTabularDatasetFileReader.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/tabular/VerticalDiscreteTabularDatasetFileReader.java @@ -38,17 +38,36 @@ public class VerticalDiscreteTabularDatasetFileReader extends DatasetFileReader private boolean hasHeader; private char quoteChar; + /** + * Constructor. + * + * @param dataFile The data file. + * @param delimiter The delimiter. + */ public VerticalDiscreteTabularDatasetFileReader(Path dataFile, Delimiter delimiter) { super(dataFile, delimiter); this.hasHeader = this.hasHeader = true; this.quoteChar = '"'; } + /** + * Reads in the data. + * + * @return The data. + * @throws IOException If an I/O error occurs. + */ @Override public Data readInData() throws IOException { return readInData(Collections.EMPTY_SET); } + /** + * Reads in the data. + * + * @param namesOfColumnsToExclude the names of columns to exclude. + * @return The data. + * @throws IOException If an I/O error occurs. + */ @Override public Data readInData(Set namesOfColumnsToExclude) throws IOException { TabularColumnReader columnReader = new TabularColumnFileReader(this.dataFile, this.delimiter); @@ -68,6 +87,13 @@ public Data readInData(Set namesOfColumnsToExclude) throws IOException { return dataReader.read(dataColumns, this.hasHeader); } + /** + * Reads in the data. + * + * @param columnsToExclude the columns to exclude. + * @return The data. + * @throws IOException If an I/O error occurs. + */ @Override public Data readInData(int[] columnsToExclude) throws IOException { TabularColumnReader columnReader = new TabularColumnFileReader(this.dataFile, this.delimiter); @@ -87,11 +113,21 @@ public Data readInData(int[] columnsToExclude) throws IOException { return dataReader.read(dataColumns, this.hasHeader); } + /** + * Set whether the data has a header. + * + * @param hasHeader whether the data has a header. + */ @Override public void setHasHeader(boolean hasHeader) { this.hasHeader = hasHeader; } + /** + * Set the quote character. + * + * @param quoteCharacter the quote character + */ @Override public void setQuoteCharacter(char quoteCharacter) { this.quoteChar = quoteCharacter; diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/util/Columns.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/util/Columns.java index 162a95bdfa..1a42d810a8 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/util/Columns.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/util/Columns.java @@ -30,6 +30,12 @@ public final class Columns { private Columns() { } + /** + * Sort the columns in ascending order. + * + * @param columns the columns to sort. + * @return the sorted columns. + */ public static int[] sortNew(int[] columns) { int size = (columns == null) ? 0 : columns.length; if (size > 0) { @@ -46,9 +52,9 @@ public static int[] sortNew(int[] columns) { /** * Keep all the columns that are between 1 and numOfCols, inclusive. * - * @param numberOfColumns - * @param columns - * @return + * @param numberOfColumns the number of columns. + * @param columns the columns to keep. + * @return the valid columns. */ public static int[] extractValidColumnNumbers(int numberOfColumns, int[] columns) { return (columns == null || columns.length == 0) diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/util/TextFileUtils.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/util/TextFileUtils.java index e133241ff3..6aaed4afcd 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/util/TextFileUtils.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/util/TextFileUtils.java @@ -32,9 +32,19 @@ */ public class TextFileUtils { + /** + * The line feed delimiter for text data files. + */ protected static final byte LINE_FEED = '\n'; + + /** + * The carriage return delimiter for text data files. + */ protected static final byte CARRIAGE_RETURN = '\r'; + /** + * The space character for text data files. + */ protected static final byte SPACE_CHAR = ' '; private TextFileUtils() { @@ -53,8 +63,8 @@ private TextFileUtils() { * @param comment a comment symbol to ignore lines in files * @param quoteCharacter used for grouping characters * @param delims the set of delimiters to test for - * @return - * @throws IOException + * @return the inferred delimiter + * @throws IOException if an I/O error occurs */ public static char inferDelimiter(File file, int n, int skip, String comment, char quoteCharacter, char[] delims) throws IOException { if (file == null) { diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/AbstractDataFileValidation.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/AbstractDataFileValidation.java index a8758381b9..4741b2c485 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/AbstractDataFileValidation.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/AbstractDataFileValidation.java @@ -30,13 +30,27 @@ */ public abstract class AbstractDataFileValidation extends DataFileReader implements Validation { + /** + * The maximum number of messages to validate. + */ protected int maxNumOfMsg; + /** + * Constructor. + * + * @param dataFile the data file + * @param delimiter the delimiter + */ public AbstractDataFileValidation(Path dataFile, Delimiter delimiter) { super(dataFile, delimiter); this.maxNumOfMsg = Integer.MAX_VALUE; } + /** + * Set the maximum number of messages to validate. + * + * @param maxNumOfMsg the maximum number of messages + */ @Override public void setMaximumNumberOfMessages(int maxNumOfMsg) { this.maxNumOfMsg = maxNumOfMsg; diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/MessageType.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/MessageType.java index 702bf2e6f5..dae7c45b38 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/MessageType.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/MessageType.java @@ -25,11 +25,34 @@ */ public enum MessageType { + /** + * Error in file input/output operation. + */ FILE_IO_ERROR, + + /** + * Missing value in file. + */ FILE_MISSING_VALUE, + + /** + * Invalid number in file. + */ FILE_INVALID_NUMBER, + + /** + * Excess or insufficient data in file. + */ FILE_EXCESS_DATA, + + /** + * Excess or insufficient data in file. + */ FILE_INSUFFICIENT_DATA, + + /** + * File summary. + */ FILE_SUMMARY } diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/Validation.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/Validation.java index 8674e7ae13..6ec74fa02c 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/Validation.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/Validation.java @@ -25,6 +25,11 @@ */ public interface Validation { + /** + * Sets the maximum number of messages. + * + * @param maxNumOfMsg the maximum number of messages. + */ void setMaximumNumberOfMessages(int maxNumOfMsg); } diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/ValidationAttribute.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/ValidationAttribute.java index 1fdf8b7df8..537d3178ae 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/ValidationAttribute.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/ValidationAttribute.java @@ -25,21 +25,84 @@ */ public enum ValidationAttribute { + /** + * The number of continuous variables. + */ CONTINUOUS_VAR_COUNT, + + /** + * The number of discrete variables. + */ DISCRETE_VAR_COUNT, + + /** + * The line number. + */ LINE_NUMBER, + + /** + * The column number. + */ COLUMN_NUMBER, + + /** + * The row number. + */ ROW_NUMBER, + + /** + * The expected count. + */ EXPECTED_COUNT, + + /** + * The actual count. + */ ACTUAL_COUNT, + + /** + * The line count. + */ LINE_COUNT, + + /** + * The column count. + */ COLUMN_COUNT, + + /** + * The row count. + */ ROW_COUNT, + + /** + * The assumed missing count. + */ ASSUMED_MISSING_COUNT, + + /** + * The labeled missing count. + */ LABELED_MISSING_COUNT, + + /** + * The number of rows with missing values. + */ ROW_WITH_MISSING_VALUE_COUNT, + + /** + * The number of columns with missing values. + */ COLUMN_WITH_MISSING_VALUE_COUNT, + + /** + * The file name. + */ FILE_NAME, + + /** + * The value. + */ VALUE } diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/ValidationCode.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/ValidationCode.java index 602719da6e..ca96714377 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/ValidationCode.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/ValidationCode.java @@ -25,8 +25,19 @@ */ public enum ValidationCode { + /** + * Information message. + */ INFO, + + /** + * Warning message. + */ WARNING, + + /** + * Error message. + */ ERROR } diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/ValidationResult.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/ValidationResult.java index 9f9a62c27e..beeb9fc50b 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/ValidationResult.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/ValidationResult.java @@ -36,42 +36,91 @@ public class ValidationResult { private String message; + /** + * Default constructor. + * + * @param code the validation code. + * @param messageType the message type. + */ public ValidationResult(ValidationCode code, MessageType messageType) { this.code = code; this.messageType = messageType; this.attributes = new EnumMap<>(ValidationAttribute.class); } + /** + * Constructor with message. + * + * @param code the validation code. + * @param messageType the message type. + * @param message the message. + */ public ValidationResult(ValidationCode code, MessageType messageType, String message) { this(code, messageType); this.message = message; } + /** + * Return the string representation of this object. + * + * @return the string representation of this object. + */ @Override public String toString() { return "ValidationResult{" + "code=" + this.code + ", messageType=" + this.messageType + ", attributes=" + this.attributes + ", message=" + this.message + '}'; } + /** + * Return the hash code of this object. + * + * @return the hash code of this object. + */ public ValidationCode getCode() { return this.code; } + /** + * Return the message type. + * + * @return the message type. + */ public MessageType getMessageType() { return this.messageType; } + /** + * Return the attributes. + * + * @return the attributes. + */ public Map getAttributes() { return this.attributes; } + /** + * Sets the attribute value. + * + * @param attribute the attribute. + * @param value the value. + */ public void setAttribute(ValidationAttribute attribute, Object value) { this.attributes.put(attribute, value); } + /** + * Return the message. + * + * @return the message. + */ public String getMessage() { return this.message; } + /** + * Sets the message. + * + * @param message the message. + */ public void setMessage(String message) { this.message = message; } diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/covariance/CovarianceValidation.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/covariance/CovarianceValidation.java index b462818697..c9980db01b 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/covariance/CovarianceValidation.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/covariance/CovarianceValidation.java @@ -31,6 +31,11 @@ */ public interface CovarianceValidation extends Validation, DataReader { + /** + * Validate the covariance. + * + * @return the validation results. + */ List validate(); } diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/covariance/LowerCovarianceDataFileValidation.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/covariance/LowerCovarianceDataFileValidation.java index f6c3fac7c6..108c7388b0 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/covariance/LowerCovarianceDataFileValidation.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/covariance/LowerCovarianceDataFileValidation.java @@ -37,10 +37,21 @@ */ public class LowerCovarianceDataFileValidation extends AbstractDataFileValidation implements CovarianceValidation { + /** + * Constructor. + * + * @param dataFile the data file. + * @param delimiter the delimiter. + */ public LowerCovarianceDataFileValidation(Path dataFile, Delimiter delimiter) { super(dataFile, delimiter); } + /** + * Validate the covariance. + * + * @return the validation results. + */ @Override public List validate() { List validationResults = new LinkedList<>(); diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/tabular/TabularColumnFileValidation.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/tabular/TabularColumnFileValidation.java index bf5505d3df..f973575eda 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/tabular/TabularColumnFileValidation.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/tabular/TabularColumnFileValidation.java @@ -43,16 +43,33 @@ public class TabularColumnFileValidation extends AbstractTabularColumnFileReader private int maxNumOfMsg; + /** + * Constructor. + * + * @param dataFile The data file. + * @param delimiter The delimiter. + */ public TabularColumnFileValidation(Path dataFile, Delimiter delimiter) { super(dataFile, delimiter); this.maxNumOfMsg = Integer.MAX_VALUE; } + /** + * Constructor. + * + * @return The maximum number of messages. + */ @Override public List validate() { return validate(Collections.EMPTY_SET); } + /** + * Validate the data file. + * + * @param excludedColumns the columns to exclude. + * @return the validation results. + */ @Override public List validate(int[] excludedColumns) { List results = new LinkedList<>(); @@ -75,6 +92,12 @@ public List validate(int[] excludedColumns) { return results; } + /** + * Validate the data file. + * + * @param excludedColumns the columns to exclude. + * @return the validation results. + */ @Override public List validate(Set excludedColumns) { List results = new LinkedList<>(); @@ -86,14 +109,14 @@ public List validate(Set excludedColumns) { Set modifiedExcludedCols = new HashSet<>(); if (Character.isDefined(this.quoteCharacter)) { excludedColumns.stream() - .map(e -> e.trim()) + .map(String::trim) .filter(e -> !e.isEmpty()) .forEach(e -> modifiedExcludedCols.add(stripCharacter(e, this.quoteCharacter))); } else { excludedColumns.stream() - .map(e -> e.trim()) + .map(String::trim) .filter(e -> !e.isEmpty()) - .forEach(e -> modifiedExcludedCols.add(e)); + .forEach(modifiedExcludedCols::add); } int[] excludedCols = toColumnNumbers(modifiedExcludedCols); @@ -267,6 +290,11 @@ private void validateColumns(int[] excludedColumns, List resul results.add(result); } + /** + * Set the maximum number of messages. + * + * @param maxNumOfMsg the maximum number of messages. + */ @Override public void setMaximumNumberOfMessages(int maxNumOfMsg) { this.maxNumOfMsg = maxNumOfMsg; diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/tabular/TabularColumnValidation.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/tabular/TabularColumnValidation.java index ac2fd9564c..d7321e3ea1 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/tabular/TabularColumnValidation.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/tabular/TabularColumnValidation.java @@ -32,10 +32,27 @@ */ public interface TabularColumnValidation extends Validation, DataReader { + /** + * Validate the columns. + * + * @return the validation results. + */ List validate(); + /** + * Validate the columns. + * + * @param excludedColumns the columns to exclude. + * @return the validation results. + */ List validate(int[] excludedColumns); + /** + * Validate the columns. + * + * @param excludedColumns the columns to exclude. + * @return the validation results. + */ List validate(Set excludedColumns); } diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/tabular/TabularDataFileValidation.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/tabular/TabularDataFileValidation.java index bf1b223abb..1b7f5b02a7 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/tabular/TabularDataFileValidation.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/tabular/TabularDataFileValidation.java @@ -44,11 +44,24 @@ public class TabularDataFileValidation extends DatasetFileReader implements Tabu private int maxNumOfMsg; + /** + * Constructor. + * + * @param dataFile the data file. + * @param delimiter the delimiter. + */ public TabularDataFileValidation(Path dataFile, Delimiter delimiter) { super(dataFile, delimiter); this.maxNumOfMsg = Integer.MAX_VALUE; } + /** + * Constructor. + * + * @param dataColumns the data columns. + * @param hasHeader the data has header. + * @return the validation results. + */ @Override public List validate(DataColumn[] dataColumns, boolean hasHeader) { List results = new LinkedList<>(); diff --git a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/tabular/TabularDataValidation.java b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/tabular/TabularDataValidation.java index e8f01ed450..9cb7b6bf2e 100644 --- a/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/tabular/TabularDataValidation.java +++ b/data-reader/src/main/java/edu/pitt/dbmi/data/reader/validation/tabular/TabularDataValidation.java @@ -32,6 +32,13 @@ */ public interface TabularDataValidation extends Validation, DatasetReader { + /** + * Validate the data columns. + * + * @param dataColumns the data columns. + * @param hasHeader the flag indicating if the data has a header. + * @return the validation results. + */ List validate(DataColumn[] dataColumns, boolean hasHeader); } diff --git a/pom.xml b/pom.xml index b03d15628e..cff05d0bb4 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 io.github.cmu-phil tetrad - 7.6.1 + 7.6.2-SNAPSHOT pom Tetrad Project @@ -64,8 +64,8 @@ maven-compiler-plugin 3.11.0 - 1.8 - 1.8 + 17 + 17 @@ -116,7 +116,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 2.9.1 + 3.6.3 /usr/bin/javadoc @@ -144,7 +144,7 @@ org.apache.maven.plugins maven-source-plugin - 3.2.1 + 3.3.0 attach-sources @@ -188,8 +188,8 @@ UTF-8 -Xdoclint:none - 1.8 - 1.8 + 17 + 17 diff --git a/tetrad-gui/pom.xml b/tetrad-gui/pom.xml index 0483b1ab23..f9fc45341b 100644 --- a/tetrad-gui/pom.xml +++ b/tetrad-gui/pom.xml @@ -6,7 +6,7 @@ io.github.cmu-phil tetrad - 7.6.1 + 7.6.2-SNAPSHOT tetrad-gui @@ -33,14 +33,14 @@ maven-compiler-plugin 3.11.0 - 1.8 - 1.8 + 17 + 17 org.apache.maven.plugins maven-shade-plugin - 3.1.0 + 3.5.1 package diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/Tetrad.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/Tetrad.java index 6e9d9fb2cd..c04d1a5efa 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/Tetrad.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/Tetrad.java @@ -27,7 +27,6 @@ import edu.cmu.tetradapp.util.DesktopController; import edu.cmu.tetradapp.util.ImageUtils; import edu.cmu.tetradapp.util.SplashScreen; -import org.apache.commons.math3.util.FastMath; import javax.swing.*; import java.awt.*; @@ -35,6 +34,7 @@ import java.awt.event.WindowEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.io.Serial; import java.util.Locale; import java.util.prefs.Preferences; @@ -50,38 +50,37 @@ */ public final class Tetrad implements PropertyChangeListener { + // The experimental option private static final String EXP_OPT = "--experimental"; + // Whether to enable experimental features public static boolean enableExperimental; - /** - * The main application title. - */ + // The main application title. private final String mainTitle = "Tetrad " + Version.currentViewableVersion(); - /** - * The launch frame. - */ - private JFrame frame; - /** - * The desktop placed into the launch frame. - */ + // The launch frame. + public static JFrame frame; + // The desktop placed into the launch frame. private TetradDesktop desktop; //==============================CONSTRUCTORS===========================// + + /** + * Constructs a new Tetrad instance. + */ public Tetrad() { } //==============================PUBLIC METHODS=========================// /** - *

* Launches Tetrad as an application. One way to launch Tetrad IV as an application is the following:> 0 *

java -cp jarname.jar INSTANCE.Tetrad
*

- * where "jarname.jar" is a jar containing all of the classes of Tetrad IV, properly compiled, along with all of the - * auxiliary jar contents and all of the images which Tetrad IV uses, all in their proper relative directories.> + * where "jarname.jar" is a jar containing all the classes of Tetrad IV, properly compiled, along with all the + * auxiliary jar contents and all the images which Tetrad IV uses, all in their proper relative directories.> * 0 * - * @param argv --skip-latest argument will skip checking for latest version. + * @param argv --skip-latest argument will skip checking for the latest version. */ public static void main(String[] argv) { if (argv != null && argv.length > 0) { @@ -96,47 +95,40 @@ public static void main(String[] argv) { // This is needed to get numbers to be parsed and rendered uniformly, especially in the interface. Locale.setDefault(Locale.US); - // Check if we should skip checking for latest version + // Check if we should skip checking for the latest version SplashScreen.show("Loading Tetrad...", 1000); EventQueue.invokeLater(() -> new Tetrad().launchFrame()); Tetrad.enableExperimental = Preferences.userRoot().getBoolean("enableExperimental", false); } + /** + * Responds to "exitProgram" property change events by disposing of the Tetrad IV frame and exiting if possible. + * + * @param e the property change event + */ + @Override + public void propertyChange(PropertyChangeEvent e) { + if ("exitProgram".equals(e.getPropertyName())) { + exitApplication(); + } + } + //===============================PRIVATE METHODS=======================// private static void setLookAndFeel() { try { String os = System.getProperties().getProperty("os.name"); if (os.equals("Windows XP")) { - // The only system look and feel that seems to work well is the - // one for Windows XP. When running on Mac the mac look and - // feel is forced. The new look (synth or whatever it's called) - // and feel for linux on 1.5 looks - // pretty bad, so it shouldn't be used. - // By default, linux will use the metal look and feel. UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName()); } } catch (Exception e) { - e.printStackTrace(); + TetradLogger.getInstance().forceLogMessage("Couldn't set look and feel."); } } - /** - * Responds to "exitProgram" property change events by disposing of the Tetrad IV frame and exiting if possible. - * - * @param e the property change event - */ - @Override - public void propertyChange(PropertyChangeEvent e) { - if ("exitProgram".equals(e.getPropertyName())) { - exitApplication(); - } - } - /** - * Launches the frame. (This is left as a separate method in case we ever want to launch it as an applet.) - */ + // Launches the frame. (This is left as a separate method in case we ever want to launch it as an applet.) private void launchFrame() { System.setProperty("java.util.Arrays.useLegacyMergeSort", "true"); @@ -146,40 +138,36 @@ private void launchFrame() { JOptionUtils.setCenteringComp(getDesktop()); DesktopController.setReference(getDesktop()); - // Set up the frame. Note the order in which the next few steps - // happen. First, the frame is given a preferred size, so that if - // someone unmaximizes it, it doesn't shrivel up to the top left - // corner. Next, the content pane is set. Next, it is packed. Finally, - // it is maximized. For some reason, most of the details of this - // order are important. jdramsey 12/14/02 - this.frame = new JFrame(this.mainTitle) { - + /* + This sets up the frame. Note the order in which the next few steps + happen. First, the frame is given a preferred size, so that if + someone unmaximizes it, it doesn't shrivel up to the top left + corner. Next, the content pane is set. Next, it is packed. Finally, + it is maximized. For some reason, most of the details of this + order are important. Jdramsey 12/14/02 + */ + frame = new JFrame(this.mainTitle) { + + @Serial private static final long serialVersionUID = -9077349253115802418L; @Override public Dimension getPreferredSize() { - Dimension size = Toolkit.getDefaultToolkit().getScreenSize(); - double minLength = FastMath.min(size.getWidth(), size.getHeight()); - double height = minLength * 0.8; - double width = height * (4.0 / 3); - - return new Dimension((int) width, (int) height); - + return Toolkit.getDefaultToolkit().getScreenSize(); } }; // Fixing a bug caused by switch to Oracle Java (at least for Mac), although I must say the following // code is what should have worked to begin with. Bug was that sessions would appear only in the lower - // left hand corner of the screen. - this.frame.setPreferredSize(Toolkit.getDefaultToolkit().getScreenSize()); + // left-hand corner of the screen. + frame.setPreferredSize(Toolkit.getDefaultToolkit().getScreenSize()); getFrame().setContentPane(getDesktop()); getFrame().pack(); getFrame().setLocationRelativeTo(null); // This doesn't let the user resize the main window. -// getFrame().setExtendedState(Frame.MAXIMIZED_BOTH); Image image = ImageUtils.getImage(this, "tyler16.png"); getFrame().setIconImage(image); @@ -199,11 +187,27 @@ public void windowClosing(WindowEvent e) { SplashScreen.hide(); + if (Desktop.isDesktopSupported()) { + Desktop desktop = Desktop.getDesktop(); + + try { + desktop.setQuitHandler((e2, response) -> { + int result = JOptionPane.showConfirmDialog(null, + "Are you sure you want to quit? Any unsaved work will be lost.", + "Confirm Quit", JOptionPane.YES_NO_OPTION); + if (result == JOptionPane.YES_OPTION) { + response.performQuit(); + } else { + response.cancelQuit(); + } + }); + } catch (Exception e) { + TetradLogger.getInstance().forceLogMessage("Could not set quit handler on this platform.."); + } + } } - /** - * Exits the application gracefully. - */ + // Exits the application gracefully. private void exitApplication() { boolean succeeded = getDesktop().closeAllSessions(); @@ -223,7 +227,7 @@ private void exitApplication() { } private JFrame getFrame() { - return this.frame; + return frame; } private TetradDesktop getDesktop() { diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/app/CloseSessionAction.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/app/CloseSessionAction.java index d091485332..221cf4c4fd 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/app/CloseSessionAction.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/app/CloseSessionAction.java @@ -34,9 +34,7 @@ * * @author josephramsey */ -final class CloseSessionAction extends AbstractAction { - - private boolean saved; +public final class CloseSessionAction extends AbstractAction { /** * Creates a new close session action for the given desktop. @@ -70,7 +68,6 @@ public void actionPerformed(ActionEvent e) { if (response == JOptionPane.YES_OPTION) { SaveSessionAction saveSessionAction = new SaveSessionAction(); saveSessionAction.actionPerformed(e); - this.saved = saveSessionAction.isSaved(); } else if (response == JOptionPane.CANCEL_OPTION) { return; } @@ -89,10 +86,6 @@ public void actionPerformed(ActionEvent e) { public String toString() { return "Close session action."; } - - public boolean isSaved() { - return this.saved; - } } diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/app/SaveSessionAction.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/app/SaveSessionAction.java index 34e238a73c..0571573b3e 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/app/SaveSessionAction.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/app/SaveSessionAction.java @@ -31,6 +31,7 @@ import java.awt.event.ActionEvent; import java.io.IOException; import java.io.ObjectOutputStream; +import java.io.Serial; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -42,11 +43,12 @@ * @author josephramsey * @author Kevin V. Bui (kvb2@pitt.edu) */ -final class SaveSessionAction extends AbstractAction { +public final class SaveSessionAction extends AbstractAction { + @Serial private static final long serialVersionUID = -1812370698394158108L; - private boolean saved; + public static boolean saved = false; public SaveSessionAction() { super("Save Session"); @@ -69,7 +71,7 @@ public void actionPerformed(ActionEvent e) { if (Files.notExists(outputFile) || sessionWrapper.isNewSession()) { SaveSessionAsAction saveSessionAsAction = new SaveSessionAsAction(); saveSessionAsAction.actionPerformed(e); - this.saved = saveSessionAsAction.isSaved(); + saved = SaveSessionAsAction.saved; return; } @@ -80,7 +82,7 @@ public void actionPerformed(ActionEvent e) { if (ret == JOptionPane.NO_OPTION) { SaveSessionAsAction saveSessionAsAction = new SaveSessionAsAction(); saveSessionAsAction.actionPerformed(e); - this.saved = saveSessionAsAction.isSaved(); + saved = SaveSessionAsAction.saved; return; } @@ -89,7 +91,7 @@ public void actionPerformed(ActionEvent e) { class MyWatchedProceess extends WatchedProcess { @Override - public void watch() throws InterruptedException { + public void watch() { try (ObjectOutputStream objOut = new ObjectOutputStream(Files.newOutputStream(outputFile))) { sessionWrapper.setNewSession(false); objOut.writeObject(metadata); @@ -110,9 +112,4 @@ public void watch() throws InterruptedException { new MyWatchedProceess(); } - - public boolean isSaved() { - return this.saved; - } - } diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/app/SaveSessionAsAction.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/app/SaveSessionAsAction.java index 4a24898ffb..5e0a85a2ca 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/app/SaveSessionAsAction.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/app/SaveSessionAsAction.java @@ -33,6 +33,7 @@ import java.io.File; import java.io.IOException; import java.io.ObjectOutputStream; +import java.io.Serial; import java.nio.file.Files; import java.util.prefs.Preferences; @@ -41,11 +42,12 @@ * * @author josephramsey */ -final class SaveSessionAsAction extends AbstractAction { +public final class SaveSessionAsAction extends AbstractAction { + @Serial private static final long serialVersionUID = 2798487128341621686L; - private boolean saved; + public static boolean saved = false; public SaveSessionAsAction() { super("Save Session As..."); @@ -71,14 +73,14 @@ public void actionPerformed(ActionEvent e) { JOptionUtils.centeringComp(), true, "Save Session As...", sessionSaveLocation); if (file == null) { - this.saved = false; + saved = false; return; } if ((DesktopController.getInstance().existsSessionByName( file.getName()) && !(sessionWrapper.getName().equals(file.getName())))) { - this.saved = false; + saved = false; JOptionPane.showMessageDialog(JOptionUtils.centeringComp(), "Another session by that name is currently open. Please " + "\nclose that session first."); @@ -88,25 +90,24 @@ public void actionPerformed(ActionEvent e) { sessionWrapper.setName(file.getName()); sessionEditor.setName(file.getName()); - class MyWatchedProceess extends WatchedProcess { + class MyWatchedProcess extends WatchedProcess { @Override - public void watch() throws InterruptedException { + public void watch() { try (ObjectOutputStream objOut = new ObjectOutputStream(Files.newOutputStream(file.toPath()))) { + saved = false; objOut.writeObject(metadata); objOut.writeObject(sessionWrapper); sessionWrapper.setSessionChanged(false); sessionWrapper.setNewSession(false); - setSaved(true); -// this.saved = true; + saved = true; } catch (IOException exception) { exception.printStackTrace(System.err); JOptionPane.showMessageDialog(JOptionUtils.centeringComp(), "An error occurred while attempting to save the session."); - setSaved(false); -// this.saved = false; + saved = false; } DesktopController.getInstance().putMetadata(sessionWrapper, metadata); @@ -114,32 +115,6 @@ public void watch() throws InterruptedException { } } - new MyWatchedProceess(); - -// try (ObjectOutputStream objOut = new ObjectOutputStream(Files.newOutputStream(file.toPath()))) { -// objOut.writeObject(metadata); -// objOut.writeObject(sessionWrapper); -// -// sessionWrapper.setSessionChanged(false); -// sessionWrapper.setNewSession(false); -// this.saved = true; -// } catch (IOException exception) { -// exception.printStackTrace(System.err); -// -// JOptionPane.showMessageDialog(JOptionUtils.centeringComp(), -// "An error occurred while attempting to save the session."); -// this.saved = false; -// } -// -// DesktopController.getInstance().putMetadata(sessionWrapper, metadata); -// sessionEditor.firePropertyChange("name", null, file.getName()); - } - - public boolean isSaved() { - return this.saved; - } - - public void setSaved(boolean saved) { - this.saved = saved; + new MyWatchedProcess(); } } diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/app/TetradDesktop.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/app/TetradDesktop.java index 36118f24ae..61356c1932 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/app/TetradDesktop.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/app/TetradDesktop.java @@ -40,6 +40,7 @@ import java.awt.event.ActionEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.io.Serial; import java.util.List; import java.util.*; import java.util.prefs.Preferences; @@ -54,6 +55,7 @@ public final class TetradDesktop extends JPanel implements DesktopControllable, PropertyChangeListener { + @Serial private static final long serialVersionUID = -3415072280557904460L; /** @@ -62,14 +64,14 @@ public final class TetradDesktop extends JPanel implements DesktopControllable, private static final int MARGIN = 0; /** - * The desktop pane in which all of the session editors are located. + * The desktop pane in which all the session editors are located. */ private final JDesktopPane desktopPane; /** * Stores a list of keys for components added to the workbench. */ - private final List sessionNodeKeys; + private final List sessionNodeKeys; /** * A map from components in the desktop to the frames they're embedded in. @@ -190,7 +192,7 @@ public void addSessionEditor(SessionEditorIndirectRef editorRef) { } /** - * Adds the given componet to the given layer. + * Adds the given component to the given layer. */ public void addEditorWindow(EditorWindowIndirectRef windowRef, int layer) { EditorWindow window = (EditorWindow) windowRef; @@ -236,7 +238,7 @@ public void addEditorWindow(EditorWindowIndirectRef windowRef, int layer) { window.setLocation(x, y); window.setPreferredSize(new Dimension(width, height)); - // This line sometimes hangs, so I'm putting it in a watched process + // This line sometimes hangs, so I'm putting it in a watched process, // so it can be stopped by the user. Not ideal. // Window owner = (Window) getTopLevelAncestor(); // @@ -294,8 +296,7 @@ public void closeEmptySessions() { for (JInternalFrame frame : frames) { Object o = frame.getContentPane().getComponents()[0]; - if (o instanceof SessionEditor) { - SessionEditor sessionEditor = (SessionEditor) o; + if (o instanceof SessionEditor sessionEditor) { SessionEditorWorkbench workbench = sessionEditor .getSessionWorkbench(); Graph graph = workbench.getGraph(); @@ -313,9 +314,7 @@ public boolean existsSessionByName(String name) { for (JInternalFrame allFrame : allFrames) { Object o = allFrame.getContentPane().getComponents()[0]; - if (o instanceof SessionEditor) { - SessionEditor editor = (SessionEditor) o; - + if (o instanceof SessionEditor editor) { String editorName = editor.getName(); if (editorName.equals(name)) { return true; @@ -333,9 +332,7 @@ public Session getSessionByName(String name) { for (JInternalFrame allFrame : allFrames) { Object o = allFrame.getContentPane().getComponents()[0]; - if (o instanceof SessionEditor) { - SessionEditor editor = (SessionEditor) o; - + if (o instanceof SessionEditor editor) { String editorName = editor.getName(); if (editorName.equals(name)) { return editor.getSessionWorkbench().getSessionWrapper() @@ -380,14 +377,14 @@ public void propertyChange(PropertyChangeEvent e) { } } } else if ("closeFrame".equals(e.getPropertyName())) { - if (getFramesMap().containsKey(e.getSource())) { - JInternalFrame frame = getFramesMap().get(e.getSource()); + if (getFramesMap().containsKey((SessionEditor) e.getSource())) { + JInternalFrame frame = getFramesMap().get((SessionEditor) e.getSource()); frame.setVisible(false); frame.dispose(); } } else if ("name".equals(e.getPropertyName())) { - if (getFramesMap().containsKey(e.getSource())) { - JInternalFrame frame = getFramesMap().get(e.getSource()); + if (getFramesMap().containsKey((SessionEditor) e.getSource())) { + JInternalFrame frame = getFramesMap().get((SessionEditor) e.getSource()); String _name = (String) (e.getNewValue()); frame.setTitle(_name); setMainTitle(_name); @@ -413,7 +410,7 @@ public JDesktopPane getDesktopPane() { } /** - * Queries the user as to whether they would like to save their sessions. + * Queries the user whether they would like to save their sessions. * * @return true if the transaction was ended successfully, false if not (that is, canceled). */ @@ -449,19 +446,6 @@ public boolean closeAllSessions() { action.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "Dummy close action")); - if (!action.isSaved()) { - int ret2 = JOptionPane - .showConfirmDialog( - JOptionUtils.centeringComp(), - "This session was not saved. Close session and continue anyway?", - "Advise needed...", - JOptionPane.OK_CANCEL_OPTION); - - if (ret2 == JOptionPane.CANCEL_OPTION) { - return false; - } - } - closeFrontmostSession(); } @@ -495,15 +479,15 @@ public boolean isDisplayLogging() { /** * Sets whether the display log output should be displayed or not. If true then a text area roughly 20% of the * screen size will appear on the bottom and will display any log output, otherwise just the standard tetrad - * workbend is shown. + * workbench is shown. */ public void setDisplayLogging(boolean displayLogging) { if (displayLogging) { try { TetradLogger.getInstance().setNextOutputStream(); } catch (IllegalStateException e2) { - // TetradLogger.getInstance().removeNextOutputStream(); - e2.printStackTrace(); + TetradLogger.getInstance().forceLogMessage( + "Unable to setup logging, please restart Tetrad."); return; } diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/CheckKnowledgeEditor.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/CheckKnowledgeEditor.java new file mode 100644 index 0000000000..401cf9a5e6 --- /dev/null +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/CheckKnowledgeEditor.java @@ -0,0 +1,87 @@ +/////////////////////////////////////////////////////////////////////////////// +// 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.editor; + +import edu.cmu.tetrad.util.Parameters; +import edu.cmu.tetradapp.model.CheckKnowledgeModel; +import edu.cmu.tetradapp.model.EdgewiseComparisonModel; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.awt.*; + +/** + * Provides a little display/editor for notes in the session workbench. This may be elaborated in the future to allow + * marked up text. + * + * @author josephramsey + */ +public class CheckKnowledgeEditor extends JPanel { + + private static final long serialVersionUID = 7921819261142670181L; + + /** + * The model for the note. + */ + private final CheckKnowledgeModel comparison; + private final Parameters params; + private JTextArea area; + + /** + * Constructs the editor given the model + */ + public CheckKnowledgeEditor(CheckKnowledgeModel comparison) { + this.comparison = comparison; + this.params = comparison.getParams(); + setup(); + } + + //============================ Private Methods =========================// + private void setup() { + setLayout(new BorderLayout()); + + JPanel pane = new JPanel(); + + Font font = new Font("Monospaced", Font.PLAIN, 14); + area = new JTextArea(); + area.setText(tableTextWithHeader()); + + area.setFont(font); + + JScrollPane scrollTextPane = new JScrollPane(area); + scrollTextPane.setPreferredSize(new Dimension(500, 600)); + + pane.add(scrollTextPane, new BorderLayout()); + + add(pane); + + this.area.setText(comparison.getComparisonString()); + this.area.moveCaretPosition(0); + this.area.setSelectionStart(0); + this.area.setSelectionEnd(0); + + this.area.repaint(); + } + + private String tableTextWithHeader() { + return this.comparison.getComparisonString(); + } +} diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/DagEditor.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/DagEditor.java index 1f5441e5b8..002eeb875a 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/DagEditor.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/DagEditor.java @@ -263,7 +263,7 @@ private void initUI(DagWrapper dagWrapper) { @Override public void actionPerformed(ActionEvent e) { // Initialize helpSet - final String helpHS = "/resources/javahelp/TetradHelp.hs"; + final String helpHS = "/docs/javahelp/TetradHelp.hs"; try { URL url = this.getClass().getResource(helpHS); @@ -425,6 +425,7 @@ private JMenu createGraphMenu() { graph.add(new JMenuItem(new SelectDirectedAction(this.workbench))); graph.add(new JMenuItem(new SelectBidirectedAction(this.workbench))); graph.add(new JMenuItem(new SelectUndirectedAction(this.workbench))); + graph.add(new JMenuItem(new SelectTrianglesAction(this.workbench))); graph.add(new JMenuItem(new SelectLatentsAction(this.workbench))); // graph.add(new PagTypeSetter(getWorkbench())); diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/GraphEditor.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/GraphEditor.java index 97430d165d..2e205bdeba 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/GraphEditor.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/GraphEditor.java @@ -265,7 +265,7 @@ private void initUI(GraphWrapper graphWrapper) { @Override public void actionPerformed(ActionEvent e) { // Initialize helpSet - final String helpHS = "/resources/javahelp/TetradHelp.hs"; + final String helpHS = "/docs/javahelp/TetradHelp.hs"; try { URL url = this.getClass().getResource(helpHS); @@ -417,6 +417,7 @@ JMenuBar createGraphMenuBarNoEditing() { graph.add(new JMenuItem(new SelectDirectedAction(this.workbench))); graph.add(new JMenuItem(new SelectBidirectedAction(this.workbench))); graph.add(new JMenuItem(new SelectUndirectedAction(this.workbench))); + graph.add(new JMenuItem(new SelectTrianglesAction(this.workbench))); graph.add(new JMenuItem(new SelectLatentsAction(this.workbench))); // graph.addSeparator(); graph.add(new PagColorer(getWorkbench())); @@ -521,6 +522,7 @@ public void internalFrameClosed(InternalFrameEvent e1) { graph.add(new JMenuItem(new SelectDirectedAction(getWorkbench()))); graph.add(new JMenuItem(new SelectBidirectedAction(getWorkbench()))); graph.add(new JMenuItem(new SelectUndirectedAction(getWorkbench()))); + graph.add(new JMenuItem(new SelectTrianglesAction(getWorkbench()))); graph.add(new JMenuItem(new SelectLatentsAction(getWorkbench()))); graph.add(new PagColorer(getWorkbench())); diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/GraphSelectionEditor.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/GraphSelectionEditor.java index 563461d367..5a5dbc4d3f 100755 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/GraphSelectionEditor.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/GraphSelectionEditor.java @@ -95,7 +95,7 @@ public GraphSelectionEditor(GraphSelectionWrapper wrapper) { } // Initialize helpSet - Zhou - String helpHS = "/resources/javahelp/TetradHelp.hs"; + String helpHS = "/docs/javahelp/TetradHelp.hs"; try { URL url = this.getClass().getResource(helpHS); diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/HistogramPanel.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/HistogramPanel.java index cc5fc797b9..131012869d 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/HistogramPanel.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/HistogramPanel.java @@ -22,15 +22,11 @@ package edu.cmu.tetradapp.editor; import edu.cmu.tetrad.data.Histogram; -import edu.cmu.tetrad.graph.Node; import org.apache.commons.math3.util.FastMath; import javax.swing.*; import java.awt.*; import java.awt.event.MouseEvent; -import java.text.DecimalFormat; -import java.text.NumberFormat; -import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; @@ -44,10 +40,9 @@ public class HistogramPanel extends JPanel { "septile", "octile", "nontile", "decile"}; private static final Color LINE_COLOR = Color.GRAY.darker(); private final Histogram histogram; - private final NumberFormat format = new DecimalFormat("0.#");// NumberFormatUtil.getInstance().getNumberFormat(); private final Map rectMap = new LinkedHashMap<>(); - private boolean drawAxes = true; - private int paddingX; + private final boolean drawAxes; + private final int paddingX; private Color barColor = Color.RED.darker(); /** @@ -104,7 +99,7 @@ public String getToolTipText(MouseEvent evt) { */ public void paintComponent(Graphics graphics) { int paddingY = drawAxes ? 15 : 5; - int height = drawAxes ? getHeight() - 2 : getHeight() - 2; + int height = getHeight() - 2; int width = getWidth() - (drawAxes ? 4 : 2); int displayedHeight = (int) (height - paddingY); int space = drawAxes ? 2 : 1; @@ -144,8 +139,6 @@ public void paintComponent(Graphics graphics) { // draw the buttom line g2d.setColor(HistogramPanel.LINE_COLOR); - Node target = histogram.getTargetNode(); - // Draw axes. if (drawAxes) { // draw the side line @@ -175,32 +168,11 @@ public void setBarColor(Color barColor) { this.barColor = barColor; } - private Map pickGoodPointsAndValues(double minValue, double maxValue) { - double range = maxValue - minValue; - int powerOfTen = (int) FastMath.floor(FastMath.log(range) / FastMath.log(10)); - Map points = new HashMap<>(); - - int low = (int) FastMath.floor(minValue / FastMath.pow(10, powerOfTen)); - int high = (int) FastMath.ceil(maxValue / FastMath.pow(10, powerOfTen)); - - for (int i = low; i < high; i++) { - double realValue = i * FastMath.pow(10, powerOfTen); - Integer intValue = translateToInt(minValue, maxValue, realValue); - - if (intValue == null) { - continue; - } - - points.put(intValue, realValue); - } - - return points; - } - private Integer translateToInt(double minValue, double maxValue, double value) { if (minValue >= maxValue) { throw new IllegalArgumentException(); } + if (paddingX >= 332) { throw new IllegalArgumentException(); } diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/IndTestMenuItems.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/IndTestMenuItems.java index c50a94c805..db1c7850b6 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/IndTestMenuItems.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/IndTestMenuItems.java @@ -72,7 +72,7 @@ static void addIndependenceTestChoices(JMenu test, IndTestTypeSetter setter) { static void addContinuousTestMenuItems(JMenu test, IndTestTypeSetter setter) { IndTestType testType = setter.getTestType(); if (testType != IndTestType.FISHER_Z && - testType != IndTestType.FISHER_ZD && +// testType != IndTestType.FISHER_ZD && testType != IndTestType.SEM_BIC && testType != IndTestType.CONDITIONAL_CORRELATION && testType != IndTestType.LINEAR_REGRESSION && diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/LoadDataDialog.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/LoadDataDialog.java index 1a9e1429e5..261b98092d 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/LoadDataDialog.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/LoadDataDialog.java @@ -36,6 +36,7 @@ import java.awt.event.MouseEvent; import java.io.File; import java.io.IOException; +import java.io.Serial; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; @@ -53,6 +54,7 @@ */ public final class LoadDataDialog extends JPanel { + @Serial private static final long serialVersionUID = 2299304318793152418L; private final List loadedFiles; diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/MarkovCheckEditor.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/MarkovCheckEditor.java index 3e06f09bc4..c12f76cdb7 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/MarkovCheckEditor.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/MarkovCheckEditor.java @@ -18,7 +18,6 @@ // 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.editor; import edu.cmu.tetrad.algcomparison.independence.IndependenceWrapper; @@ -31,51 +30,55 @@ import edu.cmu.tetrad.search.IndependenceTest; import edu.cmu.tetrad.search.test.IndependenceResult; import edu.cmu.tetrad.search.test.MsepTest; -import edu.cmu.tetrad.util.NumberFormatUtil; -import edu.cmu.tetrad.util.ParamDescription; -import edu.cmu.tetrad.util.ParamDescriptions; -import edu.cmu.tetrad.util.Parameters; +import edu.cmu.tetrad.search.test.RowsSettable; +import edu.cmu.tetrad.util.*; import edu.cmu.tetradapp.model.MarkovCheckIndTestModel; import edu.cmu.tetradapp.ui.PaddingPanel; import edu.cmu.tetradapp.ui.model.IndependenceTestModel; import edu.cmu.tetradapp.ui.model.IndependenceTestModels; import edu.cmu.tetradapp.util.*; -import org.jetbrains.annotations.NotNull; - -import javax.swing.*; -import javax.swing.border.EmptyBorder; -import javax.swing.table.AbstractTableModel; -import javax.swing.table.DefaultTableCellRenderer; -import javax.swing.table.JTableHeader; +import static edu.cmu.tetradapp.util.ParameterComponents.toArray; import java.awt.*; +import java.awt.Point; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.lang.reflect.InvocationTargetException; import java.text.DecimalFormat; import java.text.NumberFormat; -import java.util.List; import java.util.*; +import java.util.List; import java.util.function.Function; import java.util.stream.Collectors; - -import static edu.cmu.tetradapp.util.ParameterComponents.toArray; - +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.JTableHeader; +import org.jetbrains.annotations.NotNull; /** - * Lists independence facts specified by user and allows the list to be sorted by independence fact or by p value. + * A model for the Markov check. The Markov check for a given graph and dataset + * checks whether the graph is Markov with respect to the dataset. The Markov + * check can be used to check whether a graph is Markov with respect to a + * dataset, or whether a graph is Markov with respect to a dataset and a set of + * variables. The Markov check can also be used to check whether a graph is + * Markov with respect to a dataset and a set of variables, given a set of + * knowledge. For facts of the form X _||_ Y | Z, X and Y should be in the last + * tier of the knowledge, and Z should be in previous tiers. * * @author josephramsey */ public class MarkovCheckEditor extends JPanel { + private final MarkovCheckIndTestModel model; private final NumberFormat nf = NumberFormatUtil.getInstance().getNumberFormat(); private final JLabel markovTestLabel = new JLabel("(Unspecified Test)"); - // private final JTextArea testDescTextArea = new JTextArea(); private final JComboBox indTestJComboBox = new JComboBox<>(); private final JComboBox conditioningSetTypeJComboBox = new JComboBox<>(); private final JLabel testLabel = new JLabel("(Unspecified Test)"); private final JLabel conditioningLabelDep = new JLabel("(Unspecified)"); private final JLabel conditioningLabelIndep = new JLabel("(Unspecified)"); + private final DoubleTextField percent; boolean updatingTestModels = true; private AbstractTableModel tableModelIndep; private AbstractTableModel tableModelDep; @@ -83,8 +86,12 @@ public class MarkovCheckEditor extends JPanel { private JLabel fractionDepLabelDep; private JLabel ksLabelDep; private JLabel ksLabelIndep; - private JLabel masLabelDep; - private JLabel masLabelIndep; + private JLabel binomialPLabelDep; + private JLabel binomialPLabelIndep; + private JLabel andersonDarlingA2LabelDep; + private JLabel andersonDarlingA2LabelIndep; + private JLabel andersonDarlingPLabelDep; + private JLabel andersonDarlingPLabelIndep; private int sortDir; private int lastSortCol; private IndependenceWrapper independenceWrapper; @@ -119,16 +126,17 @@ public MarkovCheckEditor(MarkovCheckIndTestModel model) { model.getMarkovCheck().setSetType(ConditioningSetType.GLOBAL_MARKOV); break; default: - throw new IllegalArgumentException("Unknown conditioning set type: " + - conditioningSetTypeJComboBox.getSelectedItem()); + throw new IllegalArgumentException("Unknown conditioning set type: " + + conditioningSetTypeJComboBox.getSelectedItem()); } class MyWatchedProcess extends WatchedProcess { + public void watch() { if (model.getMarkovCheck().getSetType() == ConditioningSetType.GLOBAL_MARKOV && model.getVars().size() > 12) { int ret = JOptionPane.showOptionDialog(MarkovCheckEditor.this, - "The all subsets option is exponential and can become extremely slow beyond 12" + - "\nvariables. You may possibly be required to force quit Tetrad. Continue?", "Warning", + "The all subsets option is exponential and can become extremely slow beyond 12" + + "\nvariables. You may possibly be required to force quit Tetrad. Continue?", "Warning", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, null, null ); @@ -162,6 +170,7 @@ public void watch() { indTestJComboBox.addActionListener(e -> { class MyWatchedProcess extends WatchedProcess { + public void watch() { setTest(); model.getMarkovCheck().generateResults(); @@ -186,7 +195,7 @@ public void watch() { setTest(); Graph _graph = model.getGraph(); - Graph graph = GraphUtils.replaceNodes(_graph, model.getMarkovCheck().getVariables()); + Graph graph = GraphUtils.replaceNodes(_graph, model.getMarkovCheck().getVariables(model.getGraph().getNodes(), model.getMarkovCheck().getIndependenceNodes(), model.getMarkovCheck().getConditioningNodes())); JPanel indep = buildGuiIndep(); JPanel dep = buildGuiDep(); @@ -195,7 +204,7 @@ public void watch() { tableModelDep.fireTableDataChanged(); Graph sourceGraph = model.getGraph(); - List variables = model.getMarkovCheck().getVariables(); + List variables = model.getMarkovCheck().getVariables(model.getGraph().getNodes(), model.getMarkovCheck().getIndependenceNodes(), model.getMarkovCheck().getConditioningNodes()); List newVars = new ArrayList<>(); @@ -212,25 +221,42 @@ public void watch() { for (Node w : sourceGraph.getNodes()) { if (model.getMarkovCheck().getVariable(w.getName()) == null) { missingVars.add(w); - if (missingVars.size() >= 5) break; + if (missingVars.size() >= 5) { + break; + } } } if (!missingVars.isEmpty()) { - throw new IllegalArgumentException("At least these variables in the DAG are missing from the data:" + - "\n " + missingVars); + throw new IllegalArgumentException("At least these variables in the DAG are missing from the data:" + + "\n " + missingVars); } model.setVars(graph.getNodeNames()); - Box box = Box.createVerticalBox(); - Box box1 = Box.createHorizontalBox(); - box1.add(Box.createHorizontalStrut(20)); - box1.add(new JLabel("Test:")); - box1.add(indTestJComboBox); JButton params = new JButton("Params"); - box1.add(params); - box1.add(Box.createHorizontalGlue()); + JButton recalculate = new JButton("Recalculate"); + + this.percent = new DoubleTextField(0.5, 4, new DecimalFormat("0.0###")); + + JLabel percentSampleLabel; + if (model.getMarkovCheck().getIndependenceTest().getData() != null) { + percentSampleLabel = new JLabel("% Sample:"); + } else if (!(model.getMarkovCheck().getIndependenceTest() instanceof RowsSettable)) { + percentSampleLabel = new JLabel("(Test cannot be subsampled)"); + } else { + percentSampleLabel = new JLabel("(Not tabular data)"); + } + + recalculate.addActionListener(e -> refreshResult(model, percent)); + + percent.setFilter((value, oldValue) -> { + if (value < 0.0 || value > 1.0) { + return oldValue; + } else { + return value; + } + }); setLabelTexts(); @@ -242,34 +268,14 @@ class MyWatchedProcess2 extends WatchedProcess { @Override public void watch() { - setTest(); - model.getMarkovCheck().generateResults(); - tableModelIndep.fireTableDataChanged(); - tableModelDep.fireTableDataChanged(); - histogramPanelDep.removeAll(); - histogramPanelIndep.removeAll(); - histogramPanelDep.add(createHistogramPanel(false), BorderLayout.CENTER); - histogramPanelIndep.add(createHistogramPanel(true), BorderLayout.CENTER); - histogramPanelDep.validate(); - histogramPanelIndep.validate(); - histogramPanelDep.repaint(); - histogramPanelIndep.repaint(); - setLabelTexts(); + refreshResult(model, percent); } } new MyWatchedProcess2(); }); - box.add(box1); - - Box box2 = Box.createHorizontalBox(); - box2.add(Box.createHorizontalStrut(20)); - box2.add(new JLabel("Conditioning Sets:")); - box2.add(conditioningSetTypeJComboBox); - box2.add(Box.createHorizontalGlue()); - - box.add(box2); + JLabel conditioningSetsLabel = new JLabel("Conditioning Sets:"); JTextArea testDescTextArea = new JTextArea(getHelpMessage()); testDescTextArea.setEditable(true); @@ -278,16 +284,13 @@ public void watch() { JScrollPane scroll = new JScrollPane(testDescTextArea); scroll.setPreferredSize(new Dimension(600, 400)); - JTabbedPane pane = new JTabbedPane(); pane.addTab("Check Markov", indep); pane.addTab("Check Dependent Distribution", dep); - pane.addTab("Help", scroll); - box.add(pane); - -// setPreferredSize(new Dimension(750, 550)); + pane.addTab("Help", new PaddingPanel(scroll)); class MyWatchedProcess extends WatchedProcess { + public void watch() { setTest(); model.getMarkovCheck().generateResults(); @@ -306,37 +309,123 @@ public void watch() { } new MyWatchedProcess(); + // add(box); + initComponents(params, recalculate, pane, conditioningSetsLabel, percentSampleLabel); + } + + private void initComponents(JButton params, JButton recalculate, JTabbedPane pane, JLabel conditioningSetsLabel, JLabel percentSampleLabel) { + GroupLayout layout = new GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(pane) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(conditioningSetsLabel) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(conditioningSetTypeJComboBox, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addComponent(testLabel) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(indTestJComboBox, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(params) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(recalculate) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(percentSampleLabel) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(percent, GroupLayout.PREFERRED_SIZE, 46, GroupLayout.PREFERRED_SIZE))) + .addGap(0, 0, Short.MAX_VALUE))) + .addContainerGap()) + ); + layout.setVerticalGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(testLabel) + .addComponent(indTestJComboBox, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addComponent(params) + .addComponent(recalculate) + .addComponent(percentSampleLabel) + .addComponent(percent, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(conditioningSetTypeJComboBox, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addComponent(conditioningSetsLabel)) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(pane, GroupLayout.DEFAULT_SIZE, 442, Short.MAX_VALUE) + .addContainerGap()) + ); + } -// box.setPreferredSize(new Dimension(750, 550)); + @NotNull + public static String getHelpMessage() { + return """ + This tool lets you plot statistics for independence tests of a pair of variables given some conditioning calculated for one of those variables, for a given graph and dataset. Two tables are made, one in which the independence facts predicted by the graph using these conditioning sets are tested in the data and the other in which the graph's predicted dependence facts are tested. The first of these sets is a check for "Markov" (a check for implied independence facts) for the chosen conditioning sets; the is a check of the "Dependent Distribution." (a check of implied dependence facts)” + + Each table gives columns for the independence fact being checked, its test result, and its statistic. This statistic is either a p-value, ranging from 0 to 1, where p-values above the alpha level of the test are judged as independent, or a score bump, where this bump is negative for independent judgments and positive for dependent judgments. + + If the independence test yields a p-value, as for instance, for the Fisher Z test (for the linear, Gaussian case) or else the Chi-Square test (for the multinomial case), then under the null hypothesis of independence and for a consistent test, these p-values should be distributed as Uniform(0, 1). That is, it should be just as likely to see p-values in any range of equal width. If the test is inconsistent or the graph is incorrect (i.e., the parents of some or all of the nodes in the graph are incorrect), then this distribution of p-values will not be Uniform. To visualize this, we display the histogram of the p-values with equally sized bins; the bars in this histogram, for this case, should ideally all be of equal height. + + If the first bar in this histogram is especially high (for the p-value case), that means that many tests are being judged as dependent. For checking the dependent distribution, one hopes that this list is non-empty, in which case this first bar will be especially high since high p-values are examples where the graph is unfaithful to the distribution. These are possibly for cases where paths in the graph cancel unfaithfully. But for checking Markov, one hopes that this first bar will be the same height as all of the other bars. + + To make it especially clear, we give two statistics in the interface. The first is the percentage of p-values judged dependent on the test. If an alpha level is used in the test, this number should be very close to the alpha level for the Local Markov check since the distribution of p-values under this condition is Uniform. For the second, we test the Uniformity of the p-values using a Kolmogorov-Smirnov test. The p-value returned by this test should be greater than the user’s preferred alpha level if the distribution of p-values is Uniform and less than this alpha level if the distribution of p-values is non-uniform. + + If the independence test yields a bump in the score, this score should be negative for independence judgments and positive for dependence judgments. The histogram will reflect this. + + Feel free to select all of the data in the tables, copy it, and paste it into a text file or into Excel. This will let you analyze the data yourself. + + A note about Markov Blankets: The "Markov Blanket" conditioning set choice implements the Markov blanket calculation in a way that is correct for DAGs, CPDAGs, MAGs, and PAGs. For all of these graph types, the list of m-connecting facts in the Faithfulness tab should be empty, since the Markov blanket should screen off the target from any other variables in the dataset. It's possible that for some other graph types, this list may not be empty (i.e., the Markov blanket calculation may not be correct). - add(box); + Knowledge may be supplied to the Markov Checker. This will be interpreted as follows. For X _||_ Y | Z checked, X and Y will be drawn from the last tier of the knowledge, and the variables in Z will be drawn from all variables in tiers. Additional forbidden or required edges are not allowed. + """; } @NotNull - private static String getHelpMessage() { - return "This tool lets you plot statistics for independence tests of a pair of variables given some conditioning calculated for one of those variables, for a given graph and dataset. Two tables are made, one in which the independence facts predicted by the graph using these conditioning sets are tested in the data and the other in which the graph's predicted dependence facts are tested. The first of these sets is a check for \"Markov\" (a check for implied independence facts) for the chosen conditioning sets; the is a check of the \"Dependent Distribution.\" (a check of implied dependence facts)”\n" + - "\n" + - "Each table gives columns for the independence fact being checked, its test result, and its statistic. This statistic is either a p-value, ranging from 0 to 1, where p-values above the alpha level of the test are judged as independent, or a score bump, where this bump is negative for independent judgments and positive for dependent judgments.\n" + - "\n" + - "If the independence test yields a p-value, as for instance, for the Fisher Z test (for the linear, Gaussian case) or else the Chi-Square test (for the multinomial case), then under the null hypothesis of independence and for a consistent test, these p-values should be distributed as Uniform(0, 1). That is, it should be just as likely to see p-values in any range of equal width. If the test is inconsistent or the graph is incorrect (i.e., the parents of some or all of the nodes in the graph are incorrect), then this distribution of p-values will not be Uniform. To visualize this, we display the histogram of the p-values with equally sized bins; the bars in this histogram, for this case, should ideally all be of equal height.\n" + - "\n" + - "If the first bar in this histogram is especially high (for the p-value case), that means that many tests are being judged as dependent. For checking the dependent distribution, one hopes that this list is non-empty, in which case this first bar will be especially high, since high p-values are for examples where the graph is unfaithful to the distribution. These are likely for for cases where paths in the graph cancel unfaithfully. But for checking Markov, one hopes that this first bar will be the same height as all of the other bars.\n" + - "\n" + - "To make it especially clear, we give two statistics in the interface. The first is the percentage of p-values judged dependent on the test. If an alpha level is used in the test, this number should be very close to the alpha level for the Local Markov check since the distribution of p-values under this condition is Uniform. For the second, we test the Uniformity of the p-values using a Kolmogorov-Smirnov test. The p-value returned by this test should be greater than the user’s preferred alpha level if the distribution of p-values is Uniform and less then this alpha level if the distribution of p-values is non-Uniform.\n" + - "\n" + - "If the independence test yields a bump in the score, this score should be negative for independence judgments and positive for dependence judgments. The histogram will reflect this.\n" + - "\n" + - "Feel free to select all of the data in the tables, copy it, and paste it into a text file or into Excel. This will let you analyze the data yourself.\n" + - "\n" + - "A note about Markov Blankets: The \"Markov Blanket\" conditioning set choice implements the Markov blanket calculation in a way that is correct for DAGs, CPDAGs, MAGs, and PAGs. For all of these graph types, the list of m-connecting facts in the Faithfulness tab should be empty, since the Markov blanket should screen off the target from any other variables in the dataset. It's possible that for some other graph types this list may not be empty (i.e., the Markov blanket calculation may not be correct)."; + private static HistogramPanel getHistogramPanel(List results) { + DataSet dataSet = new BoxDataSet(new VerticalDoubleDataBox(results.size(), 1), + Collections.singletonList(new ContinuousVariable("P-Value or Bump"))); + + for (int i = 0; i < results.size(); i++) { + dataSet.setDouble(i, 0, results.get(i).getPValue()); + } + + Histogram histogram = new Histogram(dataSet, "P-Value or Bump", false); + HistogramPanel view = new HistogramPanel(histogram, true); + + Color fillColor = new Color(113, 165, 210); + view.setBarColor(fillColor); + + view.setMaximumSize(new Dimension(300, 200)); + return view; } //========================PUBLIC METHODS==========================// + private void refreshResult(MarkovCheckIndTestModel model, DoubleTextField percent) { + setTest(); + + model.getMarkovCheck().setPercentResample(percent.getValue()); + model.getMarkovCheck().generateResults(); + tableModelIndep.fireTableDataChanged(); + tableModelDep.fireTableDataChanged(); + histogramPanelIndep.removeAll(); + histogramPanelDep.add(createHistogramPanel(false), BorderLayout.CENTER); + histogramPanelIndep.add(createHistogramPanel(true), BorderLayout.CENTER); + histogramPanelDep.validate(); + histogramPanelIndep.validate(); + histogramPanelDep.repaint(); + histogramPanelIndep.repaint(); + setLabelTexts(); + } private void setTest() { IndependenceTestModel selectedItem = (IndependenceTestModel) indTestJComboBox.getSelectedItem(); Class clazz = (selectedItem == null) ? null - : selectedItem.getIndependenceTest().getClazz(); + : selectedItem.getIndependenceTest().clazz(); IndependenceTest independenceTest; if (clazz != null) { @@ -348,39 +437,27 @@ private void setTest() { testLabel.setText(model.getMarkovCheck().getIndependenceTest().toString()); invalidate(); repaint(); - } catch (InstantiationException | IllegalAccessException | InvocationTargetException | - NoSuchMethodException e1) { - e1.printStackTrace(); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException + | NoSuchMethodException e1) { + TetradLogger.getInstance().forceLogMessage("Error: " + e1.getMessage()); throw new RuntimeException(e1); } } - } - /** - * Performs the action of opening a session from a file. - */ - private JPanel buildGuiDep() { + private JPanel buildGuiIndep() { + JPanel tablelPanel = new JPanel(new BorderLayout()); - Box b1 = Box.createVerticalBox(); - Box b2 = Box.createHorizontalBox(); String setType = (String) conditioningSetTypeJComboBox.getSelectedItem(); - conditioningLabelDep.setText("Tests graphical predictions of Dep(X, Y | " + setType + ")"); - b2.add(conditioningLabelDep); - b2.add(Box.createHorizontalGlue()); - b1.add(b2); + conditioningLabelIndep.setText("Tests graphical predictions of Indep(X, Y | " + setType + ")"); + tablelPanel.add(conditioningLabelIndep, BorderLayout.NORTH); markovTestLabel.setText(model.getMarkovCheck().getIndependenceTest().toString()); testLabel.setText(model.getMarkovCheck().getIndependenceTest().toString()); - Box b2a = Box.createHorizontalBox(); - b2a.add(Box.createHorizontalGlue()); - b1.add(b2a); - b1.add(Box.createVerticalStrut(5)); - - this.tableModelDep = new AbstractTableModel() { + this.tableModelIndep = new AbstractTableModel() { public String getColumnName(int column) { if (column == 0) { return "Index"; @@ -389,39 +466,39 @@ public String getColumnName(int column) { } else if (column == 2) { return "Test Result"; } else if (column == 3) { - return "P-Value or Bump"; + return "P-value or Bump"; } return null; } public int getColumnCount() { - return 4;//2 + MarkovFactsEditor.this.indTestProducers.size(); + return 4; } public int getRowCount() { - return model.getResults(false).size(); + List results = model.getResults(true); + return results.size(); } public Object getValueAt(int rowIndex, int columnIndex) { - if (rowIndex > model.getResults(false).size()) return null; + if (rowIndex > model.getResults(true).size()) { + return null; + } if (columnIndex == 0) { return rowIndex + 1; } - if (columnIndex == 1) { - IndependenceFact fact = model.getResults(false).get(rowIndex).getFact(); - List Z = new ArrayList<>(fact.getZ()); - Collections.sort(Z); + IndependenceResult result = model.getResults(true).get(rowIndex); + if (columnIndex == 1) { + IndependenceFact fact = model.getResults(true).get(rowIndex).getFact(); + List Z = new ArrayList<>(fact.getZ()); String z = Z.stream().map(Node::getName).collect(Collectors.joining(", ")); - - return "Dep(" + fact.getX() + ", " + fact.getY() + (Z.isEmpty() ? "" : " | " + z) + ")"; + return "Ind(" + fact.getX() + ", " + fact.getY() + (Z.isEmpty() ? "" : " | " + z) + ")"; } - IndependenceResult result = model.getResults(false).get(rowIndex); - if (columnIndex == 2) { if (model.getMarkovCheck().getIndependenceTest() instanceof MsepTest) { if (result.isIndependent()) { @@ -457,9 +534,9 @@ public Class getColumnClass(int columnIndex) { } }; - JTable table = new JTable(tableModelDep); + JTable table = new JTable(tableModelIndep); - tableModelDep.addTableModelListener(e -> { + tableModelIndep.addTableModelListener(e -> { if (e.getColumn() == 2) { table.revalidate(); table.repaint(); @@ -478,7 +555,6 @@ public Class getColumnClass(int columnIndex) { table.getColumnModel().getColumn(2).setCellRenderer(new Renderer()); table.getColumnModel().getColumn(3).setCellRenderer(new Renderer()); - JTableHeader header = table.getTableHeader(); header.addMouseListener(new MouseAdapter() { @@ -488,89 +564,73 @@ public void mouseClicked(MouseEvent e) { int col = header.columnAtPoint(point); int sortCol = header.getTable().convertColumnIndexToModel(col); - MarkovCheckEditor.this.sortByColumn(sortCol, false); + MarkovCheckEditor.this.sortByColumn(sortCol, true); } }); JScrollPane scroll = new JScrollPane(table); -// scroll.setPreferredSize(new Dimension(400, 400)); - b1.add(scroll); + tablelPanel.add(scroll, BorderLayout.CENTER); - Box b1a = Box.createHorizontalBox(); JLabel label = new JLabel("Table contents can be selected and copied in to, e.g., Excel."); - b1a.add(label); - b1a.add(Box.createHorizontalGlue()); - b1.add(b1a); - - Box b4 = Box.createHorizontalBox(); - b4.add(Box.createGlue()); - b4.add(Box.createHorizontalStrut(10)); - - b4.add(Box.createHorizontalGlue()); - - Box b5 = Box.createHorizontalBox(); - b5.add(Box.createGlue()); + tablelPanel.add(label, BorderLayout.SOUTH); setLabelTexts(); - Box b0 = Box.createHorizontalBox(); - b0.add(b1); - b0.add(Box.createHorizontalStrut(10)); - - Box b0b1 = Box.createVerticalBox(); - b0b1.add(Box.createVerticalGlue()); - histogramPanelDep = new JPanel(); - histogramPanelDep.setLayout(new BorderLayout()); - histogramPanelDep.setBorder(new EmptyBorder(10, 10, 10, 10)); - histogramPanelIndep.add(createHistogramPanel(false), BorderLayout.CENTER); - - b0b1.add(histogramPanelDep); - b5.add(fractionDepLabelDep); - b0b1.add(b5); - - Box b6 = Box.createHorizontalBox(); - b6.add(Box.createHorizontalGlue()); - b6.add(ksLabelDep); - b0b1.add(b6); - - Box b7 = Box.createHorizontalBox(); - b7.add(Box.createHorizontalGlue()); - b7.add(masLabelDep); - b0b1.add(b7); - - b0b1.add(Box.createVerticalGlue()); - b0.add(b0b1); - - JPanel panel = new JPanel(); - panel.setLayout(new BorderLayout()); - panel.add(b0, BorderLayout.CENTER); - panel.setBorder(new EmptyBorder(10, 10, 10, 10)); - return panel; + Box a4 = Box.createVerticalBox(); + histogramPanelIndep = new JPanel(); + histogramPanelIndep.setLayout(new BorderLayout()); + histogramPanelIndep.setBorder(new EmptyBorder(10, 10, 10, 10)); + histogramPanelIndep.add(createHistogramPanel(true), BorderLayout.CENTER); + a4.add(histogramPanelIndep); + + Box a5 = Box.createHorizontalBox(); + a5.add(Box.createHorizontalGlue()); + a5.add(fractionDepLabelIndep); + a4.add(a5); + + Box a6 = Box.createHorizontalBox(); + a6.add(Box.createHorizontalGlue()); + a6.add(ksLabelIndep); + a4.add(a6); + + Box a7 = Box.createHorizontalBox(); + a7.add(Box.createHorizontalGlue()); + a7.add(binomialPLabelIndep); + a4.add(a7); + + Box a8 = Box.createHorizontalBox(); + a8.add(Box.createHorizontalGlue()); + a8.add(andersonDarlingA2LabelIndep); + a4.add(a8); + + Box a9 = Box.createHorizontalBox(); + a9.add(Box.createHorizontalGlue()); + a9.add(andersonDarlingPLabelIndep); + a4.add(a9); + + JPanel checkMarkovPanel = new JPanel(new BorderLayout()); + checkMarkovPanel.add(new PaddingPanel(tablelPanel), BorderLayout.CENTER); + checkMarkovPanel.add(new PaddingPanel(a4), BorderLayout.EAST); + + return checkMarkovPanel; } - private JPanel buildGuiIndep() { - - Box b1 = Box.createVerticalBox(); - - Box b2 = Box.createHorizontalBox(); + /** + * Performs the action of opening a session from a file. + */ + private JPanel buildGuiDep() { + JPanel tablelPanel = new JPanel(new BorderLayout()); String setType = (String) conditioningSetTypeJComboBox.getSelectedItem(); - conditioningLabelIndep.setText("Tests graphical predictions of Indep(X, Y | " + setType + ")"); - b2.add(conditioningLabelIndep); - b2.add(Box.createHorizontalGlue()); - b1.add(b2); + conditioningLabelDep.setText("Tests graphical predictions of Dep(X, Y | " + setType + ")"); + tablelPanel.add(conditioningLabelDep, BorderLayout.NORTH); markovTestLabel.setText(model.getMarkovCheck().getIndependenceTest().toString()); testLabel.setText(model.getMarkovCheck().getIndependenceTest().toString()); - Box b2a = Box.createHorizontalBox(); - b2a.add(Box.createHorizontalGlue()); - b1.add(b2a); - - b1.add(Box.createVerticalStrut(5)); - - this.tableModelIndep = new AbstractTableModel() { +// a1.add(Box.createVerticalStrut(5)); + this.tableModelDep = new AbstractTableModel() { public String getColumnName(int column) { if (column == 0) { return "Index"; @@ -586,7 +646,7 @@ public String getColumnName(int column) { } public int getColumnCount() { - return 4;//2 + MarkovFactsEditor.this.indTestProducers.size(); + return 4; } public int getRowCount() { @@ -595,7 +655,9 @@ public int getRowCount() { } public Object getValueAt(int rowIndex, int columnIndex) { - if (rowIndex > model.getResults(true).size()) return null; + if (rowIndex > model.getResults(true).size()) { + return null; + } if (columnIndex == 0) { return rowIndex + 1; @@ -605,12 +667,8 @@ public Object getValueAt(int rowIndex, int columnIndex) { if (columnIndex == 1) { IndependenceFact fact = model.getResults(true).get(rowIndex).getFact(); - List Z = new ArrayList<>(fact.getZ()); - Collections.sort(Z); - String z = Z.stream().map(Node::getName).collect(Collectors.joining(", ")); - return "Ind(" + fact.getX() + ", " + fact.getY() + (Z.isEmpty() ? "" : " | " + z) + ")"; } @@ -649,9 +707,9 @@ public Class getColumnClass(int columnIndex) { } }; - JTable table = new JTable(tableModelIndep); + JTable table = new JTable(tableModelDep); - tableModelIndep.addTableModelListener(e -> { + tableModelDep.addTableModelListener(e -> { if (e.getColumn() == 2) { table.revalidate(); table.repaint(); @@ -670,7 +728,6 @@ public Class getColumnClass(int columnIndex) { table.getColumnModel().getColumn(2).setCellRenderer(new Renderer()); table.getColumnModel().getColumn(3).setCellRenderer(new Renderer()); - JTableHeader header = table.getTableHeader(); header.addMouseListener(new MouseAdapter() { @@ -680,65 +737,61 @@ public void mouseClicked(MouseEvent e) { int col = header.columnAtPoint(point); int sortCol = header.getTable().convertColumnIndexToModel(col); - MarkovCheckEditor.this.sortByColumn(sortCol, true); + MarkovCheckEditor.this.sortByColumn(sortCol, false); } }); JScrollPane scroll = new JScrollPane(table); -// scroll.setPreferredSize(new Dimension(400, 400)); - b1.add(scroll); + tablelPanel.add(scroll, BorderLayout.CENTER); - Box b1a = Box.createHorizontalBox(); + Box a3 = Box.createHorizontalBox(); JLabel label = new JLabel("Table contents can be selected and copied in to, e.g., Excel."); - b1a.add(label); - b1a.add(Box.createHorizontalGlue()); - b1.add(b1a); - - Box b4 = Box.createHorizontalBox(); - b4.add(Box.createGlue()); - b4.add(Box.createHorizontalStrut(10)); - - b4.add(Box.createHorizontalGlue()); - - Box b5 = Box.createHorizontalBox(); - b5.add(Box.createGlue()); + a3.add(label); + a3.add(Box.createHorizontalGlue()); + tablelPanel.add(label, BorderLayout.SOUTH); setLabelTexts(); - Box b0 = Box.createHorizontalBox(); - b0.add(b1); - b0.add(Box.createHorizontalStrut(10)); - - Box b0b1 = Box.createVerticalBox(); - b0b1.add(Box.createVerticalGlue()); - histogramPanelIndep = new JPanel(); - histogramPanelIndep.setLayout(new BorderLayout()); - histogramPanelIndep.setBorder(new EmptyBorder(10, 10, 10, 10)); - histogramPanelIndep.add(createHistogramPanel(true), BorderLayout.CENTER); - b0b1.add(histogramPanelIndep); - b0b1.add(Box.createVerticalGlue()); - - b5.add(fractionDepLabelIndep); - b0b1.add(b5); - - Box b6 = Box.createHorizontalBox(); - b6.add(Box.createHorizontalGlue()); - b6.add(ksLabelIndep); - b0b1.add(b6); - - Box b7 = Box.createHorizontalBox(); - b7.add(Box.createHorizontalGlue()); - b7.add(masLabelIndep); - b0b1.add(b7); - - b0.add(b0b1); - - JPanel panel = new JPanel(); - panel.setLayout(new BorderLayout()); - panel.add(b0, BorderLayout.CENTER); - - panel.setBorder(new EmptyBorder(10, 10, 10, 10)); - return panel; + Box a4 = Box.createVerticalBox(); + histogramPanelDep = new JPanel(); + histogramPanelDep.setLayout(new BorderLayout()); + histogramPanelDep.setBorder(new EmptyBorder(10, 10, 10, 10)); + histogramPanelDep.add(createHistogramPanel(true), BorderLayout.CENTER); + a4.add(histogramPanelDep); + + Box a5 = Box.createHorizontalBox(); + a5.add(Box.createHorizontalGlue()); + a5.add(fractionDepLabelDep); + a4.add(a5); + + Box a6 = Box.createHorizontalBox(); + a6.add(Box.createHorizontalGlue()); + a6.add(ksLabelDep); + a4.add(a6); + + Box a7 = Box.createHorizontalBox(); + a7.add(Box.createHorizontalGlue()); + a7.add(binomialPLabelDep); + a4.add(a7); + + Box a8 = Box.createHorizontalBox(); + a8.add(Box.createHorizontalGlue()); + a8.add(andersonDarlingA2LabelDep); + a4.add(a8); + + Box a9 = Box.createHorizontalBox(); + a9.add(Box.createHorizontalGlue()); + a9.add(andersonDarlingPLabelDep); + a4.add(a9); + + Box a11 = Box.createHorizontalBox(); + a11.add(a4); + + JPanel checkDependDistributionPanel = new JPanel(new BorderLayout()); + checkDependDistributionPanel.add(new PaddingPanel(tablelPanel), BorderLayout.CENTER); + checkDependDistributionPanel.add(new PaddingPanel(a4), BorderLayout.EAST); + + return checkDependDistributionPanel; } private void sortByColumn(int sortCol, boolean indep) { @@ -768,30 +821,72 @@ private void setLabelTexts() { ksLabelDep = new JLabel(); } - if (fractionDepLabelIndep == null) { - fractionDepLabelIndep = new JLabel(); + if (binomialPLabelIndep == null) { + binomialPLabelIndep = new JLabel(); } - if (fractionDepLabelDep == null) { - fractionDepLabelDep = new JLabel(); + if (binomialPLabelDep == null) { + binomialPLabelDep = new JLabel(); + } + + if (andersonDarlingA2LabelIndep == null) { + andersonDarlingA2LabelIndep = new JLabel(); + } + + if (andersonDarlingA2LabelDep == null) { + andersonDarlingA2LabelDep = new JLabel(); + } + + if (andersonDarlingPLabelIndep == null) { + andersonDarlingPLabelIndep = new JLabel(); } - if (masLabelIndep == null) { - masLabelIndep = new JLabel(); + if (andersonDarlingPLabelDep == null) { + andersonDarlingPLabelDep = new JLabel(); } - if (masLabelDep == null) { - masLabelDep = new JLabel(); + if (fractionDepLabelIndep == null) { + fractionDepLabelIndep = new JLabel(); } - ksLabelIndep.setText("P-value of Kolmogorov-Smirnov Uniformity Test = " + if (fractionDepLabelDep == null) { + fractionDepLabelDep = new JLabel(); + } + + ksLabelIndep.setText("P-value of KS Uniformity Test = " + ((Double.isNaN(model.getMarkovCheck().getKsPValue(true)) ? "-" : NumberFormatUtil.getInstance().getNumberFormat().format(model.getMarkovCheck().getKsPValue(true))))); - ksLabelDep.setText("P-value of Kolmogorov-Smirnov Uniformity Test = " + ksLabelDep.setText("P-value of KS Uniformity Test = " + ((Double.isNaN(model.getMarkovCheck().getKsPValue(false)) ? "-" : NumberFormatUtil.getInstance().getNumberFormat().format(model.getMarkovCheck().getKsPValue(false))))); + + andersonDarlingA2LabelIndep.setText("A^2 = " + + ((Double.isNaN(model.getMarkovCheck().getAndersonDarlingA2Star(true)) + ? "-" + : NumberFormatUtil.getInstance().getNumberFormat().format(model.getMarkovCheck().getAndersonDarlingA2Star(true))))); + andersonDarlingA2LabelDep.setText("A^2* = " + + ((Double.isNaN(model.getMarkovCheck().getAndersonDarlingA2Star(false)) + ? "-" + : NumberFormatUtil.getInstance().getNumberFormat().format(model.getMarkovCheck().getAndersonDarlingA2Star(false))))); + + andersonDarlingPLabelIndep.setText("P-value of the Anderson-Darling test = " + + ((Double.isNaN(model.getMarkovCheck().getAndersonDarlingP(true)) + ? "-" + : NumberFormatUtil.getInstance().getNumberFormat().format(model.getMarkovCheck().getAndersonDarlingP(true))))); + andersonDarlingPLabelDep.setText("P-value of the Anderson-Darling test = " + + ((Double.isNaN(model.getMarkovCheck().getAndersonDarlingP(false)) + ? "-" + : NumberFormatUtil.getInstance().getNumberFormat().format(model.getMarkovCheck().getAndersonDarlingP(false))))); + binomialPLabelIndep.setText("P-value of Binomial Test = " + + ((Double.isNaN(model.getMarkovCheck().getBinomialP(true)) + ? "-" + : NumberFormatUtil.getInstance().getNumberFormat().format(model.getMarkovCheck().getBinomialP(true))))); + binomialPLabelDep.setText("P-value of Binomial Test = " + + ((Double.isNaN(model.getMarkovCheck().getBinomialP(false)) + ? "-" + : NumberFormatUtil.getInstance().getNumberFormat().format(model.getMarkovCheck().getBinomialP(false))))); fractionDepLabelIndep.setText("% dependent = " + ((Double.isNaN(model.getMarkovCheck().getFractionDependent(true)) ? "-" @@ -800,21 +895,11 @@ private void setLabelTexts() { + ((Double.isNaN(model.getMarkovCheck().getFractionDependent(false)) ? "-" : NumberFormatUtil.getInstance().getNumberFormat().format(model.getMarkovCheck().getFractionDependent(false))))); - masLabelIndep.setText("Markov Adequacy Score = " - + ((Double.isNaN(model.getMarkovCheck().getMarkovAdequacyScore(0.01)) - ? "-" - : NumberFormatUtil.getInstance().getNumberFormat().format(model.getMarkovCheck().getMarkovAdequacyScore(0.01))))); - masLabelDep.setText("Markov Adequacy Score = " - + ((Double.isNaN(model.getMarkovCheck().getMarkovAdequacyScore(0.01)) - ? "-" - : NumberFormatUtil.getInstance().getNumberFormat().format(model.getMarkovCheck().getMarkovAdequacyScore(0.01))))); - conditioningLabelIndep.setText("Tests graphical predictions of Indep(X, Y | " + conditioningSetTypeJComboBox.getSelectedItem() + ")"); conditioningLabelDep.setText("Tests graphical predictions of Dep(X, Y | " + conditioningSetTypeJComboBox.getSelectedItem() + ")"); } - private int getLastSortCol() { return this.lastSortCol; } @@ -846,47 +931,22 @@ private Box createHistogramPanel(boolean indep) { return Box.createVerticalBox(); } - - DataSet dataSet = new BoxDataSet(new VerticalDoubleDataBox(results.size(), 1), - Collections.singletonList(new ContinuousVariable("P-Value or Bump"))); - - for (int i = 0; i < results.size(); i++) { - dataSet.setDouble(i, 0, results.get(i).getPValue()); - } - - Histogram histogram = new Histogram(dataSet, "P-Value or Bump", false); -// histogram.setTarget("P-Value or Bump"); - HistogramPanel view = new HistogramPanel(histogram, true); - - Color fillColor = new Color(113, 165, 210); - view.setBarColor(fillColor); - - view.setPreferredSize(new Dimension(350, 200)); - - Box box = Box.createHorizontalBox(); - box.add(Box.createHorizontalGlue()); + HistogramPanel view = getHistogramPanel(results); + Box box = Box.createVerticalBox(); box.add(view); - box.add(Box.createHorizontalGlue()); - - Box vBox = Box.createVerticalBox(); - vBox.add(Box.createVerticalGlue()); - vBox.add(box); - vBox.add(Box.createVerticalGlue()); - - return vBox; + return box; } private DataType getDataType() { DataModel dataSet = model.getDataModel(); if (dataSet.isContinuous() && !(dataSet instanceof ICovarianceMatrix)) { - // covariance dataset is continuous at the same time - Zhou return DataType.Continuous; } else if (dataSet.isDiscrete()) { return DataType.Discrete; } else if (dataSet.isMixed()) { return DataType.Mixed; - } else if (dataSet instanceof ICovarianceMatrix) { // Better to add an isCovariance() - Zhou + } else if (dataSet instanceof ICovarianceMatrix) { return DataType.Covariance; } else { return null; @@ -936,11 +996,11 @@ private JPanel createParamsPanel(Set params, Parameters parameters) { } private Map createParameterComponents(Set params, Parameters parameters) { - ParamDescriptions paramDescs = ParamDescriptions.getInstance(); + ParamDescriptions paramDescriptions = ParamDescriptions.getInstance(); return params.stream() .collect(Collectors.toMap( Function.identity(), - e -> createParameterComponent(e, parameters, paramDescs.get(e)), + e -> createParameterComponent(e, parameters, paramDescriptions.get(e)), (u, v) -> { throw new IllegalStateException(String.format("Duplicate key %s.", u)); }, @@ -985,7 +1045,7 @@ private Box createParameterComponent(String parameter, Parameters parameters, Pa } private DoubleTextField getDoubleField(String parameter, Parameters parameters, - double defaultValue, double lowerBound, double upperBound) { + double defaultValue, double lowerBound, double upperBound) { DoubleTextField field = new DoubleTextField(parameters.getDouble(parameter, defaultValue), 8, new DecimalFormat("0.####"), new DecimalFormat("0.0#E0"), 0.001); @@ -1015,7 +1075,7 @@ private DoubleTextField getDoubleField(String parameter, Parameters parameters, } private IntTextField getIntTextField(String parameter, Parameters parameters, - int defaultValue, double lowerBound, double upperBound) { + int defaultValue, double lowerBound, double upperBound) { IntTextField field = new IntTextField(parameters.getInt(parameter, defaultValue), 8); field.setFilter((value, oldValue) -> { @@ -1044,7 +1104,7 @@ private IntTextField getIntTextField(String parameter, Parameters parameters, } private LongTextField getLongTextField(String parameter, Parameters parameters, - long defaultValue, long lowerBound, long upperBound) { + long defaultValue, long lowerBound, long upperBound) { LongTextField field = new LongTextField(parameters.getLong(parameter, defaultValue), 8); field.setFilter((value, oldValue) -> { @@ -1137,6 +1197,7 @@ private StringTextField getStringField(String parameter, Parameters parameters, } static class Renderer extends DefaultTableCellRenderer { + private JTable table; private boolean selected; @@ -1164,8 +1225,3 @@ public Component getTableCellRendererComponent(JTable table, Object value, boole } } - - - - - diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/SelectBidirectedAction.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/SelectBidirectedAction.java index 6c8d558347..9c39e8fd80 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/SelectBidirectedAction.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/SelectBidirectedAction.java @@ -34,7 +34,7 @@ import java.awt.event.ActionEvent; /** - * Copies a selection of session nodes in the frontmost session editor, to the clipboard. + * Highlights all bidirected edges in the given display graph. * * @author josephramsey */ @@ -46,7 +46,9 @@ public class SelectBidirectedAction extends AbstractAction implements ClipboardO private final GraphWorkbench workbench; /** - * Creates a new copy subsession action for the given desktop and clipboard. + * Highlights all bidirected edges in the given display graph. + * + * @param workbench the given workbench. */ public SelectBidirectedAction(GraphWorkbench workbench) { super("Highlight Bidirected Edges"); @@ -59,7 +61,9 @@ public SelectBidirectedAction(GraphWorkbench workbench) { } /** - * Copies a parentally closed selection of session nodes in the frontmost session editor to the clipboard. + * Highlights all bidirected edges in the given display graph. + * + * @param e the event to be processed */ public void actionPerformed(ActionEvent e) { this.workbench.deselectAll(); diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/SelectDirectedAction.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/SelectDirectedAction.java index f7b7cf8a98..4d87a737c3 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/SelectDirectedAction.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/SelectDirectedAction.java @@ -34,7 +34,7 @@ import java.awt.event.ActionEvent; /** - * Copies a selection of session nodes in the frontmost session editor, to the clipboard. + * Selects all directed edges in the given display graph. * * @author josephramsey */ @@ -47,6 +47,8 @@ public class SelectDirectedAction extends AbstractAction implements ClipboardOwn /** * Creates a new copy subsession action for the given desktop and clipboard. + * + * @param workbench the given workbench. */ public SelectDirectedAction(GraphWorkbench workbench) { super("Highlight Directed Edges"); @@ -59,7 +61,9 @@ public SelectDirectedAction(GraphWorkbench workbench) { } /** - * Copies a parentally closed selection of session nodes in the frontmost session editor to the clipboard. + * Selects all directed edges in the given display graph. + * + * @param e the event to be processed */ public void actionPerformed(ActionEvent e) { this.workbench.deselectAll(); diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/SelectLatentsAction.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/SelectLatentsAction.java index 0efae92daa..f61e37e4b9 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/SelectLatentsAction.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/SelectLatentsAction.java @@ -36,7 +36,7 @@ import java.awt.event.ActionEvent; /** - * Copies a selection of session nodes in the frontmost session editor, to the clipboard. + * Highlights all latent variables in the given display graph. * * @author josephramsey */ @@ -48,7 +48,9 @@ public class SelectLatentsAction extends AbstractAction implements ClipboardOwne private final GraphWorkbench workbench; /** - * Creates a new copy subsession action for the given desktop and clipboard. + * Highlights all latent variables in the given display graph. + * + * @param workbench the given workbench. */ public SelectLatentsAction(GraphWorkbench workbench) { super("Highlight Latent Nodes"); @@ -61,7 +63,9 @@ public SelectLatentsAction(GraphWorkbench workbench) { } /** - * Copies a parentally closed selection of session nodes in the frontmost session editor to the clipboard. + * Highlights all latent variables in the given display graph. + * + * @param e the event to be processed */ public void actionPerformed(ActionEvent e) { this.workbench.deselectAll(); diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/SelectTrianglesAction.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/SelectTrianglesAction.java new file mode 100644 index 0000000000..a2c2ee2a15 --- /dev/null +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/SelectTrianglesAction.java @@ -0,0 +1,93 @@ +/////////////////////////////////////////////////////////////////////////////// +// 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.editor; + +import edu.cmu.tetrad.graph.Edge; +import edu.cmu.tetrad.graph.Graph; +import edu.cmu.tetrad.graph.Node; +import edu.cmu.tetradapp.workbench.GraphWorkbench; + +import javax.swing.*; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.ClipboardOwner; +import java.awt.datatransfer.Transferable; +import java.awt.event.ActionEvent; + +/** + * Highlights all edges in triangle in the given display graph. + * + * @author josephramsey + */ +public class SelectTrianglesAction extends AbstractAction implements ClipboardOwner { + + /** + * The desktop containing the target session editor. + */ + private final GraphWorkbench workbench; + + /** + * Highlights all edges in triangle in the given display graph. + * + * @param workbench the given workbench. + */ + public SelectTrianglesAction(GraphWorkbench workbench) { + super("Highlight Triangles"); + + if (workbench == null) { + throw new NullPointerException("Desktop must not be null."); + } + + this.workbench = workbench; + } + + /** + * Selects all edges in triangle in the given display graph. + * + * @param e the event to be processed + */ + public void actionPerformed(ActionEvent e) { + this.workbench.deselectAll(); + + final Graph graph = this.workbench.getGraph(); + + for (Edge edge : graph.getEdges()) { + for (Node node : graph.getAdjacentNodes(edge.getNode1())) { + if (node == edge.getNode1() || node == edge.getNode2()) { + continue; + } + + if (graph.isAdjacentTo(node, edge.getNode1()) && graph.isAdjacentTo(node, edge.getNode2())) { + this.workbench.selectEdge(edge); + } + } + } + } + + /** + * Required by the AbstractAction interface; does nothing. + */ + public void lostOwnership(Clipboard clipboard, Transferable contents) { + } +} + + + diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/SelectUndirectedAction.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/SelectUndirectedAction.java index a93e547060..3eb259c20d 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/SelectUndirectedAction.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/SelectUndirectedAction.java @@ -34,7 +34,7 @@ import java.awt.event.ActionEvent; /** - * Copies a selection of session nodes in the frontmost session editor, to the clipboard. + * Highlights all undirected edges in the given display graph. * * @author josephramsey */ @@ -46,7 +46,9 @@ public class SelectUndirectedAction extends AbstractAction implements ClipboardO private final GraphWorkbench workbench; /** - * Creates a new copy subsession action for the given desktop and clipboard. + * Highlights all undirected edges in the given display graph. + * + * @param workbench the given workbench. */ public SelectUndirectedAction(GraphWorkbench workbench) { super("Highlight Undirected Edges"); @@ -59,7 +61,9 @@ public SelectUndirectedAction(GraphWorkbench workbench) { } /** - * Copies a parentally closed selection of session nodes in the frontmost session editor to the clipboard. + * Selects all undirected edges in the given display graph. + * + * @param e the event to be processed */ public void actionPerformed(ActionEvent e) { this.workbench.deselectAll(); diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/SemGraphEditor.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/SemGraphEditor.java index 0c627b5cb9..214c4897a5 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/SemGraphEditor.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/SemGraphEditor.java @@ -266,7 +266,7 @@ private void initUI(SemGraphWrapper semGraphWrapper) { @Override public void actionPerformed(ActionEvent e) { // Initialize helpSet - final String helpHS = "/resources/javahelp/TetradHelp.hs"; + final String helpHS = "/docs/javahelp/TetradHelp.hs"; try { URL url = this.getClass().getResource(helpHS); @@ -504,7 +504,9 @@ public void internalFrameClosed(InternalFrameEvent e1) { graph.add(new JMenuItem(new SelectDirectedAction(this.workbench))); graph.add(new JMenuItem(new SelectBidirectedAction(this.workbench))); - graph.add(new JMenuItem(new SelectUndirectedAction(this.workbench))); + graph.add(new JMenuItem(new SelectUndirectedAction(getWorkbench()))); + graph.add(new JMenuItem(new SelectTrianglesAction(getWorkbench()))); + graph.add(new JMenuItem(new SelectUndirectedAction(getWorkbench()))); graph.add(new JMenuItem(new SelectLatentsAction(this.workbench))); graph.add(new PagColorer(getWorkbench())); diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/SplitCasesParamsEditor.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/SplitCasesParamsEditor.java index c2dc5538c3..4500d53593 100755 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/SplitCasesParamsEditor.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/SplitCasesParamsEditor.java @@ -133,7 +133,7 @@ public void setup() { splitEditorPanel = new JPanel(); splitEditorPanel.setLayout(new BorderLayout()); - this.setNumSplits(params.getInt("numSplits", 3)); + this.setNumSplits(params.getInt("numSplits", 2)); JRadioButton shuffleButton = new JRadioButton("Shuffled order"); JRadioButton noShuffleButton = new JRadioButton("Original order"); diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/TimeLagGraphEditor.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/TimeLagGraphEditor.java index df624a2e68..07f7a5f7b1 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/TimeLagGraphEditor.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/TimeLagGraphEditor.java @@ -241,7 +241,7 @@ private void initUI(TimeLagGraphWrapper timeLagGraphWrapper) { @Override public void actionPerformed(ActionEvent e) { // Initialize helpSet - final String helpHS = "/resources/javahelp/TetradHelp.hs"; + final String helpHS = "/docs/javahelp/TetradHelp.hs"; try { URL url = this.getClass().getResource(helpHS); diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/search/AlgorithmCard.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/search/AlgorithmCard.java index ae9fafc127..dcca62b761 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/search/AlgorithmCard.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/search/AlgorithmCard.java @@ -376,9 +376,9 @@ public void saveStates() { * @return Algorithm */ public Algorithm getAlgorithmFromInterface(AlgorithmModel algoModel, IndependenceTestModel indTestModel, ScoreModel scoreModel) { - Class algoClass = algoModel.getAlgorithm().getClazz(); - Class indTestClass = (indTestModel == null) ? null : indTestModel.getIndependenceTest().getClazz(); - Class scoreClass = (scoreModel == null) ? null : scoreModel.getScore().getClazz(); + Class algoClass = algoModel.getAlgorithm().clazz(); + Class indTestClass = (indTestModel == null) ? null : indTestModel.getIndependenceTest().clazz(); + Class scoreClass = (scoreModel == null) ? null : scoreModel.getScore().clazz(); Algorithm algorithm = null; @@ -406,19 +406,19 @@ public boolean isAllValid() { boolean missingScore = algoModel.isRequiredScore() && (scoreModel == null); if (missingTest && missingScore) { String msg = String.format("%s requires both test and score.", - algoModel.getAlgorithm().getAnnotation().name()); + algoModel.getAlgorithm().annotation().name()); JOptionPane.showMessageDialog(this.desktop, msg, "Please Note", JOptionPane.INFORMATION_MESSAGE); return false; } else if (missingTest) { String msg = String.format("%s requires independence test.", - algoModel.getAlgorithm().getAnnotation().name()); + algoModel.getAlgorithm().annotation().name()); JOptionPane.showMessageDialog(this.desktop, msg, "Please Note", JOptionPane.INFORMATION_MESSAGE); return false; } else if (missingScore) { String msg = String.format("%s requires score.", - algoModel.getAlgorithm().getAnnotation().name()); + algoModel.getAlgorithm().annotation().name()); JOptionPane.showMessageDialog(this.desktop, msg, "Please Note", JOptionPane.INFORMATION_MESSAGE); return false; @@ -433,7 +433,7 @@ private void validateAlgorithmOption() { firePropertyChange("algoFwdBtn", null, true); AlgorithmModel algoModel = this.algorithmList.getSelectedValue(); - Class algoClass = algoModel.getAlgorithm().getClazz(); + Class algoClass = algoModel.getAlgorithm().clazz(); if (algoClass.isAnnotationPresent(Nonexecutable.class)) { String msg; @@ -476,7 +476,7 @@ private void validateAlgorithmOption() { } // SVAR (SvarFci, SvarGfci) algorithms need lagged data - String cmd = algoModel.getAlgorithm().getAnnotation().command(); + String cmd = algoModel.getAlgorithm().annotation().command(); if (cmd.equalsIgnoreCase("ts-fci") || cmd.equalsIgnoreCase("ts-gfci") || cmd.equalsIgnoreCase("ts-imgs")) { @@ -502,7 +502,7 @@ private void refreshAlgorithmList() { if ("all".equals(algoType)) { if (this.knowledgeChkBox.isSelected()) { algorithmModels.getModels(this.dataType, this.multiDataAlgo).stream() - .filter(e -> HasKnowledge.class.isAssignableFrom(e.getAlgorithm().getClazz())) + .filter(e -> HasKnowledge.class.isAssignableFrom(e.getAlgorithm().clazz())) .forEach(e -> this.algoModels.addElement(e)); } else { algorithmModels.getModels(this.dataType, this.multiDataAlgo).stream() @@ -511,7 +511,7 @@ private void refreshAlgorithmList() { } else { if (this.knowledgeChkBox.isSelected()) { algorithmModels.getModels(AlgType.valueOf(algoType), this.dataType, this.multiDataAlgo).stream() - .filter(e -> HasKnowledge.class.isAssignableFrom(e.getAlgorithm().getClazz())) + .filter(e -> HasKnowledge.class.isAssignableFrom(e.getAlgorithm().clazz())) .forEach(e -> this.algoModels.addElement(e)); } else { algorithmModels.getModels(AlgType.valueOf(algoType), this.dataType, this.multiDataAlgo).stream() @@ -539,15 +539,15 @@ private void refreshTestList() { List models = IndependenceTestModels.getInstance().getModels(this.dataType); if (this.linearGaussianRadBtn.isSelected()) { models.stream() - .filter(e -> e.getIndependenceTest().getClazz().isAnnotationPresent(LinearGaussian.class)) + .filter(e -> e.getIndependenceTest().clazz().isAnnotationPresent(LinearGaussian.class)) .forEach(e -> this.indTestComboBox.addItem(e)); } else if (this.mixedRadBtn.isSelected()) { models.stream() - .filter(e -> e.getIndependenceTest().getClazz().isAnnotationPresent(Mixed.class)) + .filter(e -> e.getIndependenceTest().clazz().isAnnotationPresent(Mixed.class)) .forEach(e -> this.indTestComboBox.addItem(e)); } else if (this.generalRadBtn.isSelected()) { models.stream() - .filter(e -> e.getIndependenceTest().getClazz().isAnnotationPresent(General.class)) + .filter(e -> e.getIndependenceTest().clazz().isAnnotationPresent(General.class)) .forEach(e -> this.indTestComboBox.addItem(e)); } else if (this.allRadBtn.isSelected()) { models.stream() @@ -590,15 +590,15 @@ private void refreshScoreList() { List models = ScoreModels.getInstance().getModels(this.dataType); if (this.linearGaussianRadBtn.isSelected()) { models.stream() - .filter(e -> e.getScore().getClazz().isAnnotationPresent(LinearGaussian.class)) + .filter(e -> e.getScore().clazz().isAnnotationPresent(LinearGaussian.class)) .forEach(e -> this.scoreComboBox.addItem(e)); } else if (this.mixedRadBtn.isSelected()) { models.stream() - .filter(e -> e.getScore().getClazz().isAnnotationPresent(Mixed.class)) + .filter(e -> e.getScore().clazz().isAnnotationPresent(Mixed.class)) .forEach(e -> this.scoreComboBox.addItem(e)); } else if (this.generalRadBtn.isSelected()) { models.stream() - .filter(e -> e.getScore().getClazz().isAnnotationPresent(General.class)) + .filter(e -> e.getScore().clazz().isAnnotationPresent(General.class)) .forEach(e -> this.scoreComboBox.addItem(e)); } else if (this.allRadBtn.isSelected()) { models.stream() diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/search/GraphCard.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/search/GraphCard.java index 69972c031d..60cf715d5a 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/search/GraphCard.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/search/GraphCard.java @@ -108,6 +108,7 @@ JMenuBar menuBar() { graph.add(new JMenuItem(new SelectDirectedAction(this.workbench))); graph.add(new JMenuItem(new SelectBidirectedAction(this.workbench))); graph.add(new JMenuItem(new SelectUndirectedAction(this.workbench))); + graph.add(new JMenuItem(new SelectTrianglesAction(this.workbench))); graph.add(new JMenuItem(new SelectLatentsAction(this.workbench))); graph.add(new PagColorer(this.workbench)); @@ -152,7 +153,7 @@ private Box createInstructionBox() { @Override public void actionPerformed(ActionEvent e) { // Initialize helpSet - final String helpHS = "/resources/javahelp/TetradHelp.hs"; + final String helpHS = "/docs/javahelp/TetradHelp.hs"; try { URL url = this.getClass().getResource(helpHS); diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/simulation/ParameterTab.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/simulation/ParameterTab.java index 94b2e49194..a64f4b31b1 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/simulation/ParameterTab.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/editor/simulation/ParameterTab.java @@ -55,8 +55,8 @@ public class ParameterTab extends JPanel { private static final String[] SOURCE_GRAPH_ITEMS = { SimulationTypes.BAYS_NET, SimulationTypes.STRUCTURAL_EQUATION_MODEL, - SimulationTypes.NON_LINEAR_STRUCTURAL_EQUATION_MODEL, SimulationTypes.LINEAR_FISHER_MODEL, + SimulationTypes.NON_LINEAR_STRUCTURAL_EQUATION_MODEL, SimulationTypes.LEE_AND_HASTIE, SimulationTypes.CONDITIONAL_GAUSSIAN, SimulationTypes.TIME_SERIES diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/AbstractAlgorithmRunner.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/AbstractAlgorithmRunner.java index 397c075340..81e5df7ec3 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/AbstractAlgorithmRunner.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/AbstractAlgorithmRunner.java @@ -33,6 +33,7 @@ import java.io.IOException; import java.io.ObjectInputStream; +import java.io.Serial; import java.util.*; /** @@ -43,45 +44,16 @@ */ public abstract class AbstractAlgorithmRunner implements AlgorithmRunner, ParamsResettable, Unmarshallable { + @Serial private static final long serialVersionUID = 23L; final Map paramSettings = new LinkedHashMap<>(); private DataWrapper dataWrapper; - /** - * @serial Can be null. - */ private String name; - /** - * The parameters guiding this search (when executed). - * - * @serial Cannot be null. - */ private Parameters params; - /** - * Keeps a reference to the dataModel source that has been provided (hopefully either a dataModel model or a - * graph). - * - * @serial Can be null. - */ private transient DataModel dataModel; - /** - * Keeps a reference to the source graph, if there is one. - * - * @serial Can be null. - */ private Graph sourceGraph; - /** - * Keeps a reference to the result graph for the algorithm. - * - * @serial Can be null. - */ private Graph resultGraph = new EdgeListGraph(); - /** - * The initial graph for the algorithm, if feasible. - */ private Graph externalGraph; - /** - * A series of graphs that the search algorithm might search over, if it's that kind of algorithm. - */ private List graphs; private Map allParamSettings; @@ -90,6 +62,10 @@ public abstract class AbstractAlgorithmRunner /** * Constructs a wrapper for the given DataWrapper. The DatWrapper must contain a DataSet that is either a DataSet or * a DataSet or a DataList containing either a DataSet or a DataSet as its selected model. + * + * @param dataWrapper the data wrapper + * @param params the parameters + * @param knowledgeBoxModel the knowledge box model */ public AbstractAlgorithmRunner(DataWrapper dataWrapper, Parameters params, KnowledgeBoxModel knowledgeBoxModel) { @@ -120,6 +96,11 @@ public AbstractAlgorithmRunner(DataWrapper dataWrapper, /** * Constructs a wrapper for the given DataWrapper. The DatWrapper must contain a DataSet that is either a DataSet or * a DataSet or a DataList containing either a DataSet or a DataSet as its selected model. + * + * @param dataWrapper the data wrapper + * @param params the parameters + * @param knowledgeBoxModel the knowledge box model + * @param facts the independence facts model */ public AbstractAlgorithmRunner(DataWrapper dataWrapper, Parameters params, KnowledgeBoxModel knowledgeBoxModel, IndependenceFactsModel facts) { @@ -149,6 +130,13 @@ public AbstractAlgorithmRunner(DataWrapper dataWrapper, transferVarNamesToParams(names); } + /** + * Constructs a wrapper for the given DataWrapper. The DatWrapper must contain a DataSet that is either a DataSet or + * a DataSet or a DataList containing either a DataSet or a DataSet as its selected model. + * + * @param dataWrapper the data wrapper + * @param params the parameters + */ public AbstractAlgorithmRunner(DataWrapper dataWrapper, Parameters params) { if (dataWrapper == null) { throw new NullPointerException(); @@ -170,6 +158,9 @@ public AbstractAlgorithmRunner(DataWrapper dataWrapper, Parameters params) { /** * Constructs a wrapper for the given graph. + * + * @param sourceGraph the source graph + * @param params the parameters */ public AbstractAlgorithmRunner(Graph sourceGraph, Parameters params) { if (sourceGraph == null) { @@ -185,6 +176,13 @@ public AbstractAlgorithmRunner(Graph sourceGraph, Parameters params) { this.sourceGraph = sourceGraph; } + /** + * Constructs a wrapper for the given graph. + * + * @param graph the graph + * @param params the parameters + * @param knowledgeBoxModel the knowledge box model + */ public AbstractAlgorithmRunner(Graph graph, Parameters params, KnowledgeBoxModel knowledgeBoxModel) { this(graph, params); @@ -193,11 +191,24 @@ public AbstractAlgorithmRunner(Graph graph, Parameters params, } } + /** + * Constructs a wrapper for the given graph. + * + * @param params the parameters + * @param graphs the graphs + */ public AbstractAlgorithmRunner(Parameters params, Graph... graphs) { this.graphs = Arrays.asList(graphs); this.params = params; } + /** + * Constructs a wrapper for the given graph. + * + * @param params the parameters + * @param knowledgeBoxModel the knowledge box model + * @param graphs the graphs + */ public AbstractAlgorithmRunner(Parameters params, KnowledgeBoxModel knowledgeBoxModel, Graph... graphs) { this.graphs = Arrays.asList(graphs); this.params = params; @@ -206,6 +217,13 @@ public AbstractAlgorithmRunner(Parameters params, KnowledgeBoxModel knowledgeBox } } + /** + * Constructs a wrapper for the given graph. + * + * @param model the model + * @param params the parameters + * @param knowledgeBoxModel the knowledge box model + */ public AbstractAlgorithmRunner(IndependenceFactsModel model, Parameters params, KnowledgeBoxModel knowledgeBoxModel) { if (model == null) { @@ -228,6 +246,14 @@ public AbstractAlgorithmRunner(IndependenceFactsModel model, this.dataModel = dataSource; } + /** + * Constructs a wrapper for the given graph. + * + * @param graph the graph + * @param params the parameters + * @param knowledgeBoxModel the knowledge box model + * @param facts the independence facts model + */ public AbstractAlgorithmRunner(Graph graph, Parameters params, KnowledgeBoxModel knowledgeBoxModel, IndependenceFacts facts) { this(graph, params); @@ -242,40 +268,78 @@ public AbstractAlgorithmRunner(Graph graph, Parameters params, //============================PUBLIC METHODS==========================// + /** + * Returns the graph that was the result of the algorithm's execution. + */ public final Graph getResultGraph() { return this.resultGraph; } + /** + * Sets the graph that was the result of the algorithm's execution. + */ public final void setResultGraph(Graph resultGraph) { this.resultGraph = resultGraph; } /** * By default, algorithm do not support knowledge. Those that do will speak up. + * + * @return true if the algorithm supports knowledge. */ public boolean supportsKnowledge() { return false; } + /** + * By default, algorithm do not support Meek rules. Those that do will speak up. + * + * @return null + */ public MeekRules getMeekRules() { return null; } + /** + * By default, algorithm do not support independence facts. Those that do will speak up. + * + * @return the external graph + */ public Graph getExternalGraph() { return this.externalGraph; } + /** + * Sets the external graph for the algorithm. + * + * @param graph the graph + */ public void setExternalGraph(Graph graph) { this.externalGraph = graph; } + /** + * Returns the algorithm's name. + * + * @return + */ @Override public abstract String getAlgorithmName(); + /** + * Returns the source graph. + * + * @return the source graph + */ public final Graph getSourceGraph() { return this.sourceGraph; } + /** + * Returns the data model. + * + * @return the data model + */ public final DataModel getDataModel() { if (this.dataWrapper != null) { DataModelList dataModelList = this.dataWrapper.getDataModelList(); @@ -294,19 +358,39 @@ public final DataModel getDataModel() { } } + /** + * Returns the data model list. + * + * @return the data model list + */ final DataModelList getDataModelList() { if (this.dataWrapper == null) return null; return this.dataWrapper.getDataModelList(); } + /** + * Returns the search parameters. + * + * @return the search parameters + */ public final Parameters getParams() { return this.params; } + /** + * Returns the pameters. + * + * @return the parameters + */ public Object getResettableParams() { return this.getParams(); } + /** + * Resets the parameters. + * + * @param params the parameters + */ public void resetParams(Object params) { this.params = (Parameters) params; } @@ -325,9 +409,7 @@ private DataModel getSelectedDataModel(DataWrapper dataWrapper) { DataModel dataModel = dataWrapper.getSelectedDataModel(); - if (dataModel instanceof DataSet) { - DataSet dataSet = (DataSet) dataModel; - + if (dataModel instanceof DataSet dataSet) { if (dataSet.isDiscrete()) { return dataSet; } else if (dataSet.isContinuous()) { @@ -378,29 +460,59 @@ private void readObject(ObjectInputStream s) } + /** + * Returns the name of the algorithm. + * + * @return the name + */ public String getName() { return this.name; } + /** + * Sets the name of the algorithm. + * + * @param name the name + */ public void setName(String name) { this.name = name; } + /** + * Returns the list of graphs. + * + * @return the graphs + */ public List getGraphs() { return this.graphs; } + /** + * Returns the param settings. + * + * @return the param settings + */ @Override public Map getParamSettings() { this.paramSettings.put("Algorithm", getAlgorithmName()); return this.paramSettings; } + /** + * Returns all param settings. + * + * @return all param settings + */ public Map getAllParamSettings() { return this.allParamSettings; } + /** + * Sets all param settings. + * + * @param allParamSettings the all param settings map. + */ public void setAllParamSettings(Map allParamSettings) { this.allParamSettings = allParamSettings; } diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/AbstractMBSearchRunner.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/AbstractMBSearchRunner.java index b8ebf4dd11..f5d211aca9 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/AbstractMBSearchRunner.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/AbstractMBSearchRunner.java @@ -31,7 +31,6 @@ import edu.cmu.tetrad.search.test.IndTestFisherZ; import edu.cmu.tetrad.search.test.IndTestGSquare; import edu.cmu.tetrad.search.test.IndTestRegression; -import edu.cmu.tetrad.search.work_in_progress.IndTestFisherZGeneralizedInverse; import edu.cmu.tetrad.util.Parameters; import edu.cmu.tetradapp.util.IndTestType; @@ -184,9 +183,11 @@ IndependenceTest getIndependenceTest() { if (IndTestType.FISHER_Z == type) { return new IndTestFisherZ(this.source, this.params.getDouble("alpha", 0.001)); } - if (IndTestType.FISHER_ZD == type) { - return new IndTestFisherZGeneralizedInverse(this.source, this.params.getDouble("alpha", 0.001)); - } +// if (IndTestType.FISHER_ZD == type) { +// IndTestFisherZ test = new IndTestFisherZ(this.source, this.params.getDouble("alpha", 0.001)); +//// test.setUsePseudoinverse(true); +// return test; +// } if (IndTestType.LINEAR_REGRESSION == type) { return new IndTestRegression(this.source, this.params.getDouble("alpha", 0.001)); } else { diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/AlgorithmRunner.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/AlgorithmRunner.java index 1eacbd66b0..f7bd1152ea 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/AlgorithmRunner.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/AlgorithmRunner.java @@ -82,6 +82,9 @@ public interface AlgorithmRunner extends SessionModel, Executable, GraphSource, */ void setExternalGraph(Graph graph); + /** + * @return the name of the algorithm. + */ String getAlgorithmName(); } diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/CPDAGFitModel.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/CPDAGFitModel.java index d8118a2dd3..1bc171316e 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/CPDAGFitModel.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/CPDAGFitModel.java @@ -84,7 +84,7 @@ public CPDAGFitModel(Simulation simulation, GeneralAlgorithmRunner algorithmRunn for (int i = 0; i < dataModels.size(); i++) { DataSet dataSet = (DataSet) dataModels.get(0); - Graph dag = GraphTransforms.dagFromCPDAG(graphs.get(0), null); + Graph dag = GraphTransforms.dagFromCpdag(graphs.get(0), null); BayesPm pm = new BayesPmWrapper(dag, new DataWrapper(dataSet)).getBayesPm(); this.bayesPms.add(pm); this.bayesIms.add(estimate(dataSet, pm)); @@ -95,7 +95,7 @@ public CPDAGFitModel(Simulation simulation, GeneralAlgorithmRunner algorithmRunn for (int i = 0; i < dataModels.size(); i++) { DataSet dataSet = (DataSet) dataModels.get(0); - Graph dag = GraphTransforms.dagFromCPDAG(graphs.get(0), null); + Graph dag = GraphTransforms.dagFromCpdag(graphs.get(0), null); try { SemPm pm = new SemPm(dag); diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/CheckKnowledgeModel.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/CheckKnowledgeModel.java new file mode 100644 index 0000000000..2549b1d9f4 --- /dev/null +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/CheckKnowledgeModel.java @@ -0,0 +1,135 @@ +/////////////////////////////////////////////////////////////////////////////// +// 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.model; + +import edu.cmu.tetrad.data.Knowledge; +import edu.cmu.tetrad.graph.Edge; +import edu.cmu.tetrad.graph.Graph; +import edu.cmu.tetrad.search.CheckKnowledge; +import edu.cmu.tetrad.session.SessionModel; +import edu.cmu.tetrad.util.Parameters; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.util.List; + + +/** + * Compares a target workbench with a reference workbench by counting errors of omission and commission. (for edge + * presence only, not orientation). + * + * @author josephramsey + * @author Erin Korber (added remove latents functionality July 2004) + */ +public final class CheckKnowledgeModel implements SessionModel { + private static final long serialVersionUID = 23L; + private final Graph graph; + private final Knowledge knowledge; + private final Parameters params; + private final String modelName; + private String name = "Check Knowledge"; + + /** + * Compares the results of a PC to a reference workbench by counting errors of omission and commission. The counts + * can be retrieved using the methods + * countOmissionErrors and countCommissionErrors. + */ + public CheckKnowledgeModel(GraphSource model, KnowledgeBoxModel knowledgeBoxModel, Parameters params) { + if (params == null) { + throw new NullPointerException("Parameters must not be null"); + } + + if (model == null) { + throw new NullPointerException("Null graph source>"); + } + + if (knowledgeBoxModel == null) { + throw new NullPointerException("Null knowledge box model"); + } + + this.graph = model.getGraph(); + this.knowledge = knowledgeBoxModel.getKnowledge(); + this.params = params; + this.modelName = model.getName(); + } + + + public String getComparisonString() { + List forbiddenViolations = CheckKnowledge.forbiddenViolations(graph, knowledge); + List requiredViolations = CheckKnowledge.requiredViolations(graph, knowledge); + + StringBuilder sb = new StringBuilder(); + sb.append("Violations of knowledge for ").append(modelName).append(": "); + + sb.append("\n\nForbidden Violations:\n"); + + for (Edge edge : forbiddenViolations) { + sb.append("\n"); + sb.append(edge.toString()); + sb.append(", "); + } + + sb.append("\n\nRequired Violations:\n"); + + for (Edge edge : requiredViolations) { + sb.append("\n"); + sb.append(edge.toString()); + sb.append(", "); + } + + sb.append("\n\nKnowledge:\n\n"); + sb.append(knowledge); + + sb.append("\n\nGraph:\n\n"); + sb.append(graph); + + return sb.toString(); + } + + /** + * Adds semantic checks to the default deserialization method. This method must have the standard signature for a + * readObject method, and the body of the method must begin with "s.defaultReadObject();". Other than that, any + * semantic checks can be specified and do not need to stay the same from version to version. A readObject method of + * this form may be added to any class, even if Tetrad sessions were previously saved out using a version of the + * class that didn't include it. (That's what the "s.defaultReadObject();" is for. See J. Bloch, Effective Java, for + * help.) + */ + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException { + s.defaultReadObject(); + } + + public Parameters getParams() { + return this.params; + } + + @Override + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} + + diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/DagFromCPDAGWrapper.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/DagFromCPDAGWrapper.java index a948a06a0e..f2518dc5da 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/DagFromCPDAGWrapper.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/DagFromCPDAGWrapper.java @@ -47,7 +47,7 @@ public DagFromCPDAGWrapper(Graph graph) { } private static Graph getGraph(Graph graph) { - return GraphTransforms.dagFromCPDAG(graph, null); + return GraphTransforms.dagFromCpdag(graph, null); } diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/DagWrapper.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/DagWrapper.java index a2e649a833..18e024479e 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/DagWrapper.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/DagWrapper.java @@ -31,19 +31,21 @@ import java.io.IOException; import java.io.ObjectInputStream; +import java.io.Serial; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** - * Holds a tetrad dag with all of the constructors necessary for it to serve as a model for the tetrad application. + * Holds a tetrad dag with all the constructors necessary for it to serve as a model for the tetrad application. * * @author josephramsey */ public class DagWrapper implements GraphSource, KnowledgeBoxInput, IndTestProducer, SimulationParamsSource, MultipleGraphSource { + @Serial private static final long serialVersionUID = 23L; private int numModels = 1; private int modelIndex; @@ -60,7 +62,6 @@ public class DagWrapper implements GraphSource, KnowledgeBoxInput, IndTestProduc private List dags; private Map allParamSettings; private Parameters parameters; - private Dag graph; //=============================CONSTRUCTORS==========================// public DagWrapper(Dag graph) { @@ -85,8 +86,9 @@ public DagWrapper(Parameters params) { } public DagWrapper(GraphSource graphSource, Parameters parameters) { - if (graphSource instanceof Simulation) { - Simulation simulation = (Simulation) graphSource; + this.parameters = new Parameters(parameters); + + if (graphSource instanceof Simulation simulation) { List graphs = simulation.getGraphs(); this.dags = new ArrayList<>(); @@ -110,9 +112,7 @@ public DagWrapper(AbstractAlgorithmRunner wrapper) { } public DagWrapper(DataWrapper wrapper) { - if (wrapper instanceof Simulation) { - Simulation simulation = (Simulation) wrapper; - + if (wrapper instanceof Simulation simulation) { List graphs = simulation.getGraphs(); this.dags = new ArrayList<>(); @@ -196,10 +196,10 @@ private void log() { * semantic checks can be specified and do not need to stay the same from version to version. A readObject method of * this form may be added to any class, even if Tetrad sessions were previously saved out using a version of the * class that didn't include it. (That's what the "s.defaultReadObject();" is for. See J. Bloch, Effective Java, for - * help. + * help.) */ - private void readObject(ObjectInputStream s) - throws IOException, ClassNotFoundException { + @Serial + private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); } diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/DataWrapper.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/DataWrapper.java index 892fbef860..2927006b2f 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/DataWrapper.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/DataWrapper.java @@ -32,6 +32,7 @@ import java.io.IOException; import java.io.ObjectInputStream; +import java.io.Serial; import java.util.*; /** @@ -105,9 +106,13 @@ public DataWrapper(Simulation wrapper, Parameters parameters) { /** * Copy constructor. + * + * @param wrapper the data wrapper to copy. + * @param parameters the parameters to use. */ public DataWrapper(DataWrapper wrapper, Parameters parameters) { this.name = wrapper.name; + this.parameters = new Parameters(parameters); DataModelList dataModelList = new DataModelList(); int selected = -1; @@ -144,16 +149,26 @@ public DataWrapper(DataWrapper wrapper, Parameters parameters) { /** * Constructs a data wrapper using a new DataSet as data model. + * + * @param dataSet the data set to use. */ public DataWrapper(DataSet dataSet) { setDataModel(dataSet); } + /** + * Constructs a data wrapper using a new DataSet as data model. + * + * @param graph the graph to use. + * @param parameters the parameters to use. + */ public DataWrapper(Graph graph, Parameters parameters) { if (graph == null) { throw new NullPointerException(); } + this.parameters = new Parameters(parameters); + List nodes = graph.getNodes(); List variables = new LinkedList<>(); @@ -173,28 +188,69 @@ public DataWrapper(Graph graph, Parameters parameters) { this.dataModelList = dataModelList; } + /** + * Constructs a data wrapper using a new DataSet as data model. + * + * @param dagWrapper the DAG to use. + * @param parameters the parameters to use. + */ public DataWrapper(DagWrapper dagWrapper, Parameters parameters) { this(dagWrapper.getDag(), parameters); } + /** + * Constructs a data wrapper using a new DataSet as data model. + * + * @param wrapper the SEM graph to use. + * @param parameters the parameters to use. + */ public DataWrapper(SemGraphWrapper wrapper, Parameters parameters) { this(wrapper.getGraph(), parameters); } + /** + * Constructs a data wrapper using a new DataSet as data model. + * + * @param wrapper the SEM graph to use. + * @param parameters the parameters to use. + */ public DataWrapper(GraphWrapper wrapper, Parameters parameters) { this(wrapper.getGraph(), parameters); } + /** + * Constructs a data wrapper using a new DataSet as data model. + * + * @param regression the regression to use. + * @param wrapper the data model to use. + * @param parameters the parameters to use. + */ public DataWrapper(RegressionRunner regression, DataWrapper wrapper, Parameters parameters) { - this(regression.getResult(), (DataSet) wrapper.getDataModelList().getSelectedModel(), parameters); + this(regression.getResult(), (DataSet) Objects.requireNonNull(wrapper.getDataModelList().getSelectedModel()), + parameters); } + /** + * Constructs a data wrapper using a new DataSet as data model. + * + * @param regression the regression to use. + * @param wrapper the data model to use. + * @param parameters the parameters to use. + */ public DataWrapper(RegressionRunner regression, Simulation wrapper, Parameters parameters) { - this(regression.getResult(), (DataSet) wrapper.getDataModelList().getSelectedModel(), parameters); + this(regression.getResult(), (DataSet) Objects.requireNonNull(wrapper.getDataModelList().getSelectedModel()), + parameters); } - // Computes regression predictions. + /** + * Constructs a data wrapper using a new DataSet as data model. + * + * @param result the regression result to use. + * @param data the data to use. + * @param parameters the parameters to use. + */ public DataWrapper(RegressionResult result, DataSet data, Parameters parameters) { + this.parameters = new Parameters(parameters); DataSet data2 = data.copy(); String predictedVariable = nextVariableName("Pred", data); @@ -229,7 +285,15 @@ public DataWrapper(RegressionResult result, DataSet data, Parameters parameters) this.dataModelList = dataModelList; } + /** + * Constructs a data wrapper using a new DataSet as data model. + * + * @param mimBuild the mim build to use. + * @param parameters the parameters to use. + */ public DataWrapper(MimBuildRunner mimBuild, Parameters parameters) { + this.parameters = new Parameters(parameters); + ICovarianceMatrix cov = mimBuild.getCovMatrix(); DataModelList dataModelList = new DataModelList(); @@ -279,8 +343,6 @@ private String nextVariableName(String base, DataSet data) { return name; } - //==============================PUBLIC METHODS========================// - /** * Stores a reference to the data model being wrapped. * @@ -290,6 +352,11 @@ public DataModelList getDataModelList() { return this.dataModelList; } + /** + * Set the data model list. + * + * @param dataModelList the data model list to set. + */ public void setDataModelList(DataModelList dataModelList) { if (dataModelList == null) { throw new NullPointerException("Data model list not provided."); @@ -297,12 +364,15 @@ public void setDataModelList(DataModelList dataModelList) { this.dataModelList = dataModelList; } + /** + * @return the data model for this wrapper. + */ public List getDataModels() { return new ArrayList<>(this.dataModelList); } /** - * @return the data model for this wrapper. + * @return the selected data model for this wrapper. */ public DataModel getSelectedDataModel() { DataModelList modelList = getDataModelList(); @@ -311,6 +381,8 @@ public DataModel getSelectedDataModel() { /** * Sets the data model. + * + * @param dataModel the data model to set. */ public void setDataModel(DataModel dataModel) { if (dataModel == null) { @@ -326,20 +398,31 @@ public void setDataModel(DataModel dataModel) { } } + /** + * @return the knowledge for this wrapper. + */ public Knowledge getKnowledge() { - return getSelectedDataModel().getKnowledge(); + return getSelectedDataModel().getKnowledge().copy(); } + /** + * Sets knowledge to a copy of the given object. + * + * @param knowledge the knowledge to set. + */ public void setKnowledge(Knowledge knowledge) { - getSelectedDataModel().setKnowledge(knowledge); + getSelectedDataModel().setKnowledge(knowledge.copy()); } + /** + * @return the variable names of the selected data model. + */ public List getVarNames() { return getSelectedDataModel().getVariableNames(); } /** - * @return the source workbench, if there is one. + * @return the source graph. */ public Graph getSourceGraph() { return this.sourceGraph; @@ -347,29 +430,27 @@ public Graph getSourceGraph() { /** * Sets the source graph. + * + * @param sourceGraph the source graph to set. */ protected void setSourceGraph(Graph sourceGraph) { this.sourceGraph = sourceGraph; } + /** + * @return the result graph. + */ public Graph getResultGraph() { return getSourceGraph(); } /** - * @return the variable names, in order. + * @return the variables, in order. */ public List getVariables() { return this.getSelectedDataModel().getVariables(); } - /** - * // * Sets the source graph. // - */ - public Map getDiscretizationSpecs() { - return this.discretizationSpecs; - } - /** * Adds semantic checks to the default deserialization method. This method must have the standard signature for a * readObject method, and the body of the method must begin with "s.defaultReadObject();". Other than that, any @@ -378,32 +459,51 @@ public Map getDiscretizationSpecs() { * class that didn't include it. (That's what the "s.defaultReadObject();" is for. See J. Bloch, Effective Java, for * help. */ + @Serial private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); } + /** + * @return the name of the data wrapper. + */ public String getName() { return this.name; } + /** + * Sets the name of the data wrapper. + * + * @param name the name to set. + */ public void setName(String name) { this.name = name; } /** - * This method is overridden by classes that can identify parameters. + * Returns the parameters being edited. * - * @return null + * @return the parameters being edited. */ public Parameters getParams() { return this.parameters; } + /** + * Sets the parameters being edited. + * + * @param parameters the parameters to set. + */ public void setParameters(Parameters parameters) { this.parameters = parameters; } + /** + * Returns the variable names. + * + * @return the variable names. + */ public List getVariableNames() { List variableNames = new ArrayList<>(); for (Node n : getVariables()) { @@ -412,6 +512,11 @@ public List getVariableNames() { return variableNames; } + /** + * Returns the parameter setting map. + * + * @return the parameter setting map. + */ @Override public Map getParamSettings() { Map paramSettings = new HashMap<>(); @@ -426,14 +531,10 @@ public Map getParamSettings() { DataModel dataModel = this.dataModelList.get(0); if (dataModel instanceof CovarianceMatrix) { - if (!paramSettings.containsKey("# Nodes")) { - paramSettings.put("# Vars", Integer.toString(((CovarianceMatrix) dataModel).getDimension())); - } + paramSettings.put("# Vars", Integer.toString(((CovarianceMatrix) dataModel).getDimension())); paramSettings.put("N", Integer.toString(((CovarianceMatrix) dataModel).getSampleSize())); } else { - if (!paramSettings.containsKey("# Nodes")) { - paramSettings.put("# Vars", Integer.toString(((DataSet) dataModel).getNumColumns())); - } + paramSettings.put("# Vars", Integer.toString(((DataSet) dataModel).getNumColumns())); paramSettings.put("N", Integer.toString(((DataSet) dataModel).getNumRows())); } } @@ -441,11 +542,21 @@ public Map getParamSettings() { return paramSettings; } + /** + * Returns the parameter setting map. + * + * @return the parameter setting map. + */ @Override public Map getAllParamSettings() { return this.allParamSettings; } + /** + * Sets the parameter setting map. + * + * @param paramSettings the parameter setting map to set. + */ @Override public void setAllParamSettings(Map paramSettings) { this.allParamSettings = paramSettings; diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/EmBayesEstimatorWrapper.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/EmBayesEstimatorWrapper.java index be285fa554..695b583314 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/EmBayesEstimatorWrapper.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/EmBayesEstimatorWrapper.java @@ -33,6 +33,7 @@ import java.io.IOException; import java.io.ObjectInputStream; +import java.io.Serial; /** * Wraps a Bayes Pm for use in the Tetrad application. @@ -41,6 +42,7 @@ * @author Frank Wimberly adapted for EM Bayes estimator and structural EM Bayes estimator */ public class EmBayesEstimatorWrapper implements SessionModel, GraphSource { + @Serial private static final long serialVersionUID = 23L; /** @@ -48,12 +50,6 @@ public class EmBayesEstimatorWrapper implements SessionModel, GraphSource { */ private String name; - /** - * @serial - * @deprecated - */ - private BayesPm bayesPm; - /** * @serial Cannot be null. */ diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/GraphSource.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/GraphSource.java index 628417ea55..420d4b892e 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/GraphSource.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/GraphSource.java @@ -29,8 +29,15 @@ * @author josephramsey */ public interface GraphSource { + + /** + * @return the graph produced by this source. + */ Graph getGraph(); + /** + * @return the name of the graph produced by this source. + */ String getName(); } diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/IndTestChooser.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/IndTestChooser.java index 3829a1bc98..de5ccde1a4 100755 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/IndTestChooser.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/IndTestChooser.java @@ -29,7 +29,6 @@ import edu.cmu.tetrad.search.score.SemBicScore; import edu.cmu.tetrad.search.test.*; import edu.cmu.tetrad.search.utils.ResolveSepsets; -import edu.cmu.tetrad.search.work_in_progress.IndTestFisherZGeneralizedInverse; import edu.cmu.tetrad.search.work_in_progress.IndTestFisherZPercentIndependent; import edu.cmu.tetrad.search.work_in_progress.IndTestMultinomialLogisticRegression; import edu.cmu.tetrad.util.Parameters; @@ -136,9 +135,11 @@ private IndependenceTest getContinuousTest(DataSet dataSet, if (IndTestType.FISHER_Z == testType) { return new IndTestFisherZ(dataSet, params.getDouble("alpha", 0.001)); } - if (IndTestType.FISHER_ZD == testType) { - return new IndTestFisherZGeneralizedInverse(dataSet, params.getDouble("alpha", 0.001)); - } +// if (IndTestType.FISHER_ZD == testType) { +// IndTestFisherZ test = new IndTestFisherZ(dataSet, params.getDouble("alpha", 0.001)); +//// test.setUsePseudoinverse(true); +// return test; +// } if (IndTestType.SEM_BIC == testType) { return new ScoreIndTest(new SemBicScore(new CovarianceMatrix(dataSet))); } diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/KnowledgeEditable.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/KnowledgeEditable.java index 6db0ceb7ad..784089d35e 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/KnowledgeEditable.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/KnowledgeEditable.java @@ -40,6 +40,8 @@ public interface KnowledgeEditable { /** * Sets knowledge to a copy of the given object. + * + * @param knowledge the knowledge to set. */ void setKnowledge(Knowledge knowledge); diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/LogData.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/LogData.java index f0832b3830..6b2346a430 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/LogData.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/LogData.java @@ -25,27 +25,34 @@ import edu.cmu.tetrad.util.Parameters; import edu.cmu.tetrad.util.TetradSerializableUtils; +import java.io.Serial; + /** - * Applies a logarithmic transform + * Applies a logarithmic transform. * * @author Jeremy Espino */ public class LogData extends DataWrapper { + @Serial private static final long serialVersionUID = 23L; //=============================CONSTRUCTORS==============================// + /** + * Applies a logarithmic transform to the data. + * + * @param wrapper The data to transform. + * @param params The parameters for the transformation. + */ public LogData(DataWrapper wrapper, Parameters params) { DataModelList inList = wrapper.getDataModelList(); DataModelList outList = new DataModelList(); for (DataModel model : inList) { - if (!(model instanceof DataSet)) { + if (!(model instanceof DataSet dataSet)) { throw new IllegalArgumentException("Not a data set: " + model.getName()); } - DataSet dataSet = (DataSet) model; - double a = params.getDouble("a"); boolean isUnlog = params.getBoolean("unlog"); int base = params.getInt("base"); diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/MarkovBlanketSearchRunner.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/MarkovBlanketSearchRunner.java index b4d8120180..01ea7351e6 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/MarkovBlanketSearchRunner.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/MarkovBlanketSearchRunner.java @@ -43,7 +43,7 @@ public interface MarkovBlanketSearchRunner extends Executable { /** - * Return the source for the search. + * @return the source for the search. */ DataSet getSource(); @@ -68,6 +68,7 @@ public interface MarkovBlanketSearchRunner extends Executable { /** * Sets the search name. + * @param n the name of the search. */ void setSearchName(String n); diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/MarkovCheckIndTestModel.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/MarkovCheckIndTestModel.java index a0dcba9ee0..583501fefb 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/MarkovCheckIndTestModel.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/MarkovCheckIndTestModel.java @@ -23,7 +23,9 @@ import edu.cmu.tetrad.data.DataModel; import edu.cmu.tetrad.data.Knowledge; +import edu.cmu.tetrad.data.KnowledgeBoxInput; import edu.cmu.tetrad.graph.Graph; +import edu.cmu.tetrad.graph.Node; import edu.cmu.tetrad.search.ConditioningSetType; import edu.cmu.tetrad.search.IndependenceTest; import edu.cmu.tetrad.search.MarkovCheck; @@ -32,27 +34,65 @@ import edu.cmu.tetrad.util.Parameters; import edu.cmu.tetrad.util.TetradSerializableUtils; +import java.io.Serial; import java.util.LinkedList; import java.util.List; /** - * Stores a list of independence facts. + * A model for the Markov check. The Markov check for a given graph and dataset checks whether the graph is Markov with + * respect to the dataset. The Markov check can be used to check whether a graph is Markov with respect to a dataset, or + * whether a graph is Markov with respect to a dataset and a set of variables. The Markov check can also be used to + * check whether a graph is Markov with respect to a dataset and a set of variables, given a set of knowledge. For facts + * of the form X _||_ Y | Z, X and Y should be in the last tier of the knowledge, and Z should be in previous tiers. * * @author josephramsey */ -public class MarkovCheckIndTestModel implements SessionModel, GraphSource { +public class MarkovCheckIndTestModel implements SessionModel, GraphSource, KnowledgeBoxInput { + @Serial private static final long serialVersionUID = 23L; + // The data model to check. private final DataModel dataModel; - private final Parameters parameters; + // The graph to check. private final Graph graph; + // The parameters. + private final Parameters parameters; + // The name of this model. private String name = ""; + // The variables to check. private List vars = new LinkedList<>(); + // The Markov check object. private transient MarkovCheck markovCheck = null; + // The knowledge to use. This will be passed to the underlying Markov check object. For facts odf the form + // X _||_ Y | Z, X and Y should be in the last tier, and Z should be in previous tiers. + private Knowledge knowledge; + /** + * Constructs a new Markov checer with the given data model, graph, and parameters. + * + * @param dataModel the data model. + * @param graphSource the graph source. + * @param parameters the parameters. + */ public MarkovCheckIndTestModel(DataWrapper dataModel, GraphSource graphSource, Parameters parameters) { + this(dataModel, graphSource, null, parameters); + } + + /** + * Constructs a new Markov checker with the given data model, graph, and parameters. + * + * @param dataModel the data model. + * @param graphSource the graph source. + * @param parameters the parameters. + */ + public MarkovCheckIndTestModel(DataWrapper dataModel, GraphSource graphSource, KnowledgeBoxModel knowlegeBox, + Parameters parameters) { this.dataModel = dataModel.getSelectedDataModel(); this.graph = graphSource.getGraph(); this.parameters = parameters; + + if (knowlegeBox != null) { + this.knowledge = knowlegeBox.getKnowledge(); + } } /** @@ -64,49 +104,167 @@ public static Knowledge serializableInstance() { return new Knowledge(); } + /** + * Sets the independence test and constructs the underlying MarkovCheck object. + * + * @param test the independence test. + */ public void setIndependenceTest(IndependenceTest test) { this.markovCheck = new MarkovCheck(this.graph, test, this.markovCheck == null ? ConditioningSetType.LOCAL_MARKOV : this.markovCheck.getSetType()); + if (this.knowledge != null) { + this.markovCheck.setKnowledge(this.knowledge); + } } + /** + * Returns the underlying MarkovCheck object. + * + * @return the underlying MarkovCheck object. + */ public MarkovCheck getMarkovCheck() { return this.markovCheck; } + /** + * Returns the graph. + * + * @return the graph. + */ @Override public Graph getGraph() { return this.graph; } + /** + * Returns the data model. + * + * @return the data model. + */ public DataModel getDataModel() { return dataModel; } + /** + * Returns the parameters. + * + * @return the parameters. + */ public Parameters getParameters() { return parameters; } + /** + * Returns the name of this model. + * + * @return the name of this model. + */ @Override public String getName() { return this.name; } + /** + * Sets the name of this model. + * + * @param name the name of this model. + */ @Override public void setName(String name) { this.name = name; } + /** + * Returns the variables to check. + * + * @return the variables to check. + */ public List getVars() { return this.vars; } + /** + * Sets the variables to check. + * + * @param vars the variables to check. + */ public void setVars(List vars) { this.vars = vars; } + /** + * Returns the results of the Markov check. + * + * @param indep whether to return the results for the independence test or the dependence test. + * @return the results of the Markov check. + */ public List getResults(boolean indep) { return markovCheck.getResults(indep); } + + /** + * Returns the knowledge to use. This will be passed to the underlying Markov check object. For facts of the form X + * _||_ Y | Z, X and Y should be in the last tier, and Z should be in previous tiers. + * + * @return the knowledge to use. + */ + public Knowledge getKnowledge() { + return this.knowledge; + } + + /** + * Sets the knowledge to use. This will be passed to the underlying Markov check object. For facts of the form X + * _||_ Y | Z, X and Y should be in the last tier, and Z should be in previous tiers. + * + * @param knowledge a knowledge object. + */ + public void setKnowledge(Knowledge knowledge) { + this.knowledge = knowledge.copy(); + + if (this.markovCheck != null) { + this.markovCheck.setKnowledge(this.knowledge); + } + } + + /** + * Returns the source graph. + * + * @return the source graph. + */ + @Override + public Graph getSourceGraph() { + return null; + } + + /** + * Returns the result graph. + * + * @return the result graph. + */ + @Override + public Graph getResultGraph() { + return null; + } + + /** + * Returns the variables. + * + * @return the variables. + */ + @Override + public List getVariables() { + return null; + } + + /** + * Returns the variable names. + * + * @return the variable names. + */ + @Override + public List getVariableNames() { + return null; + } } diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/PValueImproverWrapper.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/PValueImproverWrapper.java index 27faa11081..b6dad98b95 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/PValueImproverWrapper.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/PValueImproverWrapper.java @@ -35,6 +35,7 @@ import java.beans.PropertyChangeListener; import java.io.IOException; import java.io.ObjectInputStream; +import java.io.Serial; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; @@ -45,27 +46,18 @@ * @author Ricardo Silva */ public class PValueImproverWrapper extends AbstractAlgorithmRunner { + @Serial private static final long serialVersionUID = 23L; private final DataWrapper dataWrapper; private final Parameters params = new Parameters(); - /** - * @deprecated - */ - private final double alpha = 0.05; private AlgorithmType algorithmType = AlgorithmType.BEAM; private String name; private Graph externalGraph; private Graph graph; private transient List listeners; private Parameters params2; - private SemIm estSem; - private Graph trueDag; private SemIm originalSemIm; private SemIm newSemIm; - /** - * @deprecated - */ - private SemIm semIm; public PValueImproverWrapper(DataWrapper dataWrapper, Parameters params, KnowledgeBoxModel knowledgeBoxModel) { diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/SelectedDataset.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/SelectedDataset.java new file mode 100644 index 0000000000..bf11b0dbca --- /dev/null +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/SelectedDataset.java @@ -0,0 +1,70 @@ +/////////////////////////////////////////////////////////////////////////////// +// 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.model; + +import edu.cmu.tetrad.data.*; +import edu.cmu.tetrad.util.Parameters; +import edu.cmu.tetrad.util.TetradSerializableUtils; + +import java.io.Serial; + +/** + * Extracts a single dataset from a data box containing multiple datasets. + * + * @author josephramsey + */ +public class SelectedDataset extends DataWrapper { + @Serial + private static final long serialVersionUID = 23L; + + //=============================CONSTRUCTORS==============================// + + /** + * Applies a logarithmic transform to the data. + * + * @param wrapper The data to transform. + * @param params The parameters for the transformation. + */ + public SelectedDataset(DataWrapper wrapper, Parameters params) { + DataModelList inList = wrapper.getDataModelList(); + DataModelList outList = new DataModelList(); + DataModel selected = inList.getSelectedModel(); + outList.add(selected); + setDataModel(outList); + setSourceGraph(wrapper.getSourceGraph()); + LogDataUtils.logDataModelList("Extracted Data Model", getDataModelList()); + + } + + /** + * Generates a simple exemplar of this class to test serialization. + * + * @see TetradSerializableUtils + */ + public static PcRunner serializableInstance() { + return PcRunner.serializableInstance(); + } + +} + + + diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/SemEstimatorWrapper.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/SemEstimatorWrapper.java index 8f6641861b..40085cb70c 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/SemEstimatorWrapper.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/SemEstimatorWrapper.java @@ -32,6 +32,7 @@ import javax.swing.*; import java.io.IOException; import java.io.ObjectInputStream; +import java.io.Serial; import java.util.LinkedList; import java.util.List; @@ -41,8 +42,7 @@ * @author josephramsey */ public class SemEstimatorWrapper implements SessionModel { - ;//}, Unmarshallable { - + @Serial private static final long serialVersionUID = 23L; private final Parameters params; private final SemPm semPm; @@ -65,8 +65,7 @@ public SemEstimatorWrapper(DataModel dataModel, SemPm semPm, Parameters params) this.params = params; this.semPm = semPm; - if (dataModel instanceof DataSet) { - DataSet dataSet = (DataSet) dataModel; + if (dataModel instanceof DataSet dataSet) { SemEstimator estimator = new SemEstimator(dataSet, semPm, getOptimizer()); estimator.setNumRestarts(getParams().getInt("numRestarts", 1)); estimator.setScoreType((ScoreType) getParams().get("scoreType", ScoreType.Fgls)); @@ -135,7 +134,7 @@ private static boolean containsCovarParam(SemPm semPm) { private boolean degreesOfFreedomCheck(SemPm semPm) { if (semPm.getDof() < 1) { int ret = JOptionPane.showConfirmDialog(JOptionUtils.centeringComp(), - "This model has nonpositive degrees of freedom (DOF = " + "This model has non-positive degrees of freedom (DOF = " + semPm.getDof() + "). " + "\nEstimation will be uninformative. Are you sure you want to proceed?", "Please confirm", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); @@ -193,9 +192,10 @@ private void log() { * readObject method, and the body of the method must begin with "s.defaultReadObject();". Other than that, any * semantic checks can be specified and do not need to stay the same from version to version. A readObject method of * this form may be added to any class, even if Tetrad sessions were previously saved out using a version of the - * class that didn't include it. (That's what the "s.defaultReadObject();" is for. See J. Bloch, Effective Java, for + * class that didn't include it. (That's what the "s.defaultReadObject();" is for). See J. Bloch, Effective Java, for * help. */ + @Serial private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/datamanip/DiscretizationWrapper.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/datamanip/DiscretizationWrapper.java index 0f1e014413..6a1e5c8854 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/datamanip/DiscretizationWrapper.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/datamanip/DiscretizationWrapper.java @@ -30,6 +30,7 @@ import java.io.IOException; import java.io.ObjectInputStream; +import java.io.Serial; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -41,18 +42,9 @@ * @author Tyler */ public class DiscretizationWrapper extends DataWrapper { + @Serial private static final long serialVersionUID = 23L; - - /** - * The discretized data set. - * - * @serial Not null. - * @deprecated - */ - private final List discretizedDataSets = null; - - /** * Constructs the DiscretizationWrapper by discretizing the select * DataModel. diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/datamanip/SplitCasesWrapper.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/datamanip/SplitCasesWrapper.java index e0807e838d..efa88ea5f0 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/datamanip/SplitCasesWrapper.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/model/datamanip/SplitCasesWrapper.java @@ -28,6 +28,7 @@ import edu.cmu.tetradapp.model.DataWrapper; import edu.cmu.tetradapp.model.PcRunner; +import java.io.Serial; import java.util.ArrayList; import java.util.List; @@ -37,6 +38,7 @@ * @author Tyler Gibson */ public class SplitCasesWrapper extends DataWrapper { + @Serial private static final long serialVersionUID = 23L; /** @@ -82,7 +84,7 @@ private static DataModel createSplits(DataSet dataSet, Parameters params) { } SplitCasesSpec spec = (SplitCasesSpec) params.get("splitCasesSpec", null); - int numSplits = params.getInt("numSplits", 3); + int numSplits = params.getInt("numSplits", 2); int sampleSize = spec.getSampleSize(); int[] breakpoints = spec.getBreakpoints(); List splitNames = spec.getSplitNames(); diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/ui/model/AlgorithmModel.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/ui/model/AlgorithmModel.java index 400150317e..38d5ce0518 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/ui/model/AlgorithmModel.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/ui/model/AlgorithmModel.java @@ -47,10 +47,10 @@ public AlgorithmModel(AnnotatedClass algorithm) { } this.algorithm = algorithm; - this.name = algorithm.getAnnotation().name(); - this.description = AlgorithmDescriptions.getInstance().get(algorithm.getAnnotation().command()); - this.requiredScore = UsesScoreWrapper.class.isAssignableFrom(algorithm.getClazz()); - this.requiredTest = TakesIndependenceWrapper.class.isAssignableFrom(algorithm.getClazz()); + this.name = algorithm.annotation().name(); + this.description = AlgorithmDescriptions.getInstance().get(algorithm.annotation().command()); + this.requiredScore = UsesScoreWrapper.class.isAssignableFrom(algorithm.clazz()); + this.requiredTest = TakesIndependenceWrapper.class.isAssignableFrom(algorithm.clazz()); } @Override diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/ui/model/AlgorithmModels.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/ui/model/AlgorithmModels.java index a922911f96..10edcedf46 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/ui/model/AlgorithmModels.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/ui/model/AlgorithmModels.java @@ -68,7 +68,7 @@ private void refreshModels() { } // group by datatype - this.models.forEach(e -> map.get(e.getAlgorithm().getAnnotation().algoType()).add(e)); + this.models.forEach(e -> map.get(e.getAlgorithm().annotation().algoType()).add(e)); // make it unmodifiable map.forEach((k, v) -> map.put(k, Collections.unmodifiableList(v))); @@ -81,9 +81,9 @@ private List filterInclusivelyByAllOrSpecificDataType(List !multiDataSetAlgorithm || algoAnno.takesMultipleDataset(e.getAlgorithm().getClazz())) + .filter(e -> !multiDataSetAlgorithm || algoAnno.takesMultipleDataset(e.getAlgorithm().clazz())) .filter(e -> { - for (DataType dt : e.getAlgorithm().getAnnotation().dataType()) { + for (DataType dt : e.getAlgorithm().annotation().dataType()) { if (dt == DataType.All || dt == dataType) { return true; } diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/ui/model/IndependenceTestModel.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/ui/model/IndependenceTestModel.java index c95bda9237..1025a30544 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/ui/model/IndependenceTestModel.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/ui/model/IndependenceTestModel.java @@ -39,13 +39,13 @@ public class IndependenceTestModel implements Serializable, Comparable independenceTest) { this.independenceTest = independenceTest; - this.name = independenceTest.getAnnotation().name(); - this.description = IndependenceTestDescriptions.getInstance().get(independenceTest.getAnnotation().command()); + this.name = independenceTest.annotation().name(); + this.description = IndependenceTestDescriptions.getInstance().get(independenceTest.annotation().command()); } @Override public int compareTo(IndependenceTestModel other) { - return this.independenceTest.getAnnotation().name().compareTo(other.independenceTest.getAnnotation().name()); + return this.independenceTest.annotation().name().compareTo(other.independenceTest.annotation().name()); } @Override diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/ui/model/IndependenceTestModels.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/ui/model/IndependenceTestModels.java index 7db98b953e..bc59f0fb05 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/ui/model/IndependenceTestModels.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/ui/model/IndependenceTestModels.java @@ -70,7 +70,7 @@ private void initModelMap() { // group by datatype this.models.forEach(e -> { - DataType[] types = e.getIndependenceTest().getAnnotation().dataType(); + DataType[] types = e.getIndependenceTest().annotation().dataType(); for (DataType dataType : types) { this.modelMap.get(dataType).add(e); } @@ -106,7 +106,7 @@ private void initDefaultModelMap() { this.defaultModelMap.put(dataType, list.get(0)); } else { Optional result = list.stream() - .filter(e -> e.getIndependenceTest().getClazz().getName().equals(value)) + .filter(e -> e.getIndependenceTest().clazz().getName().equals(value)) .findFirst(); this.defaultModelMap.put(dataType, result.orElseGet(() -> list.get(0))); } diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/ui/model/ScoreModel.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/ui/model/ScoreModel.java index 148c4aa2ce..029c16ecf1 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/ui/model/ScoreModel.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/ui/model/ScoreModel.java @@ -39,13 +39,13 @@ public class ScoreModel implements Serializable, Comparable { public ScoreModel(AnnotatedClass score) { this.score = score; - this.name = score.getAnnotation().name(); - this.description = ScoreDescriptions.getInstance().get(score.getAnnotation().command()); + this.name = score.annotation().name(); + this.description = ScoreDescriptions.getInstance().get(score.annotation().command()); } @Override public int compareTo(ScoreModel other) { - return this.score.getAnnotation().name().compareTo(other.score.getAnnotation().name()); + return this.score.annotation().name().compareTo(other.score.annotation().name()); } @Override diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/ui/model/ScoreModels.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/ui/model/ScoreModels.java index 7ce33e5867..0bb691f9f4 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/ui/model/ScoreModels.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/ui/model/ScoreModels.java @@ -71,7 +71,7 @@ private void initModelMap() { // group by datatype this.models.forEach(e -> { - DataType[] types = e.getScore().getAnnotation().dataType(); + DataType[] types = e.getScore().annotation().dataType(); for (DataType dataType : types) { this.modelMap.get(dataType).add(e); } @@ -107,7 +107,7 @@ private void initDefaultModelMap() { this.defaultModelMap.put(dataType, list.get(0)); } else { Optional result = list.stream() - .filter(e -> e.getScore().getClazz().getName().equals(value)) + .filter(e -> e.getScore().clazz().getName().equals(value)) .findFirst(); this.defaultModelMap.put(dataType, result.orElseGet(() -> list.get(0))); } diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/util/ImageUtils.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/util/ImageUtils.java index 4dcbacc4b1..b221fcb8bd 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/util/ImageUtils.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/util/ImageUtils.java @@ -53,7 +53,7 @@ public static Image getImage(Object anchor, String path) { throw new NullPointerException("Path must not be null."); } - String fullPath = "/resources/images/" + path; + String fullPath = "/docs/images/" + path; URL url = anchor.getClass().getResource(fullPath); if (url == null) { diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/util/IndTestType.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/util/IndTestType.java index 3b38986a4a..601c44be12 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/util/IndTestType.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/util/IndTestType.java @@ -25,6 +25,7 @@ import edu.cmu.tetrad.util.TetradSerializable; import java.io.ObjectStreamException; +import java.io.Serial; /** * A typesafe enumeration of the types of independence tests that are used for basic search algorithm in this package. @@ -60,10 +61,11 @@ public final class IndTestType implements TetradSerializable { new IndTestType("Fisher Z Pooled Residuals", DataType.Continuous); public static final IndTestType FISHER = new IndTestType("Fisher (Fisher Z)", DataType.Continuous); public static final IndTestType TIPPETT = new IndTestType("Tippett (Fisher Z)", DataType.Continuous); + @Serial private static final long serialVersionUID = 23L; private static final IndTestType[] TYPES = {IndTestType.DEFAULT, IndTestType.CORRELATION_T, IndTestType.FISHER_Z, IndTestType.LINEAR_REGRESSION, IndTestType.CONDITIONAL_CORRELATION, IndTestType.SEM_BIC, IndTestType.LOGISTIC_REGRESSION, - IndTestType.MIXED_MLR, IndTestType.FISHER_ZD, + IndTestType.MIXED_MLR, //IndTestType.FISHER_ZD, IndTestType.G_SQUARE, IndTestType.CHI_SQUARE, IndTestType.M_SEPARATION, IndTestType.TIME_SERIES, diff --git a/tetrad-gui/src/main/java/edu/cmu/tetradapp/util/WatchedProcess.java b/tetrad-gui/src/main/java/edu/cmu/tetradapp/util/WatchedProcess.java index 97f6db77a7..e5fccb5d12 100644 --- a/tetrad-gui/src/main/java/edu/cmu/tetradapp/util/WatchedProcess.java +++ b/tetrad-gui/src/main/java/edu/cmu/tetradapp/util/WatchedProcess.java @@ -1,19 +1,23 @@ package edu.cmu.tetradapp.util; +import edu.cmu.tetrad.util.TetradLogger; +import edu.cmu.tetradapp.Tetrad; + import javax.swing.*; import javax.swing.border.BevelBorder; import java.awt.*; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; /** - *

Runs a long process, watching it with a thread and popping up a Stop button that the user can click to stop the - * process.

- * - *

Replacement for the old WatchedProcess, which called the deprecated Thread.stop() method. This method is - * deprecated because it can leave the program in an inconsistent state. This class uses Thread.interrupt() instead, - * which is the recommended way to stop a thread.

- * - *

Example usage:

- * + * Runs a long process, watching it with a thread and popping up a Stop button that the user can click to stop the + * process. + *

+ * Replacement for the old WatchedProcess, which called the deprecated Thread.stop() method. This method is deprecated + * because it can leave the program in an inconsistent state. This class uses Thread.interrupt() instead, which is the + * recommended way to stop a thread. + *

+ * Example usage: *

  * class MyWatchedProcess extends WatchedProcess {
  *
@@ -38,10 +42,28 @@ public abstract class WatchedProcess {
      * Constructor.
      */
     public WatchedProcess() {
-        frame = new JFrame("Hidden Frame");
+
+        // Get the Tetrad frame.
+        frame = Tetrad.frame;
+
+        if (frame == null) {
+            throw new RuntimeException("Tetrad frame is null. Cannot create WatchedProcess.");
+        }
+
         startLongRunningThread();
     }
 
+    private void positionDialogAboveFrameCenter(JFrame frame, JDialog dialog) {
+        // Calculate the new position for the dialog
+        Point newDialogPosition = new Point(
+                frame.getX() + frame.getWidth() / 2 - dialog.getWidth() / 2, // Centered horizontally
+                frame.getY() + frame.getHeight() / 2 - dialog.getHeight() / 2 // Centered vertically
+        );
+
+        // Set the dialog's new position
+        dialog.setLocation(newDialogPosition);
+    }
+
     /**
      * This is the method that will be called in a separate thread. It should be a long-running process that can be
      * interrupted by the user.
@@ -52,49 +74,50 @@ public WatchedProcess() {
 
     private void startLongRunningThread() {
         longRunningThread = new Thread(() -> {
-            if (Thread.interrupted()) {
-                // Thread was interrupted, so exit the loop and terminate
-                System.out.println("Thread was interrupted. Stopping...");
-                return;
-            }
-
             try {
                 watch();
             } catch (InterruptedException e) {
-                // Thread was interrupted while sleeping, so exit the loop and terminate
-                System.out.println("Thread was interrupted while watching. Stopping...");
-                return;
+                TetradLogger.getInstance().forceLogMessage("Thread was interrupted while watching. Stopping...");
+            } catch (Exception e) {
+                TetradLogger.getInstance().forceLogMessage("Exception while watching: " + e.getMessage());
             }
 
             if (dialog != null) {
-                dialog.dispose();
-                dialog = null;
+                SwingUtilities.invokeLater(() -> dialog.dispose());
             }
         });
 
-        longRunningThread.start();
-
         showStopDialog();
-    }
-
-    private void stopLongRunningThread() {
-        if (longRunningThread != null && longRunningThread.isAlive()) {
-            longRunningThread.interrupt();
-        }
+        longRunningThread.start();
     }
 
     private void showStopDialog() {
         dialog = new JDialog(frame, "Stop Process", Dialog.ModalityType.APPLICATION_MODAL);
         dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
         dialog.setUndecorated(true);
-        dialog.setSize(100, 50);
+        dialog.setSize(200, 50);
         dialog.setResizable(false);
+        dialog.setModalityType(Dialog.ModalityType.APPLICATION_MODAL);
+
+        frame.addComponentListener(new ComponentAdapter() {
+            @Override
+            public void componentMoved(ComponentEvent e) {
+                if (dialog != null) {
+                    positionDialogAboveFrameCenter(frame, dialog);
+                }
+            }
+        });
 
-        JButton stopButton = new JButton("Processing...");
+        JButton stopButton = new JButton("Processing (click to stop)...");
 
         stopButton.addActionListener(e -> {
-            stopLongRunningThread();
-            dialog.dispose();
+            if (longRunningThread != null) {
+                SwingUtilities.invokeLater(() -> longRunningThread.interrupt());
+            }
+
+            if (dialog != null) {
+                SwingUtilities.invokeLater(() -> dialog.dispose());
+            }
         });
 
         JPanel panel = new JPanel();
@@ -103,8 +126,8 @@ private void showStopDialog() {
         panel.add(stopButton);
 
         dialog.getContentPane().add(panel);
+        positionDialogAboveFrameCenter(frame, dialog);
 
-        dialog.setLocationRelativeTo(frame);
-        dialog.setVisible(true);
+        SwingUtilities.invokeLater(() -> dialog.setVisible(true));
     }
 }
diff --git a/tetrad-gui/src/main/resources/config/devConfig.xml b/tetrad-gui/src/main/resources/config/devConfig.xml
index 14bff1cbeb..d77283ca49 100644
--- a/tetrad-gui/src/main/resources/config/devConfig.xml
+++ b/tetrad-gui/src/main/resources/config/devConfig.xml
@@ -436,6 +436,17 @@
                 
                 edu.cmu.tetradapp.editor.DataEditor
             
+            
+                
+                    
+                    
+                
+                
+                    edu.cmu.tetradapp.model.SelectedDataset
+                
+                edu.cmu.tetradapp.editor.DataEditor
+            
             
             
             
@@ -1142,11 +1153,21 @@
                 edu.cmu.tetradapp.editor.EdgeWeightComparisonEditor
             
             
+                   help="Model Fit" category="Simulation-Algorithm Comparisons">
                 edu.cmu.tetradapp.model.CPDAGFitModel
                 
                 edu.cmu.tetradapp.editor.CPDAGFitEditor
             
+            
+                
+                    
+                    
+                
+                edu.cmu.tetradapp.model.CheckKnowledgeModel
+                
+                edu.cmu.tetradapp.editor.CheckKnowledgeEditor
+            
         
         
         
diff --git a/tetrad-gui/src/main/resources/config/prodConfig.xml b/tetrad-gui/src/main/resources/config/prodConfig.xml
index f3494d414d..8c4c51bb8c 100644
--- a/tetrad-gui/src/main/resources/config/prodConfig.xml
+++ b/tetrad-gui/src/main/resources/config/prodConfig.xml
@@ -409,6 +409,17 @@
                 
                 edu.cmu.tetradapp.editor.DataEditor
             
+            
+                
+                    
+                    
+                
+                
+                    edu.cmu.tetradapp.model.SelectedDataset
+                
+                edu.cmu.tetradapp.editor.DataEditor
+            
             
                 
@@ -1112,11 +1123,21 @@
                 edu.cmu.tetradapp.editor.EdgeWeightComparisonEditor
             
             
+                   help="Model Fit" category="Simulation-Algorithm Comparisons">
                 edu.cmu.tetradapp.model.CPDAGFitModel
                 
                 edu.cmu.tetradapp.editor.CPDAGFitEditor
             
+            
+                
+                    
+                    
+                
+                edu.cmu.tetradapp.model.CheckKnowledgeModel
+                
+                edu.cmu.tetradapp.editor.CheckKnowledgeEditor
+            
         
         
         
diff --git a/tetrad-lib/dependency-reduced-pom.xml b/tetrad-lib/dependency-reduced-pom.xml
index 1a34c60792..1c02aa9cb9 100644
--- a/tetrad-lib/dependency-reduced-pom.xml
+++ b/tetrad-lib/dependency-reduced-pom.xml
@@ -3,7 +3,7 @@
   
     tetrad
     io.github.cmu-phil
-    7.6.0-SNAPSHOT
+    7.6.2-SNAPSHOT
   
   4.0.0
   tetrad-lib
@@ -20,35 +20,31 @@
         maven-compiler-plugin
         3.11.0
         
-          1.8
-          1.8
+          17
+          17
         
       
       
         maven-shade-plugin
-        3.1.0
+        3.5.1
         
           
             package
             
               shade
             
-          
-        
-      
-      
-        maven-antrun-plugin
-        3.1.0
-        
-          
-            compile
-            
-              run
-            
             
-              
-                
-              
+              
+                
+                  
+                    all-permissions
+                    ${project.name}
+                    ${project.version}
+                  
+                
+              
+              true
+              shaded
             
           
         
@@ -59,4 +55,3 @@
     UTF-8
   
 
-
diff --git a/tetrad-lib/pom.xml b/tetrad-lib/pom.xml
index b963ae99b4..1a0c086e3a 100644
--- a/tetrad-lib/pom.xml
+++ b/tetrad-lib/pom.xml
@@ -6,7 +6,7 @@
     
         io.github.cmu-phil
         tetrad
-        7.6.1
+        7.6.2-SNAPSHOT
     
 
     tetrad-lib
@@ -18,14 +18,14 @@
                 maven-compiler-plugin
                 3.11.0
                 
-                    1.8
-                    1.8
+                    17
+                    17
                 
             
             
                 org.apache.maven.plugins
                 maven-shade-plugin
-                3.1.0
+                3.5.1
                 
                     
                         package
@@ -50,25 +50,6 @@
                     
                 
             
-
-            
-                maven-antrun-plugin
-                3.1.0
-                
-                    
-                        compile
-                        
-                            run
-                        
-                        
-                            
-                                
-                            
-                        
-                    
-                
-            
         
         
             
@@ -93,7 +74,7 @@
         
             org.apache.commons
             commons-lang3
-            3.12.0
+            3.14.0
         
         
             colt
@@ -121,34 +102,22 @@
             1.0.3
             compile
         
-        
-        
-        
-        
-        
-
-        
         
             javax.help
             javahelp
             2.0.05
         
-
         
             com.google.code.gson
             gson
             2.10.1
         
-
-        
         
             org.json
             json
-            20230227
+            20231013
             compile
         
-
-        
         
             javax.xml.bind
             jaxb-api
@@ -156,14 +125,11 @@
         
 
         
-        
         
             org.jsoup
             jsoup
             1.15.4
         
-
-
         
             io.github.cmu-phil
             data-reader
@@ -177,10 +143,7 @@
         
     
 
-
     
         UTF-8
     
-
-
 
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/ReturnsBootstrapGraphs.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/ReturnsBootstrapGraphs.java
index f7375fad5c..8d6b19d258 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/ReturnsBootstrapGraphs.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/ReturnsBootstrapGraphs.java
@@ -6,6 +6,11 @@
 
 public interface ReturnsBootstrapGraphs {
 
+    /**
+     * Returns the bootstrap graphs.
+     *
+     * @return the bootstrap graphs.
+     */
     List getBootstrapGraphs();
 
 }
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/continuous/dag/Dagma.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/continuous/dag/Dagma.java
index a47570bffd..b0530b1f90 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/continuous/dag/Dagma.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/continuous/dag/Dagma.java
@@ -13,6 +13,7 @@
 import edu.cmu.tetrad.graph.EdgeListGraph;
 import edu.cmu.tetrad.graph.Graph;
 import edu.cmu.tetrad.search.score.Score;
+import edu.cmu.tetrad.search.utils.LogUtilsSearch;
 import edu.cmu.tetrad.util.Parameters;
 import edu.cmu.tetrad.util.Params;
 import edu.cmu.tetrad.util.TetradLogger;
@@ -50,7 +51,7 @@ public Graph search(DataModel dataSet, Parameters parameters) {
             search.setCpdag(parameters.getBoolean(Params.CPDAG));
             Graph graph = search.search();
             TetradLogger.getInstance().forceLogMessage(graph.toString());
-
+            LogUtilsSearch.stampWithBic(graph, dataSet);
             return graph;
         } else {
             Dagma algorithm = new Dagma();
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/continuous/dag/DirectLingam.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/continuous/dag/DirectLingam.java
index d30c33400d..339201ff8d 100644
--- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/continuous/dag/DirectLingam.java
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/continuous/dag/DirectLingam.java
@@ -56,7 +56,6 @@ public Graph search(DataModel dataSet, Parameters parameters) {
             edu.cmu.tetrad.search.DirectLingam search = new edu.cmu.tetrad.search.DirectLingam(data, score);
             Graph graph = search.search();
             TetradLogger.getInstance().forceLogMessage(graph.toString());
-
             LogUtilsSearch.stampWithBic(graph, dataSet);
             return graph;
         } else {
diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/multi/ImagesBoss.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/multi/ImagesBoss.java
new file mode 100644
index 0000000000..9aaa6bdc8c
--- /dev/null
+++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/multi/ImagesBoss.java
@@ -0,0 +1,218 @@
+package edu.cmu.tetrad.algcomparison.algorithm.multi;
+
+import edu.cmu.tetrad.algcomparison.algorithm.MultiDataSetAlgorithm;
+import edu.cmu.tetrad.algcomparison.algorithm.oracle.cpdag.Fges;
+import edu.cmu.tetrad.algcomparison.independence.IndependenceWrapper;
+import edu.cmu.tetrad.algcomparison.score.ScoreWrapper;
+import edu.cmu.tetrad.algcomparison.score.SemBicScore;
+import edu.cmu.tetrad.algcomparison.utils.HasKnowledge;
+import edu.cmu.tetrad.algcomparison.utils.UsesScoreWrapper;
+import edu.cmu.tetrad.annotation.AlgType;
+import edu.cmu.tetrad.annotation.Bootstrapping;
+import edu.cmu.tetrad.data.*;
+import edu.cmu.tetrad.graph.EdgeListGraph;
+import edu.cmu.tetrad.graph.Graph;
+import edu.cmu.tetrad.search.Boss;
+import edu.cmu.tetrad.search.PermutationSearch;
+import edu.cmu.tetrad.search.score.ImagesScore;
+import edu.cmu.tetrad.search.score.Score;
+import edu.cmu.tetrad.search.utils.TsUtils;
+import edu.cmu.tetrad.util.Parameters;
+import edu.cmu.tetrad.util.Params;
+import edu.pitt.dbmi.algo.resampling.GeneralResamplingTest;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Wraps the IMaGES algorithm for continuous variables. This version uses the BOSS algorithm in place of FGES.
+ * 

+ * Requires that the parameter 'randomSelectionSize' be set to indicate how many datasets should be taken at a time + * (randomly). This cannot given multiple values. + * + * @author josephramsey + */ +@edu.cmu.tetrad.annotation.Algorithm( + name = "IMaGES-BOSS", + command = "images-boss", + algoType = AlgType.forbid_latent_common_causes, + dataType = DataType.All +) +@Bootstrapping +public class ImagesBoss implements MultiDataSetAlgorithm, HasKnowledge, UsesScoreWrapper { + + private static final long serialVersionUID = 23L; + private Knowledge knowledge = new Knowledge(); + + private ScoreWrapper score = new SemBicScore(); + + public ImagesBoss(ScoreWrapper score) { + this.score = score; + } + + public ImagesBoss() { + } + + @Override + public Graph search(List dataSets, Parameters parameters) { + int meta = parameters.getInt(Params.IMAGES_META_ALG); + + if (parameters.getInt(Params.NUMBER_RESAMPLING) < 1) { + List _dataSets = new ArrayList<>(); + + if (parameters.getInt(Params.TIME_LAG) > 0) { + for (DataModel dataSet : dataSets) { + DataSet timeSeries = TsUtils.createLagData((DataSet) dataSet, parameters.getInt(Params.TIME_LAG)); + if (dataSet.getName() != null) { + timeSeries.setName(dataSet.getName()); + } + _dataSets.add(timeSeries); + } + + dataSets = _dataSets; + } + + List scores = new ArrayList<>(); + + for (DataModel dataModel : dataSets) { + Score s = score.getScore(dataModel, parameters); + scores.add(s); + } + + ImagesScore score = new ImagesScore(scores); + + if (meta == 1) { + PermutationSearch search = new PermutationSearch(new Boss(score)); + search.setSeed(parameters.getLong(Params.SEED)); +// edu.cmu.tetrad.search.Fges search = new edu.cmu.tetrad.search.Fges(score); + search.setKnowledge(this.knowledge); +// search.setVerbose(parameters.getBoolean(Params.VERBOSE)); + return search.search(); + } else if (meta == 2) { + PermutationSearch search = new PermutationSearch(new Boss(score)); + search.setKnowledge(this.knowledge); + return search.search(); + } else { + throw new IllegalArgumentException("Unrecognized meta option: " + meta); + } + } else { + ImagesBoss imagesSemBic = new ImagesBoss(); + + List dataSets2 = new ArrayList<>(); + + for (DataModel dataModel : dataSets) { + dataSets2.add((DataSet) dataModel); + } + + List _dataSets = new ArrayList<>(); + + if (parameters.getInt(Params.TIME_LAG) > 0) { + for (DataSet dataSet : dataSets2) { + DataSet timeSeries = TsUtils.createLagData(dataSet, parameters.getInt(Params.TIME_LAG)); + if (dataSet.getName() != null) { + timeSeries.setName(dataSet.getName()); + } + _dataSets.add(timeSeries); + } + + dataSets2 = _dataSets; + } + + GeneralResamplingTest search = new GeneralResamplingTest( + dataSets2, + imagesSemBic, + parameters.getInt(Params.NUMBER_RESAMPLING), + parameters.getDouble(Params.PERCENT_RESAMPLE_SIZE), + parameters.getBoolean(Params.RESAMPLING_WITH_REPLACEMENT), parameters.getInt(Params.RESAMPLING_ENSEMBLE), parameters.getBoolean(Params.ADD_ORIGINAL_DATASET)); + search.setParameters(parameters); + search.setVerbose(parameters.getBoolean(Params.VERBOSE)); + search.setKnowledge(this.knowledge); + search.setScoreWrapper(score); + return search.search(); + } + } + + @Override + public Graph search(DataModel dataSet, Parameters parameters) { + if (parameters.getInt(Params.NUMBER_RESAMPLING) < 1) { + return search(Collections.singletonList(SimpleDataLoader.getMixedDataSet(dataSet)), parameters); + } else { + ImagesBoss images = new ImagesBoss(); + + List dataSets = Collections.singletonList(SimpleDataLoader.getMixedDataSet(dataSet)); + GeneralResamplingTest search = new GeneralResamplingTest(dataSets, + images, + parameters.getInt(Params.NUMBER_RESAMPLING), + parameters.getDouble(Params.PERCENT_RESAMPLE_SIZE), + parameters.getBoolean(Params.RESAMPLING_WITH_REPLACEMENT), + parameters.getInt(Params.RESAMPLING_ENSEMBLE), + parameters.getBoolean(Params.ADD_ORIGINAL_DATASET)); + + if (score == null) { + System.out.println(); + } + + search.setParameters(parameters); + search.setVerbose(parameters.getBoolean(Params.VERBOSE)); + search.setScoreWrapper(score); + return search.search(); + } + } + + @Override + public Graph getComparisonGraph(Graph graph) { + return new EdgeListGraph(graph); + } + + @Override + public String getDescription() { + return "IMaGES"; + } + + @Override + public DataType getDataType() { + return DataType.All; + } + + @Override + public List getParameters() { + List parameters = new LinkedList<>(); + parameters.addAll(new SemBicScore().getParameters()); + + parameters.addAll((new Fges()).getParameters()); + parameters.add(Params.RANDOM_SELECTION_SIZE); + parameters.add(Params.TIME_LAG); + parameters.add(Params.IMAGES_META_ALG); + parameters.add(Params.SEED); + parameters.add(Params.VERBOSE); + + return parameters; + } + + @Override + public Knowledge getKnowledge() { + return this.knowledge; + } + + @Override + public void setKnowledge(Knowledge knowledge) { + this.knowledge = new Knowledge((Knowledge) knowledge); + } + + @Override + public ScoreWrapper getScoreWrapper() { + return this.score; + } + + @Override + public void setScoreWrapper(ScoreWrapper score) { + this.score = score; + } + + @Override + public void setIndTestWrapper(IndependenceWrapper test) { + // Not used. + } +} diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Boss.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Boss.java index a7c92da553..7d9a4a3868 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Boss.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Boss.java @@ -42,7 +42,7 @@ public class Boss implements Algorithm, UsesScoreWrapper, HasKnowledge, private ScoreWrapper score; private Knowledge knowledge = new Knowledge(); private List bootstrapGraphs = new ArrayList<>(); - + private long seed = 01; public Boss() { // Used in reflection; do not delete. @@ -54,6 +54,8 @@ public Boss(ScoreWrapper score) { @Override public Graph search(DataModel dataModel, Parameters parameters) { + this.seed = parameters.getLong(Params.SEED); + if (parameters.getInt(Params.NUMBER_RESAMPLING) < 1) { if (parameters.getInt(Params.TIME_LAG) > 0) { DataSet dataSet = (DataSet) dataModel; @@ -68,6 +70,7 @@ public Graph search(DataModel dataModel, Parameters parameters) { Score score = this.score.getScore(dataModel, parameters); edu.cmu.tetrad.search.Boss boss = new edu.cmu.tetrad.search.Boss(score); + boss.setUseBes(parameters.getBoolean(Params.USE_BES)); boss.setNumStarts(parameters.getInt(Params.NUM_STARTS)); boss.setNumThreads(parameters.getInt(Params.NUM_THREADS)); @@ -75,8 +78,10 @@ public Graph search(DataModel dataModel, Parameters parameters) { boss.setVerbose(parameters.getBoolean(Params.VERBOSE)); PermutationSearch permutationSearch = new PermutationSearch(boss); permutationSearch.setKnowledge(this.knowledge); + permutationSearch.setSeed(seed); Graph graph = permutationSearch.search(); - LogUtilsSearch.stampWithScores(graph, dataModel, score); + LogUtilsSearch.stampWithScore(graph, score); + LogUtilsSearch.stampWithBic(graph, dataModel); return graph; } else { Boss algorithm = new Boss(this.score); @@ -117,6 +122,7 @@ public List getParameters() { params.add(Params.TIME_LAG); params.add(Params.NUM_THREADS); params.add(Params.USE_DATA_ORDER); + params.add(Params.SEED); params.add(Params.VERBOSE); return params; diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/BossLingam.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/BossLingam.java index 4dc585c651..dac01c2201 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/BossLingam.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/BossLingam.java @@ -67,6 +67,7 @@ public Graph search(DataModel dataModel, Parameters parameters) { boss.setUseDataOrder(parameters.getBoolean(Params.USE_DATA_ORDER)); boss.setVerbose(parameters.getBoolean(Params.VERBOSE)); PermutationSearch permutationSearch = new PermutationSearch(boss); + permutationSearch.setSeed(parameters.getLong(Params.SEED)); permutationSearch.setKnowledge(this.knowledge); Graph cpdag = permutationSearch.search(); @@ -114,6 +115,7 @@ public List getParameters() { parameters.add(Params.TIME_LAG); parameters.add(Params.NUM_THREADS); parameters.add(Params.USE_DATA_ORDER); + parameters.add(Params.SEED); parameters.add(Params.VERBOSE); return parameters; } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Cpc.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Cpc.java index 7c34c9f73b..cfbdfa40ca 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Cpc.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Cpc.java @@ -65,47 +65,27 @@ public Graph search(DataModel dataModel, Parameters parameters) { knowledge = timeSeries.getKnowledge(); } - PcCommon.ConflictRule conflictRule; - - switch (parameters.getInt(Params.CONFLICT_RULE)) { - case 1: - conflictRule = PcCommon.ConflictRule.PRIORITIZE_EXISTING; - break; - case 2: - conflictRule = PcCommon.ConflictRule.ORIENT_BIDIRECTED; - break; - case 3: - conflictRule = PcCommon.ConflictRule.OVERWRITE_EXISTING; - break; - default: - throw new IllegalArgumentException("Unknown conflict rule: " + parameters.getInt(Params.CONFLICT_RULE)); - - } - -// PcCommon.PcHeuristicType pcHeuristicType; -// -// switch (parameters.getInt(Params.PC_HEURISTIC)) { -// case 0: -// pcHeuristicType = PcCommon.PcHeuristicType.NONE; -// break; -// case 1: -// pcHeuristicType = PcCommon.PcHeuristicType.HEURISTIC_1; -// break; -// case 2: -// pcHeuristicType = PcCommon.PcHeuristicType.HEURISTIC_2; -// break; -// case 3: -// pcHeuristicType = PcCommon.PcHeuristicType.HEURISTIC_3; -// break; -// default: -// throw new IllegalArgumentException("Unknown conflict rule: " + parameters.getInt(Params.CONFLICT_RULE)); -// -// } + PcCommon.ConflictRule conflictRule = switch (parameters.getInt(Params.CONFLICT_RULE)) { + case 1 -> PcCommon.ConflictRule.PRIORITIZE_EXISTING; + case 2 -> PcCommon.ConflictRule.ORIENT_BIDIRECTED; + case 3 -> PcCommon.ConflictRule.OVERWRITE_EXISTING; + default -> + throw new IllegalArgumentException("Unknown conflict rule: " + parameters.getInt(Params.CONFLICT_RULE)); + }; + + PcCommon.PcHeuristicType pcHeuristicType = switch (parameters.getInt(Params.PC_HEURISTIC)) { + case 0 -> PcCommon.PcHeuristicType.NONE; + case 1 -> PcCommon.PcHeuristicType.HEURISTIC_1; + case 2 -> PcCommon.PcHeuristicType.HEURISTIC_2; + case 3 -> PcCommon.PcHeuristicType.HEURISTIC_3; + default -> + throw new IllegalArgumentException("Unknown conflict rule: " + parameters.getInt(Params.CONFLICT_RULE)); + }; edu.cmu.tetrad.search.Cpc search = new edu.cmu.tetrad.search.Cpc(getIndependenceWrapper().getTest(dataModel, parameters)); search.setDepth(parameters.getInt(Params.DEPTH)); search.meekPreventCycles(parameters.getBoolean(Params.MEEK_PREVENT_CYCLES)); -// search.setPcHeuristicType(pcHeuristicType); + search.setPcHeuristicType(pcHeuristicType); search.setVerbose(parameters.getBoolean(Params.VERBOSE)); search.setKnowledge(knowledge); search.setConflictRule(conflictRule); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Fas.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Fas.java index bd8df26b75..babb6958dc 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Fas.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Fas.java @@ -14,11 +14,13 @@ import edu.cmu.tetrad.graph.EdgeListGraph; import edu.cmu.tetrad.graph.Graph; import edu.cmu.tetrad.graph.GraphTransforms; +import edu.cmu.tetrad.search.utils.PcCommon; import edu.cmu.tetrad.util.Parameters; import edu.cmu.tetrad.util.Params; import edu.pitt.dbmi.algo.resampling.GeneralResamplingTest; import java.io.PrintStream; +import java.io.Serial; import java.util.ArrayList; import java.util.List; @@ -36,6 +38,7 @@ public class Fas implements Algorithm, HasKnowledge, TakesIndependenceWrapper, ReturnsBootstrapGraphs { + @Serial private static final long serialVersionUID = 23L; private IndependenceWrapper test; private Knowledge knowledge = new Knowledge(); @@ -51,28 +54,18 @@ public Fas(IndependenceWrapper test) { @Override public Graph search(DataModel dataSet, Parameters parameters) { if (parameters.getInt(Params.NUMBER_RESAMPLING) < 1) { -// PcCommon.PcHeuristicType pcHeuristicType; -// -// switch (parameters.getInt(Params.PC_HEURISTIC)) { -// case 0: -// pcHeuristicType = PcCommon.PcHeuristicType.NONE; -// break; -// case 1: -// pcHeuristicType = PcCommon.PcHeuristicType.HEURISTIC_1; -// break; -// case 2: -// pcHeuristicType = PcCommon.PcHeuristicType.HEURISTIC_2; -// break; -// case 3: -// pcHeuristicType = PcCommon.PcHeuristicType.HEURISTIC_3; -// break; -// default: -// throw new IllegalArgumentException("Unknown conflict rule: " + parameters.getInt(Params.CONFLICT_RULE)); -// } + PcCommon.PcHeuristicType pcHeuristicType = switch (parameters.getInt(Params.PC_HEURISTIC)) { + case 0 -> PcCommon.PcHeuristicType.NONE; + case 1 -> PcCommon.PcHeuristicType.HEURISTIC_1; + case 2 -> PcCommon.PcHeuristicType.HEURISTIC_2; + case 3 -> PcCommon.PcHeuristicType.HEURISTIC_3; + default -> + throw new IllegalArgumentException("Unknown conflict rule: " + parameters.getInt(Params.CONFLICT_RULE)); + }; edu.cmu.tetrad.search.Fas search = new edu.cmu.tetrad.search.Fas(this.test.getTest(dataSet, parameters)); search.setStable(parameters.getBoolean(Params.STABLE_FAS)); -// search.setPcHeuristicType(pcHeuristicType); + search.setPcHeuristicType(pcHeuristicType); search.setDepth(parameters.getInt(Params.DEPTH)); search.setKnowledge(this.knowledge); search.setVerbose(parameters.getBoolean(Params.VERBOSE)); @@ -119,7 +112,7 @@ public DataType getDataType() { public List getParameters() { List parameters = new ArrayList<>(); parameters.add(Params.DEPTH); -// parameters.add(Params.PC_HEURISTIC); + parameters.add(Params.PC_HEURISTIC); parameters.add(Params.STABLE_FAS); parameters.add(Params.VERBOSE); return parameters; diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Fges.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Fges.java index d3298a8528..6b0c020a68 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Fges.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Fges.java @@ -100,11 +100,12 @@ public Graph search(DataModel dataModel, Parameters parameters) { graph = search.search(); - if (!graph.getAllAttributes().containsKey("BIC")) { + if (dataModel.isContinuous() && !graph.getAllAttributes().containsKey("BIC")) { graph.addAttribute("BIC", new BicEst().getValue(null, graph, dataModel)); } - LogUtilsSearch.stampWithScores(graph, dataModel, score); + LogUtilsSearch.stampWithScore(graph, score); + LogUtilsSearch.stampWithBic(graph, dataModel); return graph; } else { Fges fges = new Fges(this.score); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Grasp.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Grasp.java index 287699409d..796bf0758b 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Grasp.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Grasp.java @@ -16,6 +16,7 @@ import edu.cmu.tetrad.graph.EdgeListGraph; import edu.cmu.tetrad.graph.Graph; import edu.cmu.tetrad.search.IndependenceTest; +import edu.cmu.tetrad.search.score.GraphScore; import edu.cmu.tetrad.search.score.Score; import edu.cmu.tetrad.search.utils.LogUtilsSearch; import edu.cmu.tetrad.search.utils.TsUtils; @@ -75,6 +76,7 @@ public Graph search(DataModel dataModel, Parameters parameters) { test.setVerbose(parameters.getBoolean(Params.VERBOSE)); edu.cmu.tetrad.search.Grasp grasp = new edu.cmu.tetrad.search.Grasp(test, score); + grasp.setSeed(parameters.getLong(Params.SEED)); grasp.setDepth(parameters.getInt(Params.GRASP_DEPTH)); grasp.setUncoveredDepth(parameters.getInt(Params.GRASP_SINGULAR_DEPTH)); grasp.setNonSingularDepth(parameters.getInt(Params.GRASP_NONSINGULAR_DEPTH)); @@ -89,7 +91,11 @@ public Graph search(DataModel dataModel, Parameters parameters) { grasp.setKnowledge(this.knowledge); grasp.bestOrder(score.getVariables()); Graph graph = grasp.getGraph(parameters.getBoolean(Params.OUTPUT_CPDAG)); - LogUtilsSearch.stampWithScores(graph, dataModel, score); + LogUtilsSearch.stampWithScore(graph, score); + LogUtilsSearch.stampWithBic(graph, dataModel); + + LogUtilsSearch.stampWithBic(graph, dataModel); + return graph; } else { Grasp algorithm = new Grasp(this.test, this.score); @@ -136,6 +142,7 @@ public List getParameters() { params.add(Params.USE_DATA_ORDER); params.add(Params.ALLOW_INTERNAL_RANDOMNESS); params.add(Params.TIME_LAG); + params.add(Params.SEED); params.add(Params.VERBOSE); // Parameters diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Pc.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Pc.java index decfad9141..b1607fb99d 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Pc.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Pc.java @@ -20,6 +20,7 @@ import edu.cmu.tetrad.util.Params; import edu.pitt.dbmi.algo.resampling.GeneralResamplingTest; +import java.io.Serial; import java.util.ArrayList; import java.util.List; @@ -38,6 +39,7 @@ @Bootstrapping public class Pc implements Algorithm, HasKnowledge, TakesIndependenceWrapper, ReturnsBootstrapGraphs { + @Serial private static final long serialVersionUID = 23L; private IndependenceWrapper test; private Knowledge knowledge = new Knowledge(); @@ -63,47 +65,28 @@ public Graph search(DataModel dataModel, Parameters parameters) { knowledge = timeSeries.getKnowledge(); } - PcCommon.ConflictRule conflictRule; - - switch (parameters.getInt(Params.CONFLICT_RULE)) { - case 1: - conflictRule = PcCommon.ConflictRule.PRIORITIZE_EXISTING; - break; - case 2: - conflictRule = PcCommon.ConflictRule.ORIENT_BIDIRECTED; - break; - case 3: - conflictRule = PcCommon.ConflictRule.OVERWRITE_EXISTING; - break; - default: - throw new IllegalArgumentException("Unknown conflict rule: " + parameters.getInt(Params.CONFLICT_RULE)); - - } - -// PcCommon.PcHeuristicType pcHeuristicType; -// -// switch (parameters.getInt(Params.PC_HEURISTIC)) { -// case 0: -// pcHeuristicType = PcCommon.PcHeuristicType.NONE; -// break; -// case 1: -// pcHeuristicType = PcCommon.PcHeuristicType.HEURISTIC_1; -// break; -// case 2: -// pcHeuristicType = PcCommon.PcHeuristicType.HEURISTIC_2; -// break; -// case 3: -// pcHeuristicType = PcCommon.PcHeuristicType.HEURISTIC_3; -// break; -// default: -// throw new IllegalArgumentException("Unknown conflict rule: " + parameters.getInt(Params.CONFLICT_RULE)); -// } + PcCommon.ConflictRule conflictRule = switch (parameters.getInt(Params.CONFLICT_RULE)) { + case 1 -> PcCommon.ConflictRule.PRIORITIZE_EXISTING; + case 2 -> PcCommon.ConflictRule.ORIENT_BIDIRECTED; + case 3 -> PcCommon.ConflictRule.OVERWRITE_EXISTING; + default -> + throw new IllegalArgumentException("Unknown conflict rule: " + parameters.getInt(Params.CONFLICT_RULE)); + }; + + PcCommon.PcHeuristicType pcHeuristicType = switch (parameters.getInt(Params.PC_HEURISTIC)) { + case 0 -> PcCommon.PcHeuristicType.NONE; + case 1 -> PcCommon.PcHeuristicType.HEURISTIC_1; + case 2 -> PcCommon.PcHeuristicType.HEURISTIC_2; + case 3 -> PcCommon.PcHeuristicType.HEURISTIC_3; + default -> + throw new IllegalArgumentException("Unknown conflict rule: " + parameters.getInt(Params.CONFLICT_RULE)); + }; edu.cmu.tetrad.search.Pc search = new edu.cmu.tetrad.search.Pc(getIndependenceWrapper().getTest(dataModel, parameters)); search.setUseMaxPHeuristic(parameters.getBoolean(Params.USE_MAX_P_HEURISTIC)); search.setDepth(parameters.getInt(Params.DEPTH)); search.setMeekPreventCycles(parameters.getBoolean(Params.MEEK_PREVENT_CYCLES)); -// search.setPcHeuristicType(pcHeuristicType); + search.setPcHeuristicType(pcHeuristicType); search.setVerbose(parameters.getBoolean(Params.VERBOSE)); search.setKnowledge(this.knowledge); search.setStable(parameters.getBoolean(Params.STABLE_FAS)); @@ -149,7 +132,7 @@ public List getParameters() { parameters.add(Params.USE_MAX_P_HEURISTIC); parameters.add(Params.CONFLICT_RULE); parameters.add(Params.MEEK_PREVENT_CYCLES); -// parameters.add(Params.PC_HEURISTIC); + parameters.add(Params.PC_HEURISTIC); parameters.add(Params.DEPTH); parameters.add(Params.TIME_LAG); parameters.add(Params.VERBOSE); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Pcd.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Pcd.java index f74f3d8730..91e98402dd 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Pcd.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Pcd.java @@ -8,6 +8,7 @@ import edu.cmu.tetrad.graph.Graph; import edu.cmu.tetrad.graph.GraphTransforms; import edu.cmu.tetrad.search.test.ScoreIndTest; +import edu.cmu.tetrad.search.utils.LogUtilsSearch; import edu.cmu.tetrad.search.work_in_progress.SemBicScoreDeterministic; import edu.cmu.tetrad.util.Parameters; import edu.cmu.tetrad.util.Params; @@ -53,7 +54,9 @@ public Graph search(DataModel dataSet, Parameters parameters) { search.setDepth(parameters.getInt(Params.DEPTH)); search.setKnowledge(this.knowledge); search.setVerbose(parameters.getBoolean(Params.VERBOSE)); - return search.search(); + Graph search1 = search.search(); + LogUtilsSearch.stampWithBic(search1, dataSet); + return search1; } else { Pcd algorithm = new Pcd(); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/RestrictedBoss.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/RestrictedBoss.java index 50f0ca4e39..95020839a2 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/RestrictedBoss.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/RestrictedBoss.java @@ -97,6 +97,7 @@ public Graph search(DataModel dataModel, Parameters parameters) { boss.setUseBes(parameters.getBoolean(Params.USE_BES)); boss.setNumStarts(parameters.getInt(Params.NUM_STARTS)); PermutationSearch permutationSearch = new PermutationSearch(boss); + permutationSearch.setSeed(parameters.getLong(Params.SEED)); permutationSearch.setKnowledge(knowledge); permutationSearch.search(); @@ -169,6 +170,7 @@ public List getParameters() { params.add(Params.NUM_STARTS); params.add(Params.TARGETS); params.add(Params.TRIMMING_STYLE); + params.add(Params.SEED); return params; } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Sp.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Sp.java index d61d61584e..3eb33d683f 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Sp.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/cpdag/Sp.java @@ -70,7 +70,8 @@ public Graph search(DataModel dataModel, Parameters parameters) { PermutationSearch permutationSearch = new PermutationSearch(new edu.cmu.tetrad.search.Sp(score)); permutationSearch.setKnowledge(this.knowledge); Graph graph = permutationSearch.search(); - LogUtilsSearch.stampWithScores(graph, dataModel, score); + LogUtilsSearch.stampWithScore(graph, score); + LogUtilsSearch.stampWithBic(graph, dataModel); return graph; } else { Sp algorithm = new Sp(this.score); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/pag/Bfci.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/pag/Bfci.java index 53a25cc689..9fb5c2d212 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/pag/Bfci.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/pag/Bfci.java @@ -22,6 +22,7 @@ import edu.cmu.tetrad.util.Params; import edu.pitt.dbmi.algo.resampling.GeneralResamplingTest; +import java.io.Serial; import java.util.ArrayList; import java.util.List; @@ -46,6 +47,7 @@ public class Bfci implements Algorithm, UsesScoreWrapper, TakesIndependenceWrapper, HasKnowledge, ReturnsBootstrapGraphs { + @Serial private static final long serialVersionUID = 23L; private IndependenceWrapper test; private ScoreWrapper score; @@ -59,6 +61,12 @@ public Bfci() { // Used for reflection; do not delete. } + /** + * Constructs a new BFCI algorithm using the given test and score. + * + * @param test the independence test to use + * @param score the score to use + */ public Bfci(IndependenceWrapper test, ScoreWrapper score) { this.test = test; this.score = score; @@ -79,6 +87,7 @@ public Graph search(DataModel dataModel, Parameters parameters) { BFci search = new BFci(this.test.getTest(dataModel, parameters), this.score.getScore(dataModel, parameters)); + search.setSeed(parameters.getLong(Params.SEED)); search.setBossUseBes(parameters.getBoolean(Params.USE_BES)); search.setMaxPathLength(parameters.getInt(Params.MAX_PATH_LENGTH)); search.setCompleteRuleSetUsed(parameters.getBoolean(Params.COMPLETE_RULE_SET_USED)); @@ -130,6 +139,7 @@ public List getParameters() { params.add(Params.DO_DISCRIMINATING_PATH_RULE); params.add(Params.DEPTH); params.add(Params.TIME_LAG); + params.add(Params.SEED); params.add(Params.VERBOSE); // Parameters diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/pag/Ccd.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/pag/Ccd.java index 9accc6e7e6..5fec0b6156 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/pag/Ccd.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/pag/Ccd.java @@ -15,6 +15,7 @@ import edu.cmu.tetrad.util.Params; import edu.pitt.dbmi.algo.resampling.GeneralResamplingTest; +import java.io.Serial; import java.util.ArrayList; import java.util.List; @@ -29,8 +30,8 @@ algoType = AlgType.forbid_latent_common_causes ) @Bootstrapping -//@Experimental public class Ccd implements Algorithm, TakesIndependenceWrapper, ReturnsBootstrapGraphs { + @Serial private static final long serialVersionUID = 23L; private IndependenceWrapper test; private List bootstrapGraphs = new ArrayList<>(); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/pag/Fci.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/pag/Fci.java index 752d387009..85390ea95c 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/pag/Fci.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/pag/Fci.java @@ -14,11 +14,13 @@ import edu.cmu.tetrad.graph.EdgeListGraph; import edu.cmu.tetrad.graph.Graph; import edu.cmu.tetrad.graph.GraphTransforms; +import edu.cmu.tetrad.search.utils.PcCommon; import edu.cmu.tetrad.search.utils.TsUtils; import edu.cmu.tetrad.util.Parameters; import edu.cmu.tetrad.util.Params; import edu.pitt.dbmi.algo.resampling.GeneralResamplingTest; +import java.io.Serial; import java.util.ArrayList; import java.util.List; @@ -36,6 +38,7 @@ public class Fci implements Algorithm, HasKnowledge, TakesIndependenceWrapper, ReturnsBootstrapGraphs { + @Serial private static final long serialVersionUID = 23L; private IndependenceWrapper test; private Knowledge knowledge = new Knowledge(); @@ -62,24 +65,14 @@ public Graph search(DataModel dataModel, Parameters parameters) { knowledge = timeSeries.getKnowledge(); } -// PcCommon.PcHeuristicType pcHeuristicType; -// -// switch (parameters.getInt(Params.PC_HEURISTIC)) { -// case 0: -// pcHeuristicType = PcCommon.PcHeuristicType.NONE; -// break; -// case 1: -// pcHeuristicType = PcCommon.PcHeuristicType.HEURISTIC_1; -// break; -// case 2: -// pcHeuristicType = PcCommon.PcHeuristicType.HEURISTIC_2; -// break; -// case 3: -// pcHeuristicType = PcCommon.PcHeuristicType.HEURISTIC_3; -// break; -// default: -// throw new IllegalArgumentException("Unknown conflict rule: " + parameters.getInt(Params.CONFLICT_RULE)); -// } + PcCommon.PcHeuristicType pcHeuristicType = switch (parameters.getInt(Params.PC_HEURISTIC)) { + case 0 -> PcCommon.PcHeuristicType.NONE; + case 1 -> PcCommon.PcHeuristicType.HEURISTIC_1; + case 2 -> PcCommon.PcHeuristicType.HEURISTIC_2; + case 3 -> PcCommon.PcHeuristicType.HEURISTIC_3; + default -> + throw new IllegalArgumentException("Unknown conflict rule: " + parameters.getInt(Params.CONFLICT_RULE)); + }; edu.cmu.tetrad.search.Fci search = new edu.cmu.tetrad.search.Fci(this.test.getTest(dataModel, parameters)); search.setDepth(parameters.getInt(Params.DEPTH)); @@ -89,7 +82,7 @@ public Graph search(DataModel dataModel, Parameters parameters) { search.setPossibleMsepSearchDone(parameters.getBoolean(Params.POSSIBLE_MSEP_DONE)); search.setDoDiscriminatingPathRule(parameters.getBoolean(Params.DO_DISCRIMINATING_PATH_RULE)); search.setVerbose(parameters.getBoolean(Params.VERBOSE)); -// search.setPcHeuristicType(pcHeuristicType); + search.setPcHeuristicType(pcHeuristicType); search.setStable(parameters.getBoolean(Params.STABLE_FAS)); return search.search(); @@ -128,6 +121,7 @@ public List getParameters() { List parameters = new ArrayList<>(); parameters.add(Params.DEPTH); parameters.add(Params.STABLE_FAS); + parameters.add(Params.PC_HEURISTIC); parameters.add(Params.MAX_PATH_LENGTH); parameters.add(Params.POSSIBLE_MSEP_DONE); parameters.add(Params.DO_DISCRIMINATING_PATH_RULE); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/pag/FciMax.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/pag/FciMax.java index 4eb8e3c8f0..48a0147fd9 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/pag/FciMax.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/pag/FciMax.java @@ -14,11 +14,13 @@ import edu.cmu.tetrad.graph.EdgeListGraph; import edu.cmu.tetrad.graph.Graph; import edu.cmu.tetrad.graph.GraphTransforms; +import edu.cmu.tetrad.search.utils.PcCommon; import edu.cmu.tetrad.search.utils.TsUtils; import edu.cmu.tetrad.util.Parameters; import edu.cmu.tetrad.util.Params; import edu.pitt.dbmi.algo.resampling.GeneralResamplingTest; +import java.io.Serial; import java.util.ArrayList; import java.util.List; @@ -36,6 +38,7 @@ public class FciMax implements Algorithm, HasKnowledge, TakesIndependenceWrapper, ReturnsBootstrapGraphs { + @Serial private static final long serialVersionUID = 23L; private IndependenceWrapper test; private Knowledge knowledge = new Knowledge(); @@ -61,24 +64,14 @@ public Graph search(DataModel dataModel, Parameters parameters) { knowledge = timeSeries.getKnowledge(); } -// PcCommon.PcHeuristicType pcHeuristicType; -// -// switch (parameters.getInt(Params.PC_HEURISTIC)) { -// case 0: -// pcHeuristicType = PcCommon.PcHeuristicType.NONE; -// break; -// case 1: -// pcHeuristicType = PcCommon.PcHeuristicType.HEURISTIC_1; -// break; -// case 2: -// pcHeuristicType = PcCommon.PcHeuristicType.HEURISTIC_2; -// break; -// case 3: -// pcHeuristicType = PcCommon.PcHeuristicType.HEURISTIC_3; -// break; -// default: -// throw new IllegalArgumentException("Unknown conflict rule: " + parameters.getInt(Params.CONFLICT_RULE)); -// } + PcCommon.PcHeuristicType pcHeuristicType = switch (parameters.getInt(Params.PC_HEURISTIC)) { + case 0 -> PcCommon.PcHeuristicType.NONE; + case 1 -> PcCommon.PcHeuristicType.HEURISTIC_1; + case 2 -> PcCommon.PcHeuristicType.HEURISTIC_2; + case 3 -> PcCommon.PcHeuristicType.HEURISTIC_3; + default -> + throw new IllegalArgumentException("Unknown conflict rule: " + parameters.getInt(Params.CONFLICT_RULE)); + }; edu.cmu.tetrad.search.FciMax search = new edu.cmu.tetrad.search.FciMax(this.test.getTest(dataModel, parameters)); search.setDepth(parameters.getInt(Params.DEPTH)); @@ -87,7 +80,7 @@ public Graph search(DataModel dataModel, Parameters parameters) { search.setCompleteRuleSetUsed(parameters.getBoolean(Params.COMPLETE_RULE_SET_USED)); search.setDoDiscriminatingPathRule(parameters.getBoolean(Params.DO_DISCRIMINATING_PATH_RULE)); search.setPossibleMsepSearchDone(parameters.getBoolean(Params.POSSIBLE_MSEP_DONE)); -// search.setPcHeuristicType(pcHeuristicType); + search.setPcHeuristicType(pcHeuristicType); search.setVerbose(parameters.getBoolean(Params.VERBOSE)); return search.search(); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/pag/Gfci.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/pag/Gfci.java index c4404a117c..8c04f9d55b 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/pag/Gfci.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/pag/Gfci.java @@ -22,6 +22,7 @@ import edu.pitt.dbmi.algo.resampling.GeneralResamplingTest; import java.io.PrintStream; +import java.io.Serial; import java.util.ArrayList; import java.util.List; @@ -40,6 +41,7 @@ public class Gfci implements Algorithm, HasKnowledge, UsesScoreWrapper, TakesIndependenceWrapper, ReturnsBootstrapGraphs { + @Serial private static final long serialVersionUID = 23L; private IndependenceWrapper test; private ScoreWrapper score; @@ -138,7 +140,7 @@ public Knowledge getKnowledge() { @Override public void setKnowledge(Knowledge knowledge) { - this.knowledge = new Knowledge((Knowledge) knowledge); + this.knowledge = new Knowledge(knowledge); } @Override diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/pag/GraspFci.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/pag/GraspFci.java index 1475820bbb..874b2ba97d 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/pag/GraspFci.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/pag/GraspFci.java @@ -81,6 +81,7 @@ public Graph search(DataModel dataModel, Parameters parameters) { edu.cmu.tetrad.search.GraspFci search = new edu.cmu.tetrad.search.GraspFci(test, score); // GRaSP + search.setSeed(parameters.getLong(Params.SEED)); search.setDepth(parameters.getInt(Params.GRASP_DEPTH)); search.setSingularDepth(parameters.getInt(Params.GRASP_SINGULAR_DEPTH)); search.setNonSingularDepth(parameters.getInt(Params.GRASP_NONSINGULAR_DEPTH)); @@ -154,6 +155,9 @@ public List getParameters() { // General params.add(Params.TIME_LAG); + + params.add(Params.SEED); + params.add(Params.VERBOSE); return params; diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/pag/SvarFci.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/pag/SvarFci.java index 40c66a4e1b..792c776ad1 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/pag/SvarFci.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/algorithm/oracle/pag/SvarFci.java @@ -20,6 +20,7 @@ import edu.cmu.tetrad.util.Params; import edu.pitt.dbmi.algo.resampling.GeneralResamplingTest; +import java.io.Serial; import java.util.ArrayList; import java.util.List; @@ -39,6 +40,7 @@ public class SvarFci implements Algorithm, HasKnowledge, TakesIndependenceWrapper, ReturnsBootstrapGraphs { + @Serial private static final long serialVersionUID = 23L; private IndependenceWrapper test; private Knowledge knowledge; @@ -117,7 +119,7 @@ public Knowledge getKnowledge() { @Override public void setKnowledge(Knowledge knowledge) { - this.knowledge = new Knowledge((Knowledge) knowledge); + this.knowledge = new Knowledge(knowledge); } @Override diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/examples/TestBoss.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/examples/TestBoss.java index 526ba12154..238428f396 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/examples/TestBoss.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/examples/TestBoss.java @@ -31,8 +31,12 @@ import edu.cmu.tetrad.algcomparison.simulation.SemSimulation; import edu.cmu.tetrad.algcomparison.simulation.Simulations; import edu.cmu.tetrad.algcomparison.statistic.*; +import edu.cmu.tetrad.util.MillisecondTimes; import edu.cmu.tetrad.util.Parameters; import edu.cmu.tetrad.util.Params; +import org.apache.commons.math3.linear.Array2DRowRealMatrix; +import org.apache.commons.math3.linear.BlockRealMatrix; +import org.apache.commons.math3.linear.RealMatrix; /** * Test the degenerate Gaussian score. @@ -41,6 +45,11 @@ */ public class TestBoss { public static void main(String... args) { + if (true) { + testGigaflops(); + return; + } + Parameters parameters = new Parameters(); parameters.set(Params.NUM_RUNS, 1); parameters.set(Params.DIFFERENT_GRAPHS, true); @@ -94,6 +103,32 @@ public static void main(String... args) { comparison.compareFromSimulations("comparison", simulations, algorithms, statistics, parameters); } + + public static void testGigaflops() { + + final long start = MillisecondTimes.timeMillis();// System.currentTimeMillis(); + + for (int i = 0; i < 200; i++) { + int N = 1024; + RealMatrix A = new BlockRealMatrix(N, N); + RealMatrix B = new BlockRealMatrix(N, N); + + MillisecondTimes.type = MillisecondTimes.Type.CPU; + + RealMatrix C = A.multiply(B); + final long end = MillisecondTimes.timeMillis();// System.currentTimeMillis(); + + double gflop = N * N * N * 2e-9; + double sec = (end - start) * 1e-3; + + System.out.println(gflop / sec); + } + + final long end = MillisecondTimes.timeMillis();// System.currentTimeMillis(); + + System.out.println((end - start) * 1e-3); + + } } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/independence/ChiSquare.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/independence/ChiSquare.java index d78c8c1147..aa1a7d771a 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/independence/ChiSquare.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/independence/ChiSquare.java @@ -28,7 +28,9 @@ public class ChiSquare implements IndependenceWrapper { @Override public IndependenceTest getTest(DataModel dataSet, Parameters parameters) { - return new IndTestChiSquare(SimpleDataLoader.getDiscreteDataSet(dataSet), parameters.getDouble("alpha")); + IndTestChiSquare test = new IndTestChiSquare(SimpleDataLoader.getDiscreteDataSet(dataSet), parameters.getDouble(Params.ALPHA)); + test.setMinCountPerCell(parameters.getDouble(Params.MIN_COUNT_PER_CELL)); + return test; } @Override @@ -45,7 +47,7 @@ public DataType getDataType() { public List getParameters() { List params = new ArrayList<>(); params.add(Params.ALPHA); + params.add(Params.MIN_COUNT_PER_CELL); return params; } - } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/independence/FisherZ.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/independence/FisherZ.java index 48c0ab7fc3..ac07b8ccf0 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/independence/FisherZ.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/independence/FisherZ.java @@ -11,6 +11,7 @@ import edu.cmu.tetrad.util.Parameters; import edu.cmu.tetrad.util.Params; +import java.io.Serial; import java.util.ArrayList; import java.util.List; @@ -27,19 +28,25 @@ @LinearGaussian public class FisherZ implements IndependenceWrapper { + @Serial private static final long serialVersionUID = 23L; @Override - public IndependenceTest getTest(DataModel dataSet, Parameters parameters) { + public IndependenceTest getTest(DataModel dataModel, Parameters parameters) { double alpha = parameters.getDouble(Params.ALPHA); - if (dataSet instanceof ICovarianceMatrix) { - return new IndTestFisherZ((ICovarianceMatrix) dataSet, alpha); - } else if (dataSet instanceof DataSet) { - return new IndTestFisherZ((DataSet) dataSet, alpha); + IndTestFisherZ test; + + if (dataModel instanceof ICovarianceMatrix) { + test = new IndTestFisherZ((ICovarianceMatrix) dataModel, alpha); + } else if (dataModel instanceof DataSet) { + test = new IndTestFisherZ((DataSet) dataModel, alpha); + } else { + throw new IllegalArgumentException("Expecting either a dataset or a covariance matrix."); } - throw new IllegalArgumentException("Expecting eithet a data set or a covariance matrix."); + test.setUsePseudoinverse(parameters.getBoolean(Params.USE_PSEUDOINVERSE)); + return test; } @Override @@ -56,6 +63,7 @@ public DataType getDataType() { public List getParameters() { List params = new ArrayList<>(); params.add(Params.ALPHA); + params.add(Params.USE_PSEUDOINVERSE); return params; } } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/independence/GICScoreTests.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/independence/GICScoreTests.java index bd02f7529f..419c15561c 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/independence/GICScoreTests.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/independence/GICScoreTests.java @@ -12,6 +12,7 @@ import edu.cmu.tetrad.util.Parameters; import edu.cmu.tetrad.util.Params; +import java.io.Serial; import java.util.ArrayList; import java.util.List; @@ -28,6 +29,7 @@ @LinearGaussian public class GICScoreTests implements IndependenceWrapper { + @Serial private static final long serialVersionUID = 23L; @Override @@ -71,7 +73,7 @@ public IndependenceTest getTest(DataModel dataSet, Parameters parameters) { score.setRuleType(ruleType); score.setPenaltyDiscount(parameters.getDouble(Params.PENALTY_DISCOUNT)); - + score.setUsePseudoInverse(parameters.getBoolean(Params.USE_PSEUDOINVERSE)); return new ScoreIndTest(score, dataSet); } @@ -92,6 +94,7 @@ public List getParameters() { params.add(Params.SEM_GIC_RULE); params.add(Params.PENALTY_DISCOUNT_ZS); params.add(Params.PRECOMPUTE_COVARIANCES); + params.add(Params.USE_PSEUDOINVERSE); return params; } } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/independence/Gsquare.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/independence/GSquare.java similarity index 75% rename from tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/independence/Gsquare.java rename to tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/independence/GSquare.java index e1574d1c92..f7673b15a2 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/independence/Gsquare.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/independence/GSquare.java @@ -9,6 +9,7 @@ import edu.cmu.tetrad.util.Parameters; import edu.cmu.tetrad.util.Params; +import java.io.Serial; import java.util.ArrayList; import java.util.List; @@ -22,13 +23,16 @@ command = "g-square-test", dataType = DataType.Discrete ) -public class Gsquare implements IndependenceWrapper { +public class GSquare implements IndependenceWrapper { + @Serial private static final long serialVersionUID = 23L; @Override public IndependenceTest getTest(DataModel dataSet, Parameters parameters) { - return new IndTestGSquare(SimpleDataLoader.getDiscreteDataSet(dataSet), parameters.getDouble("alpha")); + IndTestGSquare test = new IndTestGSquare(SimpleDataLoader.getDiscreteDataSet(dataSet), parameters.getDouble("test")); + test.setMinCountPerCell(parameters.getDouble(Params.MIN_COUNT_PER_CELL)); + return test; } @Override @@ -45,6 +49,7 @@ public DataType getDataType() { public List getParameters() { List params = new ArrayList<>(); params.add(Params.ALPHA); + params.add(Params.MIN_COUNT_PER_CELL); return params; } } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/independence/Kci.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/independence/Kci.java index 82436d94b0..ab2646b278 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/independence/Kci.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/independence/Kci.java @@ -9,13 +9,12 @@ import edu.cmu.tetrad.util.Parameters; import edu.cmu.tetrad.util.Params; +import java.io.Serial; import java.util.ArrayList; import java.util.List; /** * Wrapper for KCI test. - *

- * Note that should work with Linear, Gaussian variables but is general. * * @author josephramsey */ @@ -27,14 +26,21 @@ @General public class Kci implements IndependenceWrapper { + @Serial private static final long serialVersionUID = 23L; - + /** + * Returns a KCI test. + * + * @param dataSet The data set to test independence against. + * @param parameters The paramters of the test. + * @return A KCI test. + */ @Override public IndependenceTest getTest(DataModel dataSet, Parameters parameters) { edu.cmu.tetrad.search.test.Kci kci = new edu.cmu.tetrad.search.test.Kci(SimpleDataLoader.getContinuousDataSet(dataSet), parameters.getDouble(Params.ALPHA)); - kci.setApproximate(parameters.getBoolean(Params.KCI_USE_APPROMATION)); + kci.setApproximate(parameters.getBoolean(Params.KCI_USE_APPROXIMATION)); kci.setWidthMultiplier(parameters.getDouble(Params.KERNEL_MULTIPLIER)); kci.setNumBootstraps(parameters.getInt(Params.KCI_NUM_BOOTSTRAPS)); kci.setThreshold(parameters.getDouble(Params.THRESHOLD_FOR_NUM_EIGENVALUES)); @@ -42,20 +48,36 @@ public IndependenceTest getTest(DataModel dataSet, Parameters parameters) { return kci; } + /** + * Returns the name of the test. + * + * @return The name of the test. + */ @Override public String getDescription() { return "KCI"; } + /** + * Returns the data type of the test, which is continuous. + * + * @return The data type of the test, which is continuous. + * @see DataType + */ @Override public DataType getDataType() { return DataType.Continuous; } + /** + * Returns the parameters of the test. + * + * @return The parameters of the test. + */ @Override public List getParameters() { List params = new ArrayList<>(); - params.add(Params.KCI_USE_APPROMATION); + params.add(Params.KCI_USE_APPROXIMATION); params.add(Params.ALPHA); params.add(Params.KERNEL_MULTIPLIER); params.add(Params.KCI_NUM_BOOTSTRAPS); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/independence/PoissonScoreTest.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/independence/PoissonScoreTest.java index 7133f58047..011e9ac1c4 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/independence/PoissonScoreTest.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/independence/PoissonScoreTest.java @@ -12,6 +12,7 @@ import edu.cmu.tetrad.util.Parameters; import edu.cmu.tetrad.util.Params; +import java.io.Serial; import java.util.ArrayList; import java.util.List; @@ -28,6 +29,7 @@ @LinearGaussian public class PoissonScoreTest implements IndependenceWrapper { + @Serial private static final long serialVersionUID = 23L; @Override @@ -39,7 +41,9 @@ public IndependenceTest getTest(DataModel dataSet, Parameters parameters) { } else { score = new PoissonPriorScore((DataSet) dataSet, true); } + score.setLambda(parameters.getDouble(Params.POISSON_LAMBDA)); + score.setUsePseudoInverse(parameters.getBoolean(Params.USE_PSEUDOINVERSE)); return new ScoreIndTest(score, dataSet); } @@ -58,6 +62,7 @@ public DataType getDataType() { public List getParameters() { List params = new ArrayList<>(); params.add(Params.POISSON_LAMBDA); + params.add(Params.USE_PSEUDOINVERSE); return params; } } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/independence/SemBicTest.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/independence/SemBicTest.java index 1bd5bd099f..890d77e66f 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/independence/SemBicTest.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/independence/SemBicTest.java @@ -12,6 +12,7 @@ import edu.cmu.tetrad.util.Parameters; import edu.cmu.tetrad.util.Params; +import java.io.Serial; import java.util.ArrayList; import java.util.List; @@ -28,6 +29,7 @@ @LinearGaussian public class SemBicTest implements IndependenceWrapper { + @Serial private static final long serialVersionUID = 23L; @Override @@ -43,6 +45,7 @@ public IndependenceTest getTest(DataModel dataSet, Parameters parameters) { } score.setPenaltyDiscount(parameters.getDouble(Params.PENALTY_DISCOUNT)); score.setStructurePrior(parameters.getDouble(Params.STRUCTURE_PRIOR)); + score.setUsePseudoInverse(parameters.getBoolean(Params.USE_PSEUDOINVERSE)); return new ScoreIndTest(score, dataSet); } @@ -63,6 +66,7 @@ public List getParameters() { params.add(Params.PENALTY_DISCOUNT); params.add(Params.STRUCTURE_PRIOR); params.add(Params.PRECOMPUTE_COVARIANCES); + params.add(Params.USE_PSEUDOINVERSE); return params; } } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/score/EbicScore.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/score/EbicScore.java index 3b9e10c94f..83061b8dd8 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/score/EbicScore.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/score/EbicScore.java @@ -10,6 +10,7 @@ import edu.cmu.tetrad.util.Parameters; import edu.cmu.tetrad.util.Params; +import java.io.Serial; import java.util.ArrayList; import java.util.List; @@ -26,6 +27,7 @@ @LinearGaussian public class EbicScore implements ScoreWrapper { + @Serial private static final long serialVersionUID = 23L; private DataModel dataSet; @@ -44,7 +46,7 @@ public Score getScore(DataModel dataSet, Parameters parameters) { } score.setGamma(parameters.getDouble(Params.EBIC_GAMMA)); -// score.setCorrelationThreshold(parameters.getDouble(Params.CORRELATION_THRESHOLD)); + score.setUsePseudoInverse(parameters.getBoolean(Params.USE_PSEUDOINVERSE)); return score; } @@ -62,8 +64,8 @@ public DataType getDataType() { public List getParameters() { List parameters = new ArrayList<>(); parameters.add(Params.EBIC_GAMMA); -// parameters.add(Params.CORRELATION_THRESHOLD); parameters.add(Params.PRECOMPUTE_COVARIANCES); + parameters.add(Params.USE_PSEUDOINVERSE); return parameters; } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/score/GicScores.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/score/GicScores.java index aa169a1ad9..997bf06e53 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/score/GicScores.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/score/GicScores.java @@ -10,6 +10,7 @@ import edu.cmu.tetrad.util.Parameters; import edu.cmu.tetrad.util.Params; +import java.io.Serial; import java.util.ArrayList; import java.util.List; @@ -19,13 +20,14 @@ * @author josephramsey */ @edu.cmu.tetrad.annotation.Score( - name = "Generalied Information Criterion Scores", + name = "Generalized Information Criterion Scores", command = "gic-scores", dataType = {DataType.Continuous, DataType.Covariance} ) @LinearGaussian public class GicScores implements ScoreWrapper { + @Serial private static final long serialVersionUID = 23L; private DataModel dataSet; @@ -45,33 +47,19 @@ public Score getScore(DataModel dataSet, Parameters parameters) { } int anInt = parameters.getInt((Params.SEM_GIC_RULE)); - edu.cmu.tetrad.search.score.GicScores.RuleType ruleType; - - switch (anInt) { - case 1: - ruleType = edu.cmu.tetrad.search.score.GicScores.RuleType.BIC; - break; - case 2: - ruleType = edu.cmu.tetrad.search.score.GicScores.RuleType.GIC2; - break; - case 3: - ruleType = edu.cmu.tetrad.search.score.GicScores.RuleType.RIC; - break; - case 4: - ruleType = edu.cmu.tetrad.search.score.GicScores.RuleType.RICc; - break; - case 5: - ruleType = edu.cmu.tetrad.search.score.GicScores.RuleType.GIC5; - break; - case 6: - ruleType = edu.cmu.tetrad.search.score.GicScores.RuleType.GIC6; - break; - default: - throw new IllegalArgumentException("Unrecognized rule type: " + anInt); - } + edu.cmu.tetrad.search.score.GicScores.RuleType ruleType = switch (anInt) { + case 1 -> edu.cmu.tetrad.search.score.GicScores.RuleType.BIC; + case 2 -> edu.cmu.tetrad.search.score.GicScores.RuleType.GIC2; + case 3 -> edu.cmu.tetrad.search.score.GicScores.RuleType.RIC; + case 4 -> edu.cmu.tetrad.search.score.GicScores.RuleType.RICc; + case 5 -> edu.cmu.tetrad.search.score.GicScores.RuleType.GIC5; + case 6 -> edu.cmu.tetrad.search.score.GicScores.RuleType.GIC6; + default -> throw new IllegalArgumentException("Unrecognized rule type: " + anInt); + }; score.setRuleType(ruleType); score.setPenaltyDiscount(parameters.getDouble(Params.PENALTY_DISCOUNT)); + score.setUsePseudoInverse(parameters.getBoolean(Params.USE_PSEUDOINVERSE)); return score; } @@ -92,6 +80,8 @@ public List getParameters() { parameters.add(Params.SEM_GIC_RULE); parameters.add(Params.PENALTY_DISCOUNT_ZS); parameters.add(Params.PRECOMPUTE_COVARIANCES); + parameters.add(Params.USE_PSEUDOINVERSE); + return parameters; } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/score/PoissonPriorScore.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/score/PoissonPriorScore.java index 124039dd0c..889419e0c3 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/score/PoissonPriorScore.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/score/PoissonPriorScore.java @@ -44,6 +44,7 @@ public Score getScore(DataModel dataSet, Parameters parameters) { } score.setLambda(parameters.getDouble(Params.POISSON_LAMBDA)); + score.setUsePseudoInverse(parameters.getBoolean(Params.USE_PSEUDOINVERSE)); return score; } @@ -63,6 +64,7 @@ public List getParameters() { List parameters = new ArrayList<>(); parameters.add(Params.PRECOMPUTE_COVARIANCES); parameters.add(Params.POISSON_LAMBDA); + parameters.add(Params.USE_PSEUDOINVERSE); return parameters; } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/score/ScoreWrapper.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/score/ScoreWrapper.java index 686dad09ea..ef145249b4 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/score/ScoreWrapper.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/score/ScoreWrapper.java @@ -50,7 +50,9 @@ public interface ScoreWrapper extends HasParameters, TetradSerializable { /** * Returns the variable with the given name. + * * @param name the name. + * @return the variable. */ Node getVariable(String name); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/score/SemBicScore.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/score/SemBicScore.java index be60ded960..ab6d0c6bab 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/score/SemBicScore.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/score/SemBicScore.java @@ -10,6 +10,7 @@ import edu.cmu.tetrad.util.Parameters; import edu.cmu.tetrad.util.Params; +import java.io.Serial; import java.util.ArrayList; import java.util.List; @@ -26,6 +27,7 @@ @LinearGaussian public class SemBicScore implements ScoreWrapper { + @Serial private static final long serialVersionUID = 23L; private DataModel dataSet; @@ -46,6 +48,7 @@ public Score getScore(DataModel dataSet, Parameters parameters) { semBicScore.setPenaltyDiscount(parameters.getDouble(Params.PENALTY_DISCOUNT)); semBicScore.setStructurePrior(parameters.getDouble(Params.SEM_BIC_STRUCTURE_PRIOR)); + semBicScore.setUsePseudoInverse(parameters.getBoolean(Params.USE_PSEUDOINVERSE)); switch (parameters.getInt(Params.SEM_BIC_RULE)) { case 1: @@ -78,6 +81,7 @@ public List getParameters() { parameters.add(Params.SEM_BIC_STRUCTURE_PRIOR); parameters.add(Params.SEM_BIC_RULE); parameters.add(Params.PRECOMPUTE_COVARIANCES); + parameters.add(Params.USE_PSEUDOINVERSE); return parameters; } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/score/ZhangShenBoundScore.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/score/ZhangShenBoundScore.java index 9f6649fa03..dd6f85baf6 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/score/ZhangShenBoundScore.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/score/ZhangShenBoundScore.java @@ -11,6 +11,7 @@ import edu.cmu.tetrad.util.Parameters; import edu.cmu.tetrad.util.Params; +import java.io.Serial; import java.util.ArrayList; import java.util.List; @@ -27,6 +28,7 @@ @LinearGaussian public class ZhangShenBoundScore implements ScoreWrapper { + @Serial private static final long serialVersionUID = 23L; private DataModel dataSet; @@ -47,6 +49,7 @@ public Score getScore(DataModel dataSet, Parameters parameters) { } score.setRiskBound(parameters.getDouble(Params.ZS_RISK_BOUND)); + score.setUsePseudoInverse(parameters.getBoolean(Params.USE_PSEUDOINVERSE)); return score; } @@ -66,6 +69,7 @@ public List getParameters() { List parameters = new ArrayList<>(); parameters.add(Params.ZS_RISK_BOUND); parameters.add(Params.PRECOMPUTE_COVARIANCES); + parameters.add(Params.USE_PSEUDOINVERSE); return parameters; } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/BayesNetSimulation.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/BayesNetSimulation.java index 8347eceea0..6116af41a6 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/BayesNetSimulation.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/BayesNetSimulation.java @@ -84,8 +84,6 @@ public void createData(Parameters parameters, boolean newModel) { this.ims = new ArrayList<>(); for (int i = 0; i < parameters.getInt(Params.NUM_RUNS); i++) { - System.out.println("Simulating dataset #" + (i + 1)); - if (parameters.getBoolean(Params.DIFFERENT_GRAPHS) && i > 0) { graph = this.randomGraph.createGraph(parameters); } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/ConditionalGaussianSimulation.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/ConditionalGaussianSimulation.java index 6f1ec1107d..d06b36e6eb 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/ConditionalGaussianSimulation.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/ConditionalGaussianSimulation.java @@ -108,8 +108,6 @@ public void createData(Parameters parameters, boolean newModel) { this.graphs = new ArrayList<>(); for (int i = 0; i < parameters.getInt(Params.NUM_RUNS); i++) { - System.out.println("Simulating dataset #" + (i + 1)); - if (parameters.getBoolean(Params.DIFFERENT_GRAPHS) && i > 0) { graph = this.randomGraph.createGraph(parameters); } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/GeneralSemSimulation.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/GeneralSemSimulation.java index c33bd2d0ff..dc1b8a97cc 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/GeneralSemSimulation.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/GeneralSemSimulation.java @@ -66,8 +66,6 @@ public void createData(Parameters parameters, boolean newModel) { this.ims = new ArrayList<>(); for (int i = 0; i < parameters.getInt(Params.NUM_RUNS); i++) { - System.out.println("Simulating dataset #" + (i + 1)); - if (parameters.getBoolean(Params.DIFFERENT_GRAPHS) && i > 0) { graph = this.randomGraph.createGraph(parameters); } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/GeneralSemSimulationSpecial1.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/GeneralSemSimulationSpecial1.java index b2801cc127..5ba3bf423a 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/GeneralSemSimulationSpecial1.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/GeneralSemSimulationSpecial1.java @@ -44,8 +44,6 @@ public void createData(Parameters parameters, boolean newModel) { this.graphs = new ArrayList<>(); for (int i = 0; i < parameters.getInt(Params.NUM_RUNS); i++) { - System.out.println("Simulating dataset #" + (i + 1)); - if (parameters.getBoolean(Params.DIFFERENT_GRAPHS) && i > 0) { graph = this.randomGraph.createGraph(parameters); } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/LeeHastieSimulation.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/LeeHastieSimulation.java index d20aaf89c1..08f43f7b43 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/LeeHastieSimulation.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/LeeHastieSimulation.java @@ -65,8 +65,6 @@ public void createData(Parameters parameters, boolean newModel) { this.graphs = new ArrayList<>(); for (int i = 0; i < parameters.getInt(Params.NUM_RUNS); i++) { - System.out.println("Simulating dataset #" + (i + 1)); - if (parameters.getBoolean(Params.DIFFERENT_GRAPHS) && i > 0) { graph = this.randomGraph.createGraph(parameters); } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/LinearFisherModel.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/LinearFisherModel.java index f896c17611..a750843f97 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/LinearFisherModel.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/LinearFisherModel.java @@ -70,8 +70,6 @@ public void createData(Parameters parameters, boolean newModel) { System.out.println("degree = " + GraphUtils.getDegree(graph)); for (int i = 0; i < parameters.getInt(Params.NUM_RUNS); i++) { - System.out.println("Simulating dataset #" + (i + 1)); - if (this.shocks != null && this.shocks.size() > 0) { parameters.set(Params.NUM_MEASURES, this.shocks.get(0).getVariables().size()); } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/LinearSineSimulation.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/LinearSineSimulation.java index b0cf5836d8..38473e0238 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/LinearSineSimulation.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/LinearSineSimulation.java @@ -96,8 +96,6 @@ public void createData(Parameters parameters, boolean newModel) { this.graphs = new ArrayList<>(); for (int i = 0; i < parameters.getInt(Params.NUM_RUNS); i++) { - System.out.println("Simulating dataset #" + (i + 1)); - if (parameters.getBoolean(Params.DIFFERENT_GRAPHS) && i > 0) graph = this.randomGraph.createGraph(parameters); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/NLSemSimulation.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/NLSemSimulation.java index ae8e1a97f8..e9e945aeff 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/NLSemSimulation.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/NLSemSimulation.java @@ -53,8 +53,6 @@ public void createData(Parameters parameters, boolean newModel) { int numVars = parameters.getInt(Params.NUM_MEASURES); for (int i = 0; i < parameters.getInt(Params.NUM_RUNS); i++) { - System.out.println("Simulating dataset #" + (i + 1)); - if (parameters.getBoolean(Params.DIFFERENT_GRAPHS) && i > 0) { graph = this.randomGraph.createGraph(parameters); } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/SemSimulation.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/SemSimulation.java index 989dfd72f0..e782f6d1b7 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/SemSimulation.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/SemSimulation.java @@ -67,8 +67,6 @@ public void createData(Parameters parameters, boolean newModel) { this.ims = new ArrayList<>(); for (int i = 0; i < parameters.getInt(Params.NUM_RUNS); i++) { - System.out.println("Simulating dataset #" + (i + 1)); - if (parameters.getBoolean(Params.DIFFERENT_GRAPHS) && i > 0) { graph = this.randomGraph.createGraph(parameters); } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/SemThenDiscretize.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/SemThenDiscretize.java index e2bf648fbe..6f8a74aed8 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/SemThenDiscretize.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/SemThenDiscretize.java @@ -65,8 +65,6 @@ public void createData(Parameters parameters, boolean newModel) { this.graphs = new ArrayList<>(); for (int i = 0; i < parameters.getInt(Params.NUM_RUNS); i++) { - System.out.println("Simulating dataset #" + (i + 1)); - if (parameters.getBoolean(Params.DIFFERENT_GRAPHS) && i > 0) { graph = this.randomGraph.createGraph(parameters); } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/SimulationTypes.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/SimulationTypes.java index 7c84ecb1fb..87391af9a4 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/SimulationTypes.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/SimulationTypes.java @@ -25,12 +25,12 @@ */ public final class SimulationTypes { - public static final String BAYS_NET = "Bayes Net"; - public static final String STRUCTURAL_EQUATION_MODEL = "Structural Equation Model"; - public static final String NON_LINEAR_STRUCTURAL_EQUATION_MODEL = "Non-Linear Structural Equation Model"; + public static final String BAYS_NET = "Bayes Net (Multinomial)"; + public static final String STRUCTURAL_EQUATION_MODEL = "Linear Structural Equation Model"; public static final String LINEAR_FISHER_MODEL = "Linear Fisher Model"; - public static final String LEE_AND_HASTIE = "Lee & Hastie"; - public static final String CONDITIONAL_GAUSSIAN = "Conditional Gaussian"; + public static final String NON_LINEAR_STRUCTURAL_EQUATION_MODEL = "Non-Linear Structural Equation Model"; + public static final String LEE_AND_HASTIE = "Mixed Lee & Hastie"; + public static final String CONDITIONAL_GAUSSIAN = "Mixed Conditional Gaussian"; public static final String TIME_SERIES = "Time Series"; public static final String STANDARDIZED_STRUCTURAL_EQUATION_MODEL = "Standardized Structural Equation Model"; public static final String GENERAL_STRUCTURAL_EQUATION_MODEL = "General Structural Equation Model"; diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/StandardizedSemSimulation.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/StandardizedSemSimulation.java index dcf2f7f114..cf4ecbed1a 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/StandardizedSemSimulation.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/simulation/StandardizedSemSimulation.java @@ -57,8 +57,6 @@ public void createData(Parameters parameters, boolean newModel) { this.graphs = new ArrayList<>(); for (int i = 0; i < parameters.getInt("numRuns"); i++) { - System.out.println("Simulating dataset #" + (i + 1)); - if (parameters.getBoolean("differentGraphs") && i > 0) { graph = this.randomGraph.createGraph(parameters); } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/BicDiff.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/BicDiff.java index 83241bb266..64660110c4 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/BicDiff.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/BicDiff.java @@ -8,7 +8,7 @@ import static org.apache.commons.math3.util.FastMath.tanh; /** - * Difference between the true and estiamted BIC scores. + * Difference between the true and estiamted BIC scores. The BIC is calculated as 2L - k ln N, so "higher is better." * * @author josephramsey */ @@ -16,28 +16,57 @@ public class BicDiff implements Statistic { private static final long serialVersionUID = 23L; private boolean precomputeCovariances = true; + /** + * Returns the name of the statistic. + * + * @return the name of the statistic. + */ @Override public String getAbbreviation() { return "BicDiff"; } + /** + * Returns the description of the statistic. + * + * @return the description of the statistic. + */ @Override public String getDescription() { return "Difference between the true and estimated BIC scores"; } + /** + * Returns the value of the statistic. + * + * @param trueGraph The true graph (DAG, CPDAG, PAG_of_the_true_DAG). + * @param estGraph The estimated graph (same type). + * @param dataModel The data model. + * @return The value of the statistic. + */ @Override public double getValue(Graph trueGraph, Graph estGraph, DataModel dataModel) { - double _true = SemBicScorer.scoreDag(GraphTransforms.dagFromCPDAG(trueGraph, null), dataModel, precomputeCovariances); - double est = SemBicScorer.scoreDag(GraphTransforms.dagFromCPDAG(estGraph, null), dataModel, precomputeCovariances); + double _true = SemBicScorer.scoreDag(GraphTransforms.dagFromCpdag(trueGraph, null), dataModel, precomputeCovariances); + double est = SemBicScorer.scoreDag(GraphTransforms.dagFromCpdag(estGraph, null), dataModel, precomputeCovariances); return (_true - est); } + /** + * Returns the normalized value of the statistic. + * + * @param value The value of the statistic. + * @return The normalized value of the statistic. + */ @Override public double getNormValue(double value) { return tanh(value / 1e6); } + /** + * Returns the precompute covariances flag. + * + * @param precomputeCovariances The precompute covariances flag. + */ public void setPrecomputeCovariances(boolean precomputeCovariances) { this.precomputeCovariances = precomputeCovariances; } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/BicDiffPerRecord.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/BicDiffPerRecord.java index c98412966e..ca0f412a09 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/BicDiffPerRecord.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/BicDiffPerRecord.java @@ -29,20 +29,39 @@ public String getDescription() { "divided by the sample size"; } + /** + * Returns the difference between the true and estimated BIC scores, divided by the sample size. + * + * @param trueGraph The true graph (DAG, CPDAG, PAG_of_the_true_DAG). + * @param estGraph The estimated graph (same type). + * @param dataModel The data model. + * @return The difference between the true and estimated BIC scores, divided by the sample size. + */ @Override public double getValue(Graph trueGraph, Graph estGraph, DataModel dataModel) { - double _true = SemBicScorer.scoreDag(GraphTransforms.dagFromCPDAG(trueGraph, null), dataModel, precomputeCovariances); - double est = SemBicScorer.scoreDag(GraphTransforms.dagFromCPDAG(estGraph, null), dataModel, precomputeCovariances); + double _true = SemBicScorer.scoreDag(GraphTransforms.dagFromCpdag(trueGraph, null), dataModel, precomputeCovariances); + double est = SemBicScorer.scoreDag(GraphTransforms.dagFromCpdag(estGraph, null), dataModel, precomputeCovariances); if (abs(_true) < 0.0001) _true = 0.0; if (abs(est) < 0.0001) est = 0.0; return (_true - est) / ((DataSet) dataModel).getNumRows(); } + /** + * Returns the normalized value of the statistic. + * + * @param value The value of the statistic. + * @return The normalized value of the statistic. + */ @Override public double getNormValue(double value) { return tanh(value / 1e6); } + /** + * Returns true if the covariances are precomputed. + * + * @param precomputeCovariances True if the covariances are precomputed. + */ public void setPrecomputeCovariances(boolean precomputeCovariances) { this.precomputeCovariances = precomputeCovariances; } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/BicEst.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/BicEst.java index 2fc7024067..646b2d23ff 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/BicEst.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/BicEst.java @@ -1,51 +1,110 @@ package edu.cmu.tetrad.algcomparison.statistic; import edu.cmu.tetrad.data.DataModel; +import edu.cmu.tetrad.data.DataSet; import edu.cmu.tetrad.graph.Graph; import edu.cmu.tetrad.graph.GraphTransforms; +import edu.cmu.tetrad.graph.Node; +import edu.cmu.tetrad.search.score.DiscreteBicScore; import edu.cmu.tetrad.search.score.SemBicScorer; +import java.io.Serial; +import java.util.List; + import static org.apache.commons.math3.util.FastMath.tanh; /** - * Estimated BIC score. + * Estimated BIC score. The BIC is calculated as 2L - k ln N, so "higher is better." * * @author josephramsey */ public class BicEst implements Statistic { + @Serial private static final long serialVersionUID = 23L; - private double penaltyDiscount = 1.0; private boolean precomputeCovariances = true; + /** + * No-arg constructor. Used for reflection; do not delete. + */ public BicEst() { } - public BicEst(double penaltyDiscount) { - this.penaltyDiscount = penaltyDiscount; - } - + /** + * Returns the name of the statistic. + * + * @return the name of the statistic. + */ @Override public String getAbbreviation() { return "BicEst"; } + /** + * Returns the description of the statistic. + * + * @return the description of the statistic. + */ @Override public String getDescription() { return "BIC of the estimated CPDAG (depends only on the estimated DAG and the data)"; } + /** + * Returns the value of the statistic. + * + * @param trueGraph The true graph (DAG, CPDAG, PAG_of_the_true_DAG). + * @param estGraph The estimated graph (same type). + * @param dataModel The data model. + * @return The value of the statistic. + */ @Override public double getValue(Graph trueGraph, Graph estGraph, DataModel dataModel) { -// double _true = SemBicScorer.scoreDag(SearchGraphUtils.dagFromCPDAG(trueGraph), dataModel); - return SemBicScorer.scoreDag(GraphTransforms.dagFromCPDAG(estGraph, null), dataModel, precomputeCovariances); + if (dataModel.isDiscrete()) { + DiscreteBicScore score = new DiscreteBicScore((DataSet) dataModel); + + Graph dag = GraphTransforms.dagFromCpdag(estGraph, null); + List nodes = dag.getNodes(); + + double _score = 0.0; + + for (Node node : dag.getNodes()) { + score.setPenaltyDiscount(1); + int i = nodes.indexOf(node); + List parents = dag.getParents(node); + int[] parentIndices = new int[parents.size()]; + + for (Node parent : parents) { + parentIndices[parents.indexOf(parent)] = nodes.indexOf(parent); + } + + _score += score.localScore(i, parentIndices); + } + + return _score; + } else if (dataModel.isContinuous()) { + return SemBicScorer.scoreDag(GraphTransforms.dagFromCpdag(estGraph, null), dataModel, precomputeCovariances); + } else { + throw new IllegalArgumentException("Data must be either discrete or continuous"); + } } + /** + * Returns the normalized value of the statistic. + * + * @param value The value of the statistic. + * @return The normalized value of the statistic. + */ @Override public double getNormValue(double value) { return tanh(value / 1e6); } + /** + * Returns the precompute covariances flag. + * + * @param precomputeCovariances The precompute covariances flag. + */ public void setPrecomputeCovariances(boolean precomputeCovariances) { this.precomputeCovariances = precomputeCovariances; } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/BicTrue.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/BicTrue.java index c41e272e5e..2933466d06 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/BicTrue.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/BicTrue.java @@ -5,38 +5,68 @@ import edu.cmu.tetrad.graph.GraphTransforms; import edu.cmu.tetrad.search.score.SemBicScorer; +import java.io.Serial; + import static org.apache.commons.math3.util.FastMath.tanh; /** - * True BIC score. + * True BIC score. The BIC is calculated as 2L - k ln N, so "higher is better." * * @author josephramsey */ public class BicTrue implements Statistic { + @Serial private static final long serialVersionUID = 23L; private boolean precomputeCovariances = true; + /** + * No-arg constructor. Used for reflection; do not delete. + */ @Override public String getAbbreviation() { return "BicTrue"; } + /** + * Returns the description of the statistic. + * + * @return + */ @Override public String getDescription() { return "BIC of the true model"; } + /** + * Returns the value of the statistic. + * + * @param trueGraph The true graph (DAG, CPDAG, PAG_of_the_true_DAG). + * @param estGraph The estimated graph (same type). + * @param dataModel The data model. + * @return The value of the statistic. + */ @Override public double getValue(Graph trueGraph, Graph estGraph, DataModel dataModel) { // double est = SemBicScorer.scoreDag(SearchGraphUtils.dagFromCPDAG(estGraph), dataModel); - return SemBicScorer.scoreDag(GraphTransforms.dagFromCPDAG(trueGraph, null), dataModel, precomputeCovariances); + return SemBicScorer.scoreDag(GraphTransforms.dagFromCpdag(trueGraph, null), dataModel, precomputeCovariances); } + /** + * Returns the normalized value of the statistic. + * + * @param value The value of the statistic. + * @return The normalized value of the statistic. + */ @Override public double getNormValue(double value) { return tanh(value); } + /** + * Returns whether to precompute covariances. + * + * @param precomputeCovariances whether to precompute covariances. + */ public void setPrecomputeCovariances(boolean precomputeCovariances) { this.precomputeCovariances = precomputeCovariances; } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/FBetaAdj.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/FBetaAdj.java new file mode 100644 index 0000000000..059d4675d6 --- /dev/null +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/FBetaAdj.java @@ -0,0 +1,56 @@ +package edu.cmu.tetrad.algcomparison.statistic; + +import edu.cmu.tetrad.algcomparison.statistic.utils.AdjacencyConfusion; +import edu.cmu.tetrad.data.DataModel; +import edu.cmu.tetrad.graph.Graph; + +/** + * Calculates the F1 statistic for adjacencies. See + *

+ * https://en.wikipedia.org/wiki/F1_score + *

+ * We use what's on this page called the "traditional" F1 statistic. + * + * @author Joseh Ramsey + */ +public class FBetaAdj implements Statistic { + private static final long serialVersionUID = 23L; + + private double beta = 1; + + @Override + public String getAbbreviation() { + return "FBetaAdj"; + } + + @Override + public String getDescription() { + return "FBeta statistic for adjacencies"; + } + + @Override + public double getValue(Graph trueGraph, Graph estGraph, DataModel dataModel) { + AdjacencyConfusion adjConfusion = new AdjacencyConfusion(trueGraph, estGraph); + int adjTp = adjConfusion.getTp(); + int adjFp = adjConfusion.getFp(); + int adjFn = adjConfusion.getFn(); + int adjTn = adjConfusion.getTn(); + double adjPrecision = adjTp / (double) (adjTp + adjFp); + double adjRecall = adjTp / (double) (adjTp + adjFn); + return (1 + beta * beta) * (adjPrecision * adjRecall) + / (beta * beta * adjPrecision + adjRecall); + } + + @Override + public double getNormValue(double value) { + return value; + } + + public double getBeta() { + return beta; + } + + public void setBeta(double beta) { + this.beta = beta; + } +} diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/MarkovAdequacyScore.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/MarkovAdequacyScore.java deleted file mode 100644 index 5bafefbb19..0000000000 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/MarkovAdequacyScore.java +++ /dev/null @@ -1,46 +0,0 @@ -package edu.cmu.tetrad.algcomparison.statistic; - -import edu.cmu.tetrad.data.DataModel; -import edu.cmu.tetrad.data.DataSet; -import edu.cmu.tetrad.graph.Graph; -import edu.cmu.tetrad.search.ConditioningSetType; -import edu.cmu.tetrad.search.MarkovCheck; -import edu.cmu.tetrad.search.test.IndTestFisherZ; - -/** - * Tests whether the p-values under the null distribution are distributed as Uniform, and if so, returns the proportion - * of judgements of dependence under the Alternative Hypothesis. If the p-values are not distributed as Uniform, zero is - * returned. - * - * @author josephramsey - */ -public class MarkovAdequacyScore implements Statistic { - private static final long serialVersionUID = 23L; - private double alpha = 0.05; - - @Override - public String getAbbreviation() { - return "MAS"; - } - - @Override - public String getDescription() { - return "Markov Adequacy Score (depends only on the estimated DAG and the data)"; - } - - @Override - public double getValue(Graph trueGraph, Graph estGraph, DataModel dataModel) { - MarkovCheck markovCheck = new MarkovCheck(estGraph, new IndTestFisherZ((DataSet) dataModel, 0.01), ConditioningSetType.LOCAL_MARKOV); - markovCheck.generateResults(); - return markovCheck.getMarkovAdequacyScore(alpha); - } - - @Override - public double getNormValue(double value) { - return value; - } - - public void setAlpha(double alpha) { - this.alpha = alpha; - } -} diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/NumParametersEst.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/NumParametersEst.java new file mode 100644 index 0000000000..a09152bf0f --- /dev/null +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/NumParametersEst.java @@ -0,0 +1,74 @@ +package edu.cmu.tetrad.algcomparison.statistic; + +import edu.cmu.tetrad.data.DataModel; +import edu.cmu.tetrad.data.DataSet; +import edu.cmu.tetrad.graph.Graph; +import edu.cmu.tetrad.graph.GraphTransforms; +import edu.cmu.tetrad.graph.Node; +import edu.cmu.tetrad.search.score.DiscreteBicScore; + +import java.io.Serial; +import java.util.List; + +import static org.apache.commons.math3.util.FastMath.tanh; + +/** + * Number of parameters for a discrete Bayes model of the data. Must be for a discrete dataset. + * + * @author josephramsey + */ +public class NumParametersEst implements Statistic { + + @Serial + private static final long serialVersionUID = 23L; + + public NumParametersEst() { + } + + @Override + public String getAbbreviation() { + return "NumParams"; + } + + @Override + public String getDescription() { + return "Number of parameters for the estimated graph for a Bayes or SEM model"; + } + + @Override + public double getValue(Graph trueGraph, Graph estGraph, DataModel dataModel) { + if (dataModel.isDiscrete()) { + DiscreteBicScore score = new DiscreteBicScore((DataSet) dataModel); + + Graph dag = GraphTransforms.dagFromCpdag(estGraph, null); + List nodes = dag.getNodes(); + + double params = 0.0; + + for (Node node : dag.getNodes()) { + score.setPenaltyDiscount(1); + int i = nodes.indexOf(node); + List parents = dag.getParents(node); + int[] parentIndices = new int[parents.size()]; + + for (Node parent : parents) { + parentIndices[parents.indexOf(parent)] = nodes.indexOf(parent); + } + + params += score.numParameters(i, parentIndices); + } + + return params; + } else if (dataModel.isContinuous()) { + return estGraph.getNumEdges(); + } else { + throw new IllegalArgumentException("Data must be discrete"); + } + } + + @Override + public double getNormValue(double value) { + return tanh(value / 1e6); + } +} + diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/utils/BidirectedConfusion.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/utils/BidirectedConfusion.java index 452b4c6b01..7a78f8d24b 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/utils/BidirectedConfusion.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/statistic/utils/BidirectedConfusion.java @@ -18,6 +18,12 @@ public class BidirectedConfusion { private int fp; private int fn; + /** + * Constructs a new confusion matrix for bidirected edges. + * + * @param truth The true graph. + * @param est The estimated graph. + */ public BidirectedConfusion(Graph truth, Graph est) { this.tp = 0; this.fp = 0; @@ -56,18 +62,38 @@ public BidirectedConfusion(Graph truth, Graph est) { this.tn = all - this.fn - this.fp - this.fn; } + /** + * Returns the number of true positives. + * + * @return The number of true positives. + */ public int getTp() { return this.tp; } + /** + * Returns the number of false positives. + * + * @return The number of false positives. + */ public int getFp() { return this.fp; } + /** + * Returns the number of false negatives. + * + * @return The number of false negatives. + */ public int getFn() { return this.fn; } + /** + * Returns the number of true negatives. + * + * @return The number of true negatives. + */ public int getTn() { return this.tn; } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/utils/TakesIndependenceWrapper.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/utils/TakesIndependenceWrapper.java index 5c35194606..de9911ec94 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/utils/TakesIndependenceWrapper.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/utils/TakesIndependenceWrapper.java @@ -3,12 +3,24 @@ import edu.cmu.tetrad.algcomparison.independence.IndependenceWrapper; /** - * Author : Jeremy Espino MD Created 7/13/17 2:25 PM + * Tags an algorithm as using an independence wrapper. + * + * @author Jeremy Espino MD Created 7/13/17 2:25 PM */ public interface TakesIndependenceWrapper { + /** + * Returns the independence wrapper. + * + * @return the independence wrapper. + */ IndependenceWrapper getIndependenceWrapper(); + /** + * Sets the independence wrapper. + * + * @param independenceWrapper the independence wrapper. + */ void setIndependenceWrapper(IndependenceWrapper independenceWrapper); } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/utils/UsesScoreWrapper.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/utils/UsesScoreWrapper.java index d03016493f..be853c9dc2 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/utils/UsesScoreWrapper.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/algcomparison/utils/UsesScoreWrapper.java @@ -3,11 +3,22 @@ import edu.cmu.tetrad.algcomparison.score.ScoreWrapper; /** + * Tags an algorithm as using a score wrapper. + *

* Author : Jeremy Espino MD Created 7/6/17 2:19 PM */ public interface UsesScoreWrapper { + /** + * Returns the score wrapper. + * @return the score wrapper. + */ ScoreWrapper getScoreWrapper(); + /** + * Sets the score wrapper. + * + * @param score the score wrapper. + */ void setScoreWrapper(ScoreWrapper score); } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/annotation/AbstractAnnotations.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/annotation/AbstractAnnotations.java index 2ff0a40347..0a4fd09d2c 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/annotation/AbstractAnnotations.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/annotation/AbstractAnnotations.java @@ -75,7 +75,7 @@ public List> filterByAnnotation(List> annoCl } List> list = annoClasses.stream() - .filter(e -> e.getClazz().isAnnotationPresent(type)) + .filter(e -> e.clazz().isAnnotationPresent(type)) .collect(Collectors.toList()); return Collections.unmodifiableList(list); @@ -93,7 +93,7 @@ public List> filterOutByAnnotation(List> ann } List> list = annoClasses.stream() - .filter(e -> !e.getClazz().isAnnotationPresent(type)) + .filter(e -> !e.clazz().isAnnotationPresent(type)) .collect(Collectors.toList()); return Collections.unmodifiableList(list); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/annotation/AnnotatedClass.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/annotation/AnnotatedClass.java index a56a602075..d5ea201e6f 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/annotation/AnnotatedClass.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/annotation/AnnotatedClass.java @@ -18,6 +18,7 @@ */ package edu.cmu.tetrad.annotation; +import java.io.Serial; import java.io.Serializable; import java.lang.annotation.Annotation; @@ -27,37 +28,37 @@ * @param annotation * @author Kevin V. Bui (kvb2@pitt.edu) */ -public class AnnotatedClass implements Serializable { +public record AnnotatedClass(Class clazz, T annotation) implements Serializable { + @Serial private static final long serialVersionUID = 5060798016477163171L; - private final Class clazz; - - private final T annotation; - /** * Creates an annotated class. - * @param clazz class + * + * @param clazz class * @param annotation annotation */ - public AnnotatedClass(Class clazz, T annotation) { - this.clazz = clazz; - this.annotation = annotation; + public AnnotatedClass { } /** * Gets the class. + * * @return class */ - public Class getClazz() { + @Override + public Class clazz() { return this.clazz; } /** * Gets the annotation. + * * @return annotation */ - public T getAnnotation() { + @Override + public T annotation() { return this.annotation; } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/annotation/AnnotatedClassUtils.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/annotation/AnnotatedClassUtils.java index ca4a8180d2..da14acc66a 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/annotation/AnnotatedClassUtils.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/annotation/AnnotatedClassUtils.java @@ -64,7 +64,7 @@ public static List> filterByAnnotations if (annotatedClasses != null && !annotatedClasses.isEmpty()) { annotatedClasses.stream() - .filter(e -> e.getClazz().isAnnotationPresent(annotation)) + .filter(e -> e.clazz().isAnnotationPresent(annotation)) .collect(Collectors.toCollection(() -> list)); } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/bayes/BayesProperties.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/bayes/BayesProperties.java index 37a811b5ff..539b5d1033 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/bayes/BayesProperties.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/bayes/BayesProperties.java @@ -41,7 +41,6 @@ public final class BayesProperties { private final DataSet dataSet; private final List variables; - private final int[][] data; private final int sampleSize; private final int[] numCategories; private double chisq; @@ -49,6 +48,10 @@ public final class BayesProperties { private double bic; private double likelihood; + /** + * Constructs a new BayesProperties object for the given data set. + * @param dataSet The data set. + */ public BayesProperties(DataSet dataSet) { if (dataSet == null) { throw new NullPointerException(); @@ -56,6 +59,7 @@ public BayesProperties(DataSet dataSet) { this.dataSet = dataSet; + int[][] data; if (dataSet instanceof BoxDataSet) { DataBox dataBox = ((BoxDataSet) dataSet).getDataBox(); @@ -63,19 +67,18 @@ public BayesProperties(DataSet dataSet) { VerticalIntDataBox box = new VerticalIntDataBox(dataBox); - this.data = box.getVariableVectors(); + box.getVariableVectors(); } else { - this.data = new int[dataSet.getNumColumns()][]; + data = new int[dataSet.getNumColumns()][]; this.variables = dataSet.getVariables(); for (int j = 0; j < dataSet.getNumColumns(); j++) { - this.data[j] = new int[dataSet.getNumRows()]; + data[j] = new int[dataSet.getNumRows()]; for (int i = 0; i < dataSet.getNumRows(); i++) { - this.data[j][i] = dataSet.getInt(i, j); + data[j][i] = dataSet.getInt(i, j); } } - } this.sampleSize = dataSet.getNumRows(); @@ -103,6 +106,7 @@ private static int getRowIndex(int[] dim, int[] values) { * Calculates the p-value of the graph with respect to the given data. * * @param graph The graph. + * @return The p-value. */ public LikelihoodRet getLikelihoodRatioP(Graph graph) { @@ -282,90 +286,11 @@ private int getDof2(Graph graph) { } private Ret getLikelihoodNode(int node, int[] parents) { - DiscreteBicScore bic = new DiscreteBicScore(dataSet); double lik = bic.localScore(node, parents); int dof = (numCategories[node] - 1) * parents.length; -// int d = ; -// -// for (int childValue = 0; childValue < c; childValue++) { -// d++; -// } - - -// // Number of categories for node. -// int c = this.numCategories[node]; -// -// // Numbers of categories of parents. -// int[] dims = new int[parents.length]; -// -// for (int p = 0; p < parents.length; p++) { -// dims[p] = this.numCategories[parents[p]]; -// } -// -// // Number of parent states. -// int r = 1; -// -// for (int p = 0; p < parents.length; p++) { -// r *= dims[p]; -// } -// -// // Conditional cell coefs of data for node given parents(node). -// int[][] n_jk = new int[r][c]; -// int[] n_j = new int[r]; -// -// int[] parentValues = new int[parents.length]; -// -// int[][] myParents = new int[parents.length][]; -// for (int i = 0; i < parents.length; i++) { -// myParents[i] = this.data[parents[i]]; -// } -// -// int[] myChild = this.data[node]; -// -// for (int i = 0; i < this.sampleSize; i++) { -// for (int p = 0; p < parents.length; p++) { -// parentValues[p] = myParents[p][i]; -// } -// -// int childValue = myChild[i]; -// -// if (childValue == -99) { -// throw new IllegalStateException("Please remove or impute missing " + -// "values (record " + i + " column " + i + ")"); -// } -// -// int rowIndex = BayesProperties.getRowIndex(dims, parentValues); -// -// n_jk[rowIndex][childValue]++; -// n_j[rowIndex]++; -// } - -// //Finally, compute the score -// double lik = 0.0; -// int dof = 0; -// -// for (int rowIndex = 0; rowIndex < r; rowIndex++) { -// if (rowIndex == 0) continue; -// -// if (Thread.interrupted()) break; -// -// int d = 0; -// -// for (int childValue = 0; childValue < c; childValue++) { -// int cellCount = n_jk[rowIndex][childValue]; -// int rowCount = n_j[rowIndex]; -// -// if (cellCount == 0) continue; -// lik += cellCount * FastMath.log(cellCount / (double) rowCount); -// d++; -// } -// -// if (d > 0) dof += c - 1; -// } - return new Ret(lik, dof); } @@ -391,10 +316,16 @@ private double getDofNode(int node, int[] parents) { return r * c; } + /** + * Returns the number of categories for the given variable. + */ public int getSampleSize() { return this.sampleSize; } + /** + * Returns the variable with the given name (assumed the target). + */ public Node getVariable(String targetName) { for (Node node : this.variables) { if (node.getName().equals(targetName)) { @@ -413,28 +344,63 @@ private DiscreteVariable getVariable(int i) { } } + /** + * Returns the likelihood ratio test statistic for the given graph and its degrees of freedom. + */ private static class Ret { private final double lik; private final int dof; + /** + * Constructs a new Ret object. + * @param lik The likelihood. + * @param dof The degrees of freedom. + */ public Ret(double lik, int dof) { this.lik = lik; this.dof = dof; } + /** + * Returns the likelihood. + * @return The likelihood. + */ public double getLik() { return this.lik; } + /** + * Returns the degrees of freedom. + * @return The degrees of freedom. + */ public int getDof() { return this.dof; } } - public class LikelihoodRet { + /** + * Returns the number of categories for the given variable. + */ + public static class LikelihoodRet { + + /** + * The p-value. + */ public double p; + + /** + * The BIC. + */ public double bic; + + /** + * The chi-squared statistic. + */ public double chiSq; + + /** + * The degrees of freedom. + */ public double dof; } } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/bayes/BayesUpdater.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/bayes/BayesUpdater.java index 4dbfa13c2f..3796d0a127 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/bayes/BayesUpdater.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/bayes/BayesUpdater.java @@ -28,7 +28,7 @@ * evidence), where evidence takes the form of a Proposition over the variables in the Bayes net, possibly with * additional information about which variables in the Bayes net have been manipulated. Some updaters may be able to * calculate joint marginals as well--that is, P(AND_i{Xi = xi'} | evidence). Also, not all updaters can take - * manipulation information into account. See implementations for details. + * manipulation information into account. See implementations for details.) * * @author josephramsey * @see Evidence @@ -36,6 +36,9 @@ * @see Manipulation */ public interface BayesUpdater extends TetradSerializable { + /** + * Serial version ID for serialization. + */ long serialVersionUID = 23L; /** diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/bayes/BayesXmlParser.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/bayes/BayesXmlParser.java index 39fd3c60c1..8ec2e7fc44 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/bayes/BayesXmlParser.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/bayes/BayesXmlParser.java @@ -106,6 +106,12 @@ private static BayesIm makeBayesIm(BayesPm bayesPm, Element element2) { return bayesIm; } + /** + * Returns the BayesIm object represented by the given element. + * + * @param element the element + * @return the BayesIm object + */ public BayesIm getBayesIm(Element element) { if (!"bayesNet".equals(element.getQualifiedName())) { throw new IllegalArgumentException("Expecting 'bayesNet' element."); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/bayes/BayesXmlRenderer.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/bayes/BayesXmlRenderer.java index 2644e376eb..8a2b7b09fa 100755 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/bayes/BayesXmlRenderer.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/bayes/BayesXmlRenderer.java @@ -36,6 +36,12 @@ */ public final class BayesXmlRenderer { + /** + * Private constructor to prevent instantiation. + * + * @param bayesIm the Bayes net + * @return the XML element + */ public static Element getElement(BayesIm bayesIm) { if (bayesIm == null) { throw new NullPointerException(); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/bayes/BdeMetricCache.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/bayes/BdeMetricCache.java index 4f1541073d..e016038a43 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/bayes/BdeMetricCache.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/bayes/BdeMetricCache.java @@ -34,32 +34,36 @@ /** *

Provides a method for computing the score of a model, called the BDe * metric (Bayesian Dirchlet likelihood equivalence), given a dataset (assumes no missing values) and a Bayes - * parameterized network (assumes no latent variables).> 0

This version has a method that computes the score for a - * given factor of a model, where a factor is determined by a node and its parents. It stores scores in a map whose - * argument is an ordered pair consisting of 1) a node and 2) set of parents. The score for the entire model is the - * product of the scores of its factors. Since the log of the gamma function is used here the sum of the logs is - * computed as the score. Compare this with the score method in the BdeMetric class which computes the score for the - * entire model in one pass. The advantage of the approach in this class is that it is more efficient in the context of - * a search algorithm where different models are scored but where many of them will have the same factors. This class - * stores the score (relative to the dataset) for any [node, set of parents] pair and thus avoids the expensive log - * gamma function calls. Instead it looks in the map scores to see if it has already computed the score and, if so, - * returns the previously computed value.> 0

See "Learning Bayesian Networks: The Combination of Knowledge and - * Statistical Data" by David Heckerman, Dan Geiger, and David M. Chickering. Microsoft Technical Report - * MSR-TR-94-09.> 0 + * parameterized network (assumes no latent variables).> 0 + *

+ * This version has a method that computes the score for a given factor of a model, where a factor is determined by a + * node and its parents. It stores scores in a map whose argument is an ordered pair consisting of 1) a node and 2) set + * of parents. The score for the entire model is the product of the scores of its factors. Since the log of the gamma + * function is used here the sum of the logs is computed as the score. Compare this with the score method in the + * BdeMetric class which computes the score for the entire model in one pass. The advantage of the approach in this + * class is that it is more efficient in the context of a search algorithm where different models are scored but where + * many of them will have the same factors. This class stores the score (relative to the dataset) for any [node, set of + * parents] pair and thus avoids the expensive log gamma function calls. Instead, it looks in the map scores to see if + * it has already computed the score and, if so, returns the previously computed value.> 0

See "Learning Bayesian + * Networks: The Combination of Knowledge and Statistical Data" by David Heckerman, Dan Geiger, and David M. + * Chickering. Microsoft Technical Report MSR-TR-94-09.> 0 * * @author Frank Wimberly */ public final class BdeMetricCache { private final DataSet dataSet; private final List variables; - private final BayesPm bayesPm; //Determines the list of variables (nodes) - private final Map scores; private final Map scoreCounts; - private double[][] observedCounts; + /** + * Constructs a BdeMetricCache object for a given dataset and BayesPm. + * + * @param dataSet The dataset for which the BDe metric is to be computed. + * @param bayesPm The BayesPm that determines the list of variables (nodes) and the structure of the graph. + */ public BdeMetricCache(DataSet dataSet, BayesPm bayesPm) { this.bayesPm = bayesPm; this.dataSet = dataSet; @@ -71,6 +75,12 @@ public BdeMetricCache(DataSet dataSet, BayesPm bayesPm) { /** * Computes the BDe score, using the logarithm of the gamma function, relative to the data, of the factor determined * by a node and its parents. + * + * @param node The node of the factor. + * @param parents The parents of the node. + * @param bayesPmMod The BayesPm that determines the list of variables (nodes) and the structure of the graph. + * @param bayesIm The BayesIm that determines the observed counts. + * @return The score of the factor. */ public double scoreLnGam(Node node, Set parents, BayesPm bayesPmMod, BayesIm bayesIm) { @@ -441,6 +451,11 @@ private int getVarIndex(String name) { /** * This method is used in testing and debugging and not in the BDe metric calculations. + * + * @param node The node for which the observed counts are to be returned. + * @param bayesPm The BayesPm that determines the list of variables (nodes) and the structure of the graph. + * @param bayesIm The BayesIm that determines the observed counts. + * @return The observed counts for the given node. */ public double[][] getObservedCounts(Node node, BayesPm bayesPm, BayesIm bayesIm) { @@ -461,6 +476,10 @@ public double[][] getObservedCounts(Node node, BayesPm bayesPm, /** * This is just for testing the operation of the inner class and the map from nodes and parent sets to scores. + * + * @param node The node of the factor. + * @param parents The parents of the node. + * @return The score of the factor. */ public int getScoreCount(Node node, Set parents) { NodeParentsPair nodeParents = new NodeParentsPair(node, parents); @@ -488,16 +507,29 @@ private static final class NodeParentsPair { private final Node node; private final Set parents; + + /** + * Constructs a NodeParentsPair object for a given node and set of parents. + * + * @param node The node of the pair. + * @param parents The parents of the node. + */ public NodeParentsPair(Node node, Set parents) { this.node = node; this.parents = parents; } + /** + * @return The number of elements in the set of parents plus 1. + */ public int calcCount() { return this.parents.size() + 1; } + /** + * @return The node of the pair. + */ public int hashCode() { int hash = 91; hash = 43 * hash + this.node.hashCode(); @@ -506,6 +538,12 @@ public int hashCode() { return hash; } + /** + * Equals method for NodeParentsPair. + * + * @param other The other object to compare to. + * @return True if the other object is a NodeParentsPair and has the same node and parents as this one. + */ public boolean equals(Object other) { if (other == this) { return true; diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/bayes/MlBayesIm.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/bayes/MlBayesIm.java index 77003ff05c..e58a394afb 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/bayes/MlBayesIm.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/bayes/MlBayesIm.java @@ -31,6 +31,7 @@ import java.io.IOException; import java.io.ObjectInputStream; +import java.io.Serial; import java.text.NumberFormat; import java.util.*; @@ -76,8 +77,10 @@ public final class MlBayesIm implements BayesIm { * Indicates that new rows in this BayesIm should be initialized randomly. */ public static final int RANDOM = 1; + @Serial private static final long serialVersionUID = 23L; private static final double ALLOWABLE_DIFFERENCE = 1.0e-3; + static private final Random random = new Random(); /** * The associated Bayes PM model. @@ -212,66 +215,19 @@ public static List getParameterNames() { return new ArrayList<>(); } - private static double[] getRandomWeights2(int size, double[] biases) { - assert size >= 0; - - double[] row = new double[size]; - double sum = 0.0; - - for (int i = 0; i < size; i++) { -// row[i] = RandomUtil.getInstance().nextDouble() + biases[i]; - double v = RandomUtil.getInstance().nextUniform(0, biases[i]); - row[i] = v > 0.5 ? 2 * v : v; - sum += row[i]; - } - - for (int i = 0; i < size; i++) { - row[i] /= sum; - } - - return row; - } - - private static double[] getRandomWeights3(int size) { - assert size >= 0; - - double[] row = new double[size]; - double sum = 0.0; - - for (int i = 0; i < size; i++) { - row[i] = RandomUtil.getInstance().nextBeta(size / 4d, size); - sum += row[i]; - } - - for (int i = 0; i < size; i++) { - row[i] /= sum; - } - - return row; - } - - /** - * This method chooses random probabilities for a row which add up to 1.0. Random doubles are drawn from a random - * distribution, and the final row is then normalized. - * - * @param size the length of the row. - * @return an array with randomly distributed probabilities of this length. - * @see #randomizeRow - */ private static double[] getRandomWeights(int size) { - assert size >= 0; + assert size > 0; double[] row = new double[size]; double sum = 0.0; - // Renders rows more deterministic. - final double bias = 0; + int strong = (int) Math.floor(random.nextDouble() * size); for (int i = 0; i < size; i++) { - row[i] = RandomUtil.getInstance().nextDouble(); - - if (row[i] > 0.5) { - row[i] += bias; + if (i == strong) { + row[i] = 1.0; + } else { + row[i] = RandomUtil.getInstance().nextDouble() * 0.1; } sum += row[i]; @@ -598,12 +554,7 @@ public void clearRow(int nodeIndex, int rowIndex) { */ public void randomizeRow(int nodeIndex, int rowIndex) { int size = getNumColumns(nodeIndex); - this.probs[nodeIndex][rowIndex] = MlBayesIm.getRandomWeights3(size); - } - - private void randomizeRow2(int nodeIndex, int rowIndex, double[] biases) { - int size = getNumColumns(nodeIndex); - this.probs[nodeIndex][rowIndex] = MlBayesIm.getRandomWeights2(size, biases); + this.probs[nodeIndex][rowIndex] = MlBayesIm.getRandomWeights(size); } /** @@ -628,39 +579,6 @@ public void randomizeTable(int nodeIndex) { for (int rowIndex = 0; rowIndex < getNumRows(nodeIndex); rowIndex++) { randomizeRow(nodeIndex, rowIndex); } -// randomizeTable4(nodeIndex); - } - - private void randomizeTable4(int nodeIndex) { - for (int rowIndex = 0; rowIndex < getNumRows(nodeIndex); rowIndex++) { - randomizeRow(nodeIndex, rowIndex); - } - - double[][] saved = new double[getNumRows(nodeIndex)][getNumColumns(nodeIndex)]; - - double max = Double.NEGATIVE_INFINITY; - - for (int i = 0; i < 10; i++) { - for (int rowIndex = 0; rowIndex < getNumRows(nodeIndex); rowIndex++) { -// randomizeRow(nodeIndex, rowIndex); - randomizeRow2(nodeIndex, rowIndex, this.probs[nodeIndex][rowIndex]); - } - - int score = score(nodeIndex); - - if (score > max) { - max = score; - copy(this.probs[nodeIndex], saved); - } - - if (score == getNumParents(nodeIndex)) { - break; - } - } - - for (int rowIndex = 0; rowIndex < getNumRows(nodeIndex); rowIndex++) { - copy(saved, this.probs[nodeIndex]); - } } private int score(int nodeIndex) { @@ -1103,12 +1021,10 @@ public boolean equals(Object o) { return true; } - if (!(o instanceof BayesIm)) { + if (!(o instanceof BayesIm otherIm)) { return false; } - BayesIm otherIm = (BayesIm) o; - if (getNumNodes() != otherIm.getNumNodes()) { return false; } @@ -1445,6 +1361,7 @@ private void copyValuesFromOldToNew(int oldNodeIndex, int oldRowIndex, * class that didn't include it. (That's what the "s.defaultReadObject();" is for. See J. Bloch, Effective Java, for * help. */ + @Serial private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/data/BoxDataSet.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/data/BoxDataSet.java index 450149b03c..dd2c7268ad 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/data/BoxDataSet.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/data/BoxDataSet.java @@ -124,6 +124,12 @@ public final class BoxDataSet implements DataSet { */ private char outputDelimiter = '\t'; + /** + * Constructs a new data set with the given number of rows and columns, with all values set to missing. + * + * @param dataBox The data box. + * @param variables The variables. + */ public BoxDataSet(DataBox dataBox, List variables) { this.dataBox = dataBox; this.variables = new ArrayList<>(variables); @@ -135,6 +141,8 @@ public BoxDataSet(DataBox dataBox, List variables) { /** * Makes of copy of the given data set. + * + * @param dataSet The data set to copy. */ public BoxDataSet(BoxDataSet dataSet) { this.name = dataSet.name; @@ -147,6 +155,8 @@ public BoxDataSet(BoxDataSet dataSet) { /** * Generates a simple exemplar of this class to test serialization. + * + * @return A simple exemplar of this class. */ public static BoxDataSet serializableInstance() { List vars = new ArrayList<>(); @@ -1333,6 +1343,11 @@ public NumberFormat getNumberFormat() { return this.nf; } + /** + * Sets the number format to be used when printing out the data set. The default is the one at + * + * @param nf The number format to be used when printing out the data set. The default is the one at + */ public void setNumberFormat(NumberFormat nf) { if (nf == null) { throw new NullPointerException(); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/data/ByteDataBox.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/data/ByteDataBox.java index 3e777c5990..58ae752447 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/data/ByteDataBox.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/data/ByteDataBox.java @@ -23,6 +23,7 @@ import edu.cmu.tetrad.graph.Node; +import java.io.Serial; import java.util.ArrayList; import java.util.List; @@ -30,6 +31,7 @@ * Stores a 2D array of byte data. Note that the missing value marker for this box is -99. */ public class ByteDataBox implements DataBox { + @Serial private static final long serialVersionUID = 23L; /** @@ -50,6 +52,9 @@ public class ByteDataBox implements DataBox { /** * Constructs an 2D byte array consisting entirely of missing values (-99). + * + * @param rows the number of rows. + * @param cols the number of columns. */ public ByteDataBox(int rows, int cols) { this.data = new byte[rows][cols]; @@ -66,6 +71,8 @@ public ByteDataBox(int rows, int cols) { /** * Constructs a new data box using the given 2D byte data array as data. + * + * @param data the data to use. */ public ByteDataBox(byte[][] data) { int length = data[0].length; @@ -84,6 +91,8 @@ public ByteDataBox(byte[][] data) { /** * Generates a simple exemplar of this class to test serialization. + * + * @return a simple exemplar of this class to test serialization. */ public static BoxDataSet serializableInstance() { List vars = new ArrayList<>(); @@ -106,7 +115,12 @@ public int numCols() { } /** - * Sets the value at the given row/column to the given Number value. The value used is number.byteValue(). + * Sets the value at the given row/column to the given Number value. The value used is number.byteValue(). If the + * value is null, the missing value marker (-99) is used. + * + * @param row the row index. + * @param col the column index. + * @param value the value to store. */ public void set(int row, int col, Number value) { if (value == null) { diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/data/CellTable.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/data/CellTable.java index 58d59bdd6f..472e204ad3 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/data/CellTable.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/data/CellTable.java @@ -23,7 +23,9 @@ import edu.cmu.tetrad.util.MultiDimIntTable; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; /** @@ -35,17 +37,12 @@ */ public final class CellTable { - -// /** -// * Stores a copy of coordinates for temporary use. (Reused.) -// */ -// private int[] coordCopy; - private final MultiDimIntTable table; /** * The value used in the data for missing values. */ private int missingValue = -99; + private List rows; /** * Constructs a new cell table using the given array for dimensions, initializing all cells in the table to zero. @@ -57,11 +54,22 @@ public CellTable(int[] dims) { } public void addToTable(DataSet dataSet, int[] indices) { + if (rows == null) { + rows = new ArrayList<>(); + for (int i = 0; i < dataSet.getNumRows(); i++) { + rows.add(i); + } + } else { + for (int i = 0; i < rows.size(); i++) { + if (rows.get(i) >= dataSet.getNumRows()) + throw new IllegalArgumentException("Row " + i + " is too large."); + } + } + int[] dims = new int[indices.length]; for (int i = 0; i < indices.length; i++) { - DiscreteVariable variable = - (DiscreteVariable) dataSet.getVariable(indices[i]); + DiscreteVariable variable = (DiscreteVariable) dataSet.getVariable(indices[i]); dims[i] = variable.getNumCategories(); } @@ -70,12 +78,11 @@ public void addToTable(DataSet dataSet, int[] indices) { int[] coords = new int[indices.length]; points: - for (int i = 0; i < dataSet.getNumRows(); i++) { + for (int i : rows) { for (int j = 0; j < indices.length; j++) { try { coords[j] = dataSet.getInt(i, indices[j]); } catch (Exception e) { - e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. coords[j] = dataSet.getInt(i, j); } @@ -108,7 +115,7 @@ public int getNumValues(int varIndex) { public long calcMargin(int[] coords) { int[] coordCopy = internalCoordCopy(coords); - int sum = 0; + long sum = 0; int i = -1; while (++i < coordCopy.length) { @@ -129,8 +136,8 @@ public long calcMargin(int[] coords) { /** * An alternative way to specify a marginal calculation. In this case, coords specifies a particular cell in the * table, and varIndices is an array containing the indices of the variables over which the margin sum should be - * calculated. The sum is over the cell specified by 'coord' and all of the cells which differ from that cell in any - * of the specified coordinates. + * calculated. The sum is over the cell specified by 'coord' and all the cells which differ from that cell in any of + * the specified coordinates. * * @param coords an int[] value * @param marginVars an int[] value @@ -150,16 +157,7 @@ public long calcMargin(int[] coords, int[] marginVars) { * Makes a copy of the coordinate array so that the original is not messed up. */ private int[] internalCoordCopy(int[] coords) { - int[] coordCopy = Arrays.copyOf(coords, coords.length); - -// if ((this.coordCopy == null) || -// (this.coordCopy.length != coords.length)) { -// this.coordCopy = new int[coords.length]; -// } -// -// System.arraycopy(coords, 0, this.coordCopy, 0, coords.length); - - return coordCopy; + return Arrays.copyOf(coords, coords.length); } private int getMissingValue() { @@ -173,6 +171,19 @@ public void setMissingValue(int missingValue) { public long getValue(int[] testCell) { return this.table.getValue(testCell); } + + public void setRows(List rows) { + if (rows == null) { + this.rows = null; + } else { + for (int i = 0; i < rows.size(); i++) { + if (rows.get(i) == null) throw new NullPointerException("Row " + i + " is null."); + if (rows.get(i) < 0) throw new IllegalArgumentException("Row " + i + " is negative."); + } + + this.rows = rows; + } + } } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/data/DataBox.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/data/DataBox.java index ffb1ca67c7..28f117f7a8 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/data/DataBox.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/data/DataBox.java @@ -46,12 +46,17 @@ public interface DataBox extends TetradSerializable { * Sets the value at the given row and column to the given Number. This number may be interpreted differently * depending on how values are stored. A value of null is interpreted as a missing value. * + * @param row the row index. + * @param col the column index. + * @param value the value to store. * @throws IllegalArgumentException if the given value cannot be stored (because it's out of range or cannot be * converted or whatever). */ void set(int row, int col, Number value) throws IllegalArgumentException; /** + * @param row the row index. + * @param col the column index. * @return the value at the given row and column as a Number. If the value is missing, null is uniformly returned. */ Number get(int row, int col); @@ -62,10 +67,17 @@ public interface DataBox extends TetradSerializable { DataBox copy(); /** + * @param rows the row indices. + * @param cols the column indices. * @return this data box, restricted to the given rows and columns. */ DataBox viewSelection(int[] rows, int[] cols); + /** + * Returns a data box of the same dimensions as this one, without setting any values. + * + * @return a new data box. + */ DataBox like(); } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/data/DataFilter.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/data/DataFilter.java index 6d15b59482..c8a342b506 100755 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/data/DataFilter.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/data/DataFilter.java @@ -32,6 +32,9 @@ public interface DataFilter { /** * Interpolates the given data set, producing a data set with no missing values. + * + * @param dataSet the data set to interpolate. + * @return the interpolated data set. */ DataSet filter(DataSet dataSet); } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/data/DataSet.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/data/DataSet.java index 0a5e5e0efa..bc7d3dc3d1 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/data/DataSet.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/data/DataSet.java @@ -40,12 +40,16 @@ public interface DataSet extends DataModel { /** * Adds the given variable to the data set. * + * @param variable The variable to add. * @throws IllegalArgumentException if the variable is neither continuous nor discrete. */ void addVariable(Node variable); /** * Adds the given variable at the given index. + * + * @param index The index at which to add the variable. + * @param variable The variable to add. */ void addVariable(int index, Node variable); @@ -53,6 +57,8 @@ public interface DataSet extends DataModel { * Changes the variable for the given column from from to * to. Supported currently only for discrete variables. * + * @param from The variable to change. + * @param to The variable to change to. * @throws IllegalArgumentException if the given change is not supported. */ void changeVariable(Node from, Node to); @@ -64,22 +70,28 @@ public interface DataSet extends DataModel { /** * Ensures that the dataset has at least columns columns. Used for pasting data into the dataset. When - * creating new columns, names in the excludedVarialbeNames list may not be used. The purpose of this + * creating new columns, names in the excludedVariableNames list may not be used. The purpose of this * is to allow these names to be set later by the calling class, without incurring conflicts. + * + * @param columns The number of columns to ensure. + * @param excludedVariableNames The names of variables that should not be used for new columns. */ void ensureColumns(int columns, List excludedVariableNames); /** - * Returns true if and only if this data set contains at least one missing value. + * @return true if and only if this data set contains at least one missing value. */ boolean existsMissingValue(); /** * Ensures that the dataset has at least rows rows. Used for pasting data into the dataset. + * + * @param rows The number of rows to ensure. */ void ensureRows(int rows); /** + * @param variable The variable to check. * @return the column index of the given variable. */ int getColumn(Node variable); @@ -99,6 +111,8 @@ public interface DataSet extends DataModel { Matrix getCovarianceMatrix(); /** + * @param row The index of the case. + * @param column The index of the variable. * @return the value at the given row and column as a double. For discrete data, returns the integer value cast to a * double. */ @@ -147,11 +161,13 @@ public interface DataSet extends DataModel { int[] getSelectedIndices(); /** + * @param column The index of the variable. * @return the variable at the given column. */ Node getVariable(int column); /** + * @param name The name of the variable. * @return the variable with the given name. */ Node getVariable(String name); @@ -167,45 +183,54 @@ public interface DataSet extends DataModel { List getVariables(); /** - * @return true if this is a continuous data set--that is, if it contains at least one column and all of the columns + * @return true if this is a continuous data set--that is, if it contains at least one column and all the columns * are continuous. */ boolean isContinuous(); /** - * @return true if this is a discrete data set--that is, if it contains at least one column and all of the columns - * are discrete. + * @return true if this is a discrete data set--that is, if it contains at least one column and all the columns are + * discrete. */ boolean isDiscrete(); /** * @return true if this is a continuous data set--that is, if it contains at least one continuous column and one - * discrete columnn. + * discrete column. */ boolean isMixed(); /** + * @param variable The variable to check. * @return true iff the given column has been marked as selected. */ boolean isSelected(Node variable); /** * Removes the variable (and data) at the given index. + * + * @param index The index of the variable to remove. */ void removeColumn(int index); /** * Removes the given variable, along with all of its data. + * + * @param variable The variable to remove. */ void removeColumn(Node variable); /** * Removes the given columns from the data set. + * + * @param selectedCols The indices of the columns to remove. */ void removeCols(int[] selectedCols); /** * Removes the given rows from the data set. + * + * @param selectedRows The indices of the rows to remove. */ void removeRows(int[] selectedRows); @@ -215,6 +240,7 @@ public interface DataSet extends DataModel { * * @param row The index of the case. * @param column The index of the variable. + * @param value The value to set. */ void setDouble(int row, int column, double value); @@ -222,8 +248,9 @@ public interface DataSet extends DataModel { * Sets the value at the given (row, column) to the given int value, assuming the variable for the column is * discrete. * - * @param row The index of the case. - * @param col The index of the variable. + * @param row The index of the case. + * @param col The index of the variable. + * @param value The value to set. */ void setInt(int row, int col, int value); @@ -246,17 +273,21 @@ public interface DataSet extends DataModel { * Creates and returns a dataset consisting of those variables in the list vars. Vars must be a subset of the * variables of this DataSet. The ordering of the elements of vars will be the same as in the list of variables in * this DataSet. + * + * @return a new data set consisting of the variables in the list vars. */ DataSet subsetColumns(List vars); /** - * @return a new data set in which the the column at indices[i] is placed at index i, for i = 0 to indices.length - - * 1. (View instead?) + * @param columns The indices of the columns to include in the new data set. + * @return a new data set in which the column at indices[i] is placed at index i, for i = 0 to indices.length - 1. + * (View instead?) */ DataSet subsetColumns(int[] columns); /** - * @return a new data set in which the the row at indices[i] is placed at index i, for i = 0 to indices.length - 1. + * @param rows The indices of the rows to include in the new data set. + * @return a new data set in which the row at indices[i] is placed at index i, for i = 0 to indices.length - 1. * (View instead?) */ DataSet subsetRows(int[] rows); @@ -268,16 +299,22 @@ public interface DataSet extends DataModel { /** * The number format of the dataset. + * + * @return The number format of the dataset. */ NumberFormat getNumberFormat(); /** * The number formatter used to print out continuous values. + * + * @param nf The number formatter used to print out continuous values. */ void setNumberFormat(NumberFormat nf); /** - * The character used a delimiter when the dataset is output. + * The character used a delimiter when the dataset is output + * + * @param character The character used as a delimiter when the dataset is output */ void setOutputDelimiter(Character character); @@ -286,12 +323,33 @@ public interface DataSet extends DataModel { */ void permuteRows(); + /** + * Returns the map of column names to tooltips. + * + * @return The map of column names to tooltips. + */ Map getColumnToTooltip(); + /** + * Checks if the given object is equal to this dataset. + * + * @param o The object to check. + * @return True if the given object is equal to this dataset. + */ boolean equals(Object o); + /** + * Returns a copy of this dataset. + * + * @return A copy of this dataset. + */ DataSet copy(); + /** + * Returns a dataset with the same dimensions as this dataset, but with no data. + * + * @return a dataset with the same dimensions as this dataset, but with no data. + */ DataSet like(); } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/data/GeneralAndersonDarlingTest.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/data/GeneralAndersonDarlingTest.java index a380fc86e4..76b101fa10 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/data/GeneralAndersonDarlingTest.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/data/GeneralAndersonDarlingTest.java @@ -21,12 +21,17 @@ package edu.cmu.tetrad.data; +import edu.cmu.tetrad.util.RandomUtil; import org.apache.commons.math3.distribution.RealDistribution; +import org.apache.commons.math3.distribution.UniformRealDistribution; import org.apache.commons.math3.util.FastMath; +import java.util.ArrayList; import java.util.Collections; import java.util.List; +import static org.apache.commons.math3.util.FastMath.*; + /** * Implements the Anderson-Darling test against the given CDF, with P values calculated as in R's ad.test method (in * package nortest). @@ -118,23 +123,79 @@ private void runTest() { } double a = -n - (1.0 / numSummed) * h; - double aa = (1 + 0.75 / numSummed + 2.25 / FastMath.pow(numSummed, 2)) * a; + double aa = (1 + 0.75 / numSummed + 2.25 / pow(numSummed, 2)) * a; double p; if (aa < 0.2) { - p = 1 - FastMath.exp(-13.436 + 101.14 * aa - 223.73 * aa * aa); + p = 1 - exp(-13.436 + 101.14 * aa - 223.73 * aa * aa); } else if (aa < 0.34) { - p = 1 - FastMath.exp(-8.318 + 42.796 * aa - 59.938 * aa * aa); + p = 1 - exp(-8.318 + 42.796 * aa - 59.938 * aa * aa); } else if (aa < 0.6) { - p = FastMath.exp(0.9177 - 4.279 * aa - 1.38 * aa * aa); + p = exp(0.9177 - 4.279 * aa - 1.38 * aa * aa); } else { - p = FastMath.exp(1.2937 - 5.709 * aa + 0.0186 * aa * aa); + p = exp(1.2937 - 5.709 * aa + 0.0186 * aa * aa); } this.aSquared = a; this.aSquaredStar = aa; this.p = p; } + + private double c(double n) { + return .01265 + .1757 / n; + } + + private double g1(double x) { + return sqrt(x) * (1 - x) * (49 * x - 102); + } + + private double g2(double x) { + return -.00022633 + (6.54034 - (14.6538 - (14.458 - (8.259 - 1.91864 * x) * x) * x) * x) * x; + } + + private double g3(double x) { + return -130.2137 + (745.2337 - (1705.091 - (1950.646 - (1116.360 - 255.7844 * x) * x) * x) * x) * x; + } + + private double errfix(double n, double x) { + if (x < c(n)) { + return (.0037 / pow(n, 3) + .00078 / pow(n, 2) + .00006 / n) * g1(x / c(n)); + } else if (x < .8) { + return (.04213 / n + .01365 / pow(n , 2)) * g2((x - c(n)) / (.8 - c(n))); + } else { + return g3(x) / n; + } + } + + private double adinf(double z) { + if (0 < z && z < 2) { + return pow(z, -0.5) * exp(-1.2337141 / z) * (2.00012 + (0.247105 - (.0649821 - (.0347962 - (.0116720 - .00168691 * z) * z) * z) * z) * z); + } else if (z >= 2) { + return exp( -exp(1.0776 - (2.30695 - (.43424 - (.082433 - (.008056 - .0003146 * z) * z) * z) * z) * z)); + } else { + return 0; + } + } + + public double getProbTail(double n, double z) { + return adinf(z) + errfix(n, adinf(z)); + } + + public static void main(String[] args) { + List data = new ArrayList<>(); + + for (int i = 0; i < 500; i++) { +// data.add(RandomUtil.getInstance().nextUniform(0, 1)); + data.add(RandomUtil.getInstance().nextBeta(2, 5)); + } + + GeneralAndersonDarlingTest test = new GeneralAndersonDarlingTest(data, new UniformRealDistribution(0, 1)); + + System.out.println(test.getASquared()); + System.out.println(test.getASquaredStar()); + System.out.println(test.getP()); + System.out.println(test.getProbTail(data.size(), test.getASquaredStar())); + } } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/data/IDataReader.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/data/IDataReader.java deleted file mode 100644 index 38f66cc916..0000000000 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/data/IDataReader.java +++ /dev/null @@ -1,30 +0,0 @@ -package edu.cmu.tetrad.data; - -/** - * Identifies a class that can read data from a file. - * - * @author josephramsey - */ -public interface IDataReader { - - /** - * The delimiter between entries in a line, one of DelimiterType.WHITESPACE, DelimiterType.TAB, DelimiterType.COMMA, - * DelimiterType.COLON - */ - void setDelimiter(DelimiterType delimiterType); - - /** - * True if case IDs are provided in the first column of the data. - * - * @deprecated - */ - void setIdsSupplied(boolean caseIdsPresent); - - /** - * The String identifier of the case ID column. - * - * @deprecated - */ - void setIdLabel(String caseIdsLabel); - -} diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/Edge.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/Edge.java index 374b74cac7..ed6f1ba5c6 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/Edge.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/Edge.java @@ -317,7 +317,7 @@ public final String toString() { } public final int hashCode() { - return 1; + return node1.hashCode() + node2.hashCode(); } /** diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/EdgeListGraph.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/EdgeListGraph.java index cca46a120e..040379594c 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/EdgeListGraph.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/EdgeListGraph.java @@ -20,6 +20,8 @@ /////////////////////////////////////////////////////////////////////////////// package edu.cmu.tetrad.graph; +import edu.cmu.tetrad.data.DataBox; + import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.IOException; @@ -75,6 +77,7 @@ public class EdgeListGraph implements Graph, TripleClassifier { private Set underLineTriples = new HashSet<>(); private Set dottedUnderLineTriples = new HashSet<>(); private Set ambiguousTriples = new HashSet<>(); + private Map> parentsHash = new HashMap<>(); //==============================CONSTUCTORS===========================// @@ -130,6 +133,7 @@ public EdgeListGraph(EdgeListGraph graph) throws IllegalArgumentException { } this.edgesSet = new HashSet<>(graph.edgesSet); this.namesHash = new HashMap<>(graph.namesHash); + this.parentsHash = new HashMap<>(graph.parentsHash); // this.paths = new Paths(this); this.underLineTriples = graph.getUnderLines(); @@ -358,25 +362,29 @@ public Edge getDirectedEdge(Node node1, Node node2) { */ @Override public List getParents(Node node) { - List parents = new ArrayList<>(); - Set edges = this.edgeLists.get(node); + if (!parentsHash.containsKey(node)) { + List parents = new ArrayList<>(); + Set edges = this.edgeLists.get(node); - if (edges == null) { - throw new IllegalArgumentException("Node " + node + " is not in the graph."); - } + if (edges == null) { + throw new IllegalArgumentException("Node " + node + " is not in the graph."); + } - for (Edge edge : edges) { - if (edge == null) continue; + for (Edge edge : edges) { + if (edge == null) continue; - Endpoint endpoint1 = edge.getDistalEndpoint(node); - Endpoint endpoint2 = edge.getProximalEndpoint(node); + Endpoint endpoint1 = edge.getDistalEndpoint(node); + Endpoint endpoint2 = edge.getProximalEndpoint(node); - if (endpoint1 == Endpoint.TAIL && endpoint2 == Endpoint.ARROW) { - parents.add(edge.getDistalNode(node)); + if (endpoint1 == Endpoint.TAIL && endpoint2 == Endpoint.ARROW) { + parents.add(edge.getDistalNode(node)); + } } + + parentsHash.put(node, parents); } - return parents; + return parentsHash.get(node); } /** @@ -578,6 +586,9 @@ public boolean removeEdge(Node node1, Node node2) { removeTriplesNotInGraph(); + parentsHash.remove(node1); + parentsHash.remove(node2); + return removeEdges(edges); } @@ -680,6 +691,9 @@ public boolean addEdge(Edge edge) { this.edgeLists.get(edge.getNode1()).add(edge); this.edgeLists.get(edge.getNode2()).add(edge); this.edgesSet.add(edge); + + this.parentsHash.remove(edge.getNode1()); + this.parentsHash.remove(edge.getNode2()); } if (Edges.isDirectedEdge(edge)) { @@ -810,6 +824,7 @@ public boolean equals(Object o) { public void fullyConnect(Endpoint endpoint) { this.edgesSet.clear(); this.edgeLists.clear(); + this.parentsHash.clear(); for (Node node : this.nodes) { this.edgeLists.put(node, new HashSet<>()); @@ -940,6 +955,9 @@ public boolean removeEdge(Edge edge) { this.edgeLists.put(edge.getNode1(), edgeList1); this.edgeLists.put(edge.getNode2(), edgeList2); + this.parentsHash.remove(edge.getNode1()); + this.parentsHash.remove(edge.getNode2()); + getPcs().firePropertyChange("edgeRemoved", edge, null); return true; } @@ -997,6 +1015,8 @@ public boolean removeNode(Node node) { Set edgeList2 = this.edgeLists.get(node2); edgeList2.remove(edge); this.edgesSet.remove(edge); + this.parentsHash.remove(edge.getNode1()); + this.parentsHash.remove(edge.getNode2()); changed = true; } @@ -1006,6 +1026,7 @@ public boolean removeNode(Node node) { this.edgeLists.remove(node); this.nodes.remove(node); + this.parentsHash.remove(node); this.namesHash.remove(node.getName()); removeTriplesNotInGraph(); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/GraphTransforms.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/GraphTransforms.java index 012a9b4663..50e3929e83 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/GraphTransforms.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/GraphTransforms.java @@ -3,6 +3,7 @@ import edu.cmu.tetrad.data.Knowledge; import edu.cmu.tetrad.search.utils.DagInCpcagIterator; import edu.cmu.tetrad.search.utils.DagToPag; +import edu.cmu.tetrad.search.utils.GraphSearchUtils; import edu.cmu.tetrad.search.utils.MeekRules; import edu.cmu.tetrad.util.CombinationGenerator; import org.jetbrains.annotations.NotNull; @@ -16,19 +17,19 @@ * @author josephramsey */ public class GraphTransforms { - public static Graph dagFromCPDAG(Graph graph) { - return dagFromCPDAG(graph, null); + public static Graph dagFromCpdag(Graph graph) { + return dagFromCpdag(graph, null); } - public static Graph dagFromCPDAG(Graph graph, Knowledge knowledge) { + /** + * Returns a DAG from the given CPDAG. If the given CPDAG is not a PDAG, returns null. + * @param graph the CPDAG + * @param knowledge the knowledge + * @return a DAG from the given CPDAG. If the given CPDAG is not a PDAG, returns null. + */ + public static Graph dagFromCpdag(Graph graph, Knowledge knowledge) { Graph dag = new EdgeListGraph(graph); - for (Edge edge : dag.getEdges()) { - if (Edges.isBidirectedEdge(edge)) { - throw new IllegalArgumentException("That 'cpdag' contains a bidirected edge."); - } - } - MeekRules rules = new MeekRules(); if (knowledge != null) { @@ -213,7 +214,6 @@ public static Graph dagToPag(Graph trueGraph) { return new DagToPag(trueGraph).convert(); } - private static void direct(Node a, Node c, Graph graph) { Edge before = graph.getEdge(a, c); Edge after = Edges.directedEdge(a, c); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/LayoutUtil.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/LayoutUtil.java index dbb476ca16..8f07aa92bb 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/LayoutUtil.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/LayoutUtil.java @@ -182,7 +182,10 @@ private static List> getTiers(Graph graph) { List thisTier = new LinkedList<>(); for (Node node : notFound) { - if (found.containsAll(graph.getParents(node))) { + List nodesInTo = graph.getNodesInTo(node, Endpoint.ARROW); + nodesInTo.removeAll(graph.getNodesOutTo(node, Endpoint.ARROW)); + + if (found.containsAll(nodesInTo)) { thisTier.add(node); } } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/Paths.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/Paths.java index 112506f4aa..393dedc072 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/Paths.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/graph/Paths.java @@ -4,6 +4,7 @@ import edu.cmu.tetrad.search.utils.SepsetMap; import edu.cmu.tetrad.util.SublistGenerator; import edu.cmu.tetrad.util.TaskManager; +import edu.cmu.tetrad.util.TetradLogger; import edu.cmu.tetrad.util.TetradSerializable; import java.util.*; @@ -1588,7 +1589,10 @@ private boolean visibleEdgeHelperVisit(Node c, Node a, Node b, LinkedList public boolean existsDirectedCycle() { for (Node node : graph.getNodes()) { - if (existsDirectedPathFromTo(node, node)) return true; + if (existsDirectedPathFromTo(node, node)) { + TetradLogger.getInstance().forceLogMessage("Cycle found at node " + node.getName() + "."); + return true; + } } return false; } @@ -1706,6 +1710,10 @@ public boolean isMSeparatedFrom(Node node1, Node node2, Set z) { return !isMConnectedTo(node1, node2, z); } + public boolean isMSeparatedFrom(Node node1, Node node2, Set z, Map> ancestors) { + return !isMConnectedTo(node1, node2, z, ancestors); + } + /** * @return true iff there is a semi-directed path from node1 to node2 */ diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/BFci.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/BFci.java index e001129de8..adcd9d6cbd 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/BFci.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/BFci.java @@ -29,6 +29,7 @@ import edu.cmu.tetrad.search.utils.FciOrient; import edu.cmu.tetrad.search.utils.SepsetProducer; import edu.cmu.tetrad.search.utils.SepsetsGreedy; +import edu.cmu.tetrad.util.RandomUtil; import edu.cmu.tetrad.util.TetradLogger; import java.util.List; @@ -36,21 +37,19 @@ import static edu.cmu.tetrad.graph.GraphUtils.gfciExtraEdgeRemovalStep; /** - *

Uses BOSS in place of FGES for the initial step in the GFCI algorithm. - * This tends to produce a accurate PAG than GFCI as a result, for the latent variables case. This is a simple - * substitution; the reference for GFCI is here:

- * - *

J.M. Ogarrio and P. Spirtes and J. Ramsey, "A Hybrid Causal Search Algorithm - * for Latent Variable Models," JMLR 2016. Here, BOSS has been substituted for FGES.

- * - *

BOSS is a an algorithm that is currently being written up for publication, - * so we don't yet have a reference for it.

- * - *

For BOSS only a score is needed, but there are steps in GFCI that require - * a test, so for this method, both a test and a score need to be given.

- * - *

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

+ * Uses BOSS in place of FGES for the initial step in the GFCI algorithm. This tends to produce a accurate PAG than GFCI + * as a result, for the latent variables case. This is a simple substitution; the reference for GFCI is here: + *

+ * J.M. Ogarrio and P. Spirtes and J. Ramsey, "A Hybrid Causal Search Algorithm for Latent Variable Models," JMLR 2016. + * Here, BOSS has been substituted for FGES. + *

+ * BOSS is a an algorithm that is currently being written up for publication, so we don't yet have a reference for it. + *

+ * For BOSS only a score is needed, but there are steps in GFCI that require a test, so for this method, both a test and + * a score need to be given. + *

+ * This class is configured to respect knowledge of forbidden and required edges, including knowledge of temporal + * tiers. * * @author josephramsey * @author bryan andrews @@ -83,6 +82,7 @@ public final class BFci implements IGraphSearch { private int depth = -1; private boolean doDiscriminatingPathRule = true; private boolean bossUseBes = false; + private long seed = -1; /** @@ -109,6 +109,10 @@ public BFci(IndependenceTest test, Score score) { * @return The discovered graph. */ public Graph search() { + if (seed != -1) { + RandomUtil.getInstance().setSeed(seed); + } + List nodes = getIndependenceTest().getVariables(); this.logger.log("info", "Starting FCI algorithm."); @@ -195,20 +199,43 @@ public IndependenceTest getIndependenceTest() { return this.independenceTest; } + /** + * Returns the number of times to restart the search. + * + * @param numStarts The number of times to restart the search. + */ public void setNumStarts(int numStarts) { this.numStarts = numStarts; } + /** + * Sets the depth of the search (for the constraint-based step). + * + * @param depth The depth of the search. + */ public void setDepth(int depth) { this.depth = depth; } + /** + * Sets whether the discriminating path rule should be used. + * + * @param doDiscriminatingPathRule True if the discriminating path rule should be used, false otherwise. + */ public void setDoDiscriminatingPathRule(boolean doDiscriminatingPathRule) { this.doDiscriminatingPathRule = doDiscriminatingPathRule; } + /** + * Sets whether the BES should be used. + * + * @param useBes True if the BES should be used, false otherwise. + */ public void setBossUseBes(boolean useBes) { this.bossUseBes = useBes; } + public void setSeed(long seed) { + this.seed = seed; + } } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Boss.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Boss.java index d2ca4feeb0..d9c08c567a 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Boss.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Boss.java @@ -8,35 +8,35 @@ import edu.cmu.tetrad.search.utils.GrowShrinkTree; import java.util.*; -import java.util.concurrent.*; +import java.util.concurrent.Callable; +import java.util.concurrent.ForkJoinPool; import static edu.cmu.tetrad.util.RandomUtil.shuffle; /** - *

Implements Best Order Score Search (BOSS). The following references are relevant:

- * - *

Lam, W. Y., Andrews, B., & Ramsey, J. (2022, August). Greedy relaxations of the sparsest permutation algorithm. - * In Uncertainty in Artificial Intelligence (pp. 1052-1062). PMLR.

- * - *

Teyssier, M., & Koller, D. (2012). Ordering-based search: A simple and effective algorithm for learning Bayesian - * networks. arXiv preprint arXiv:1207.1429.

- * - *

Solus, L., Wang, Y., & Uhler, C. (2021). Consistency guarantees for greedy permutation-based causal inference - * algorithms. Biometrika, 108(4), 795-814.

- * - *

The BOSS algorithm is based on the idea that implied DAGs for permutations are most optimal in their BIC scores - * when the variables in the permutations are ordered causally--that is, so that that causes in the models come before - * effects in a topological order.

- * - *

This algorithm is implemented as a "plugin-in" algorithm to a PermutationSearch object (see), which deals with - * certain details of knowledge handling that are common to different permutation searches.

- * - *

BOSS, like GRaSP (see), is characterized by high adjacency and orientation precision (especially) and recall for + * Implements Best Order Score Search (BOSS). The following references are relevant: + *

+ * Lam, W. Y., Andrews, B., & Ramsey, J. (2022, August). Greedy relaxations of the sparsest permutation algorithm. + * In Uncertainty in Artificial Intelligence (pp. 1052-1062). PMLR. + *

+ * Teyssier, M., & Koller, D. (2012). Ordering-based search: A simple and effective algorithm for learning Bayesian + * networks. arXiv preprint arXiv:1207.1429. + *

+ * Solus, L., Wang, Y., & Uhler, C. (2021). Consistency guarantees for greedy permutation-based causal inference + * algorithms. Biometrika, 108(4), 795-814. + *

+ * The BOSS algorithm is based on the idea that implied DAGs for permutations are most optimal in their BIC scores when + * the variables in the permutations are ordered causally--that is, so that that causes in the models come before + * effects in a topological order. + *

+ * This algorithm is implemented as a "plugin-in" algorithm to a PermutationSearch object (see), which deals with + * certain details of knowledge handling that are common to different permutation searches. + *

+ * BOSS, like GRaSP (see), is characterized by high adjacency and orientation precision (especially) and recall for * moderate sample sizes. BOSS scales up currently further than GRaSP to larger variable sets and denser graphs and so - * is currently preferable from a practical standpoint, though performance is essentially identical.

- * - *

The algorithm works as follows:

- * + * is currently preferable from a practical standpoint, though performance is essentially identical. + *

+ * The algorithm works as follows: *

    *
  1. Start with an arbitrary ordering.
  2. *
  3. Run the permutation search to find a better ordering.
  4. @@ -44,24 +44,24 @@ *
  5. Optionally, Run BES this CPDAG. *
  6. Return this CPDAG.
  7. *
- * - *

The optional BES step is needed for correctness, though with large + *

+ * The optional BES step is needed for correctness, though with large * models is has very little effect on the output, since nearly all edges - * are already oriented, so a parameter is included to turn that step off.

- * - *

Knowledge can be used with this search. If tiered knowledge is used, + * are already oriented, so a parameter is included to turn that step off. + *

+ * Knowledge can be used with this search. If tiered knowledge is used, * then the procedure is carried out for each tier separately, given the * variables preceding that tier, which allows the Boss algorithm to address * tiered (e.g., time series) problems with larger numbers of variables. * However, knowledge of required and forbidden edges is correctly implemented - * for arbitrary such knowledge.

- * - *

A parameter is included to restart the search a certain number of time. + * for arbitrary such knowledge. + *

+ * A parameter is included to restart the search a certain number of time. * The idea is that the goal is to optimize a BIC score, so if several runs * are done of the algorithm for the same data, the model with the highest - * BIC score should be returned and the others ignored.

- * - *

This class is meant to be used in the context of the PermutationSearch + * BIC score should be returned and the others ignored. + *

+ * This class is meant to be used in the context of the PermutationSearch * class (see). * * @author bryanandrews @@ -71,21 +71,40 @@ * @see Knowledge */ public class Boss implements SuborderSearch { + // The score. private final Score score; + // The variables. private final List variables; + // The parents. private final Map> parents; + // The grow-shrink trees. private Map gsts; + // The set of all variables. private Set all; + // The pool for parallelism. private ForkJoinPool pool; + // The knowledge. private Knowledge knowledge = new Knowledge(); + // The BES algorithm. private BesPermutation bes = null; + // The number of random starts to use. private int numStarts = 1; + // True if the order of the variables in the data should be used for an initial best-order search, false if a random + // permutation should be used. (Subsequence automatic best order runs will use random permutations.) This is + // included so that the algorithm will be capable of outputting the same results with the same data without any + // randomness. private boolean useDataOrder = true; + // True if the grow-shrink trees should be reset after each best-mutation step. private boolean resetAfterBM = false; + // True if the grow-shrink trees should be reset after each restart. private boolean resetAfterRS = true; + // The number of threads to use. private int numThreads = 1; + // True if verbose output should be printed. private List bics; + // The BIC scores. private List times; + // True if verbose output should be printed. private boolean verbose = false; @@ -103,6 +122,15 @@ public Boss(Score score) { } } + /** + * Searches a suborder of the variables. The prefix is the set of variables that must precede the suborder. The + * suborder is the set of variables to be ordered. The gsts is a map from variables to GrowShrinkTrees, which are + * used to cache scores for the variables. The searchSuborder method will update the suborder to be the best + * ordering found. + * @param prefix The prefix of the suborder. + * @param suborder The suborder. + * @param gsts The GrowShrinkTree being used to do caching of scores. + */ @Override public void searchSuborder(List prefix, List suborder, Map gsts) { assert this.numStarts > 0; @@ -129,8 +157,8 @@ public void searchSuborder(List prefix, List suborder, Map 0 && this.resetAfterRS) { - for (Node root: suborder) { - this.gsts.get(root).reset(); + for (Node root : suborder) { + this.gsts.get(root).reset(); } } @@ -196,6 +224,10 @@ public void setUseBes(boolean use) { } } + /** + * Sets the knowledge to be used for the search. + * @param knowledge This knowledge. If null, no knowledge will be used. + */ @Override public void setKnowledge(Knowledge knowledge) { this.knowledge = knowledge; @@ -214,12 +246,20 @@ public void setNumStarts(int numStarts) { this.numStarts = numStarts; } + /** + * Sets whether the grow-shrink trees should be reset after each best-mutation step. + * @param reset True if so. + */ public void setResetAfterBM(boolean reset) { this.resetAfterBM = reset; } + /** + * Sets whether the grow-shrink trees should be reset after each restart. + * @param reset True if so. + */ public void setResetAfterRS(boolean reset) { - this.resetAfterRS = reset; + this.resetAfterRS = reset; } public void setVerbose(boolean verbose) { @@ -253,7 +293,7 @@ public List getTimes() { return this.times; } - /** + /** * True if the order of the variables in the data should be used for an initial best-order search, false if a random * permutation should be used. (Subsequence automatic best order runs will use random permutations.) This is * included so that the algorithm will be capable of outputting the same results with the same data without any @@ -297,14 +337,14 @@ private boolean betterMutationAsync(List prefix, List suborder, Node if (this.resetAfterBM) this.gsts.get(x).reset(); double runningScore = 0; - for (i = with.length - 1 ; i >= 0 ; i--) { + for (i = with.length - 1; i >= 0; i--) { runningScore += with[i]; scores[i] += runningScore; } runningScore = 0; - for (i = 0 ; i < without.length ; i++) { + for (i = 0; i < without.length; i++) { runningScore += without[i]; scores[i + 1] += runningScore; } @@ -323,30 +363,6 @@ private boolean betterMutationAsync(List prefix, List suborder, Node return true; } - private static class Trace implements Callable { - private final GrowShrinkTree gst; - private final Set all; - private final Set prefix; - private final double[] scores; - private final int index; - - Trace(GrowShrinkTree gst, Set all, Set prefix, double[] scores, int index) { - this.gst = gst; - this.all = all; - this.prefix = new HashSet<>(prefix); - this.scores = scores; - this.index = index; - } - - @Override - public Void call() { - double score = gst.trace(this.prefix, this.all); - this.scores[index] = score; - - return null; - } - } - private boolean betterMutation(List prefix, List suborder, Node x) { ListIterator itr = suborder.listIterator(); double[] scores = new double[suborder.size() + 1]; @@ -357,6 +373,8 @@ private boolean betterMutation(List prefix, List suborder, Node x) { int curr = 0; while (itr.hasNext()) { + if (Thread.currentThread().isInterrupted()) return false; + Node z = itr.next(); if (this.knowledge.isRequired(x.getName(), z.getName())) { @@ -423,10 +441,6 @@ private double update(List prefix, List suborder) { return score; } - - // alter this code so that it roughly obeys tiers. - - private void makeValidKnowledgeOrder(List order) { if (this.knowledge.isEmpty()) return; @@ -462,4 +476,31 @@ private void makeValidKnowledgeOrder(List order) { } } } + + + // alter this code so that it roughly obeys tiers. + + private static class Trace implements Callable { + private final GrowShrinkTree gst; + private final Set all; + private final Set prefix; + private final double[] scores; + private final int index; + + Trace(GrowShrinkTree gst, Set all, Set prefix, double[] scores, int index) { + this.gst = gst; + this.all = all; + this.prefix = new HashSet<>(prefix); + this.scores = scores; + this.index = index; + } + + @Override + public Void call() { + double score = gst.trace(this.prefix, this.all); + this.scores[index] = score; + + return null; + } + } } \ No newline at end of file diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/BossLingam.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/BossLingam.java index ed9758a42a..047a6684e6 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/BossLingam.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/BossLingam.java @@ -39,35 +39,33 @@ import java.util.List; /** - *

Implements the BOSS-LiNGAM algorithm which first finds a CPDAG for the variables - * and then uses a non-Gaussian orientation method to orient the undirected edges. The reference is as follows: - * - *

>Hoyer et al., "Causal discovery of linear acyclic models with arbitrary - * distributions," UAI 2008.

- * - *

The test for normality used for residuals is Anderson-Darling, following 'ad.test' - * in the nortest package of R. The default alpha level is 0.05--that is, p values from AD below 0.05 are taken to - * indicate nongaussianity.

- * - *

It is assumed that the CPDAG is the result of a CPDAG search such as PC or GES. In any - * case, it is important that the residuals be independent for ICA to work.

- * - *

This may be replaced by a more general algorithm that allows alternatives for the - * CPDAG search and for the the non-Gaussian orientation method.

- * - *

This class is not configured to respect knowledge of forbidden and required - * edges.

+ * Implements the BOSS-LiNGAM algorithm which first finds a CPDAG for the variables and then uses a non-Gaussian + * orientation method to orient the undirected edges. The reference is as follows: + *

+ * Hoyer et al., "Causal discovery of linear acyclic models with arbitrary distributions," UAI 2008. + *

+ * The test for normality used for residuals is Anderson-Darling, following 'ad.test' in the nortest package of R. The + * default alpha level is 0.05--that is, p values from AD below 0.05 are taken to indicate nongaussianity. + *

+ * It is assumed that the CPDAG is the result of a CPDAG search such as PC or GES. In any case, it is important that the + * residuals be independent for ICA to work. + *

+ * This may be replaced by a more general algorithm that allows alternatives for the CPDAG search and for the the + * non-Gaussian orientation method. + *

+ * This class is not configured to respect knowledge of forbidden and required edges. * * @author peterspirtes * @author patrickhoyer * @author josephramsey */ public class BossLingam { + // The CPDAG whose unoriented edges are to be oriented. private final Graph cpdag; + // The dataset to use. private final DataSet dataSet; + // The p-values of the search. private double[] pValues; - private double alpha = 0.05; - /** * Constructor. @@ -113,7 +111,7 @@ public Graph search() { int i = nodes.indexOf(X); int j = nodes.indexOf(Y); - double lr = Fask.faskLeftRightV2(_data[i], _data[j], true, 0); + double lr = Fask.faskLeftRightV2(_data[i], _data[j], true, 0); if (lr > 0.0) { toOrient.removeEdge(edge); @@ -148,7 +146,7 @@ public void setAlpha(double alpha) { throw new IllegalArgumentException("Alpha is in range [0, 1]"); } - this.alpha = alpha; + // The alpha level for the search. } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Bpc.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Bpc.java index bca013898f..b14c9c7a04 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Bpc.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Bpc.java @@ -34,39 +34,37 @@ /** - *

Implements the Build Pure Clusters (BPC) algorithm, which allows one to identify - * clusters of measured variables in a dataset that are explained by a single latent. The algorithm outputs these - * clusters, which can then be used for further analysis, such as inferring structure over the latents. For the latter, - * see for instance the MimBuild algorithm.

- * - *

The reference for BPC is this:

- * - *

Silva, R., Scheines, R., Glymour, C., Spirtes, P., & Chickering, D. M. (2006). - * Learning the Structure of Linear Latent Variable Models. Journal of Machine Learning Research, 7(2).

- * - *

For a more detailed description of the algorithm, see the paper above. The - * algorithm is based on the idea of finding cliques in the graph of the covariance matrix. The algorithm is initialized - * by finding all maximal cliques in the graph of the covariance matrix. Then, the algorithm iterates over the cliques, - * and for each clique, it tests whether the clique is explained by a single latent. If so, the clique is added to the - * set of clusters. If not, the clique is partitioned into smaller cliques, and the process is repeated for each of the - * smaller cliques. The algorithm stops when all cliques have been tested.

- * - *

Some more References:

- * - *

Silva, R.; Scheines, R.; Spirtes, P.; Glymour, C. (2003). "Learning measurement models". - * Technical report CMU-CALD-03-100, Center for Automated Learning and Discovery, Carnegie Mellon University.

- * - *

Bollen, K. (1990). "Outlier screening and distribution-free test for vanishing tetrads." - * Sociological Methods and Research 19, 80-92.

- * - *

Wishart, J. (1928). "Sampling errors in the theory of two factors". British Journal of - * Psychology 19, 180-187.

- * - *

Bron, C. and Kerbosch, J. (1973) "Algorithm 457: Finding all cliques of an undirected graph". - * Communications of ACM 16, 575-577.

- * - *

This class is not configured to respect knowledge of forbidden and required - * edges.

+ * Implements the Build Pure Clusters (BPC) algorithm, which allows one to identify clusters of measured variables in a + * dataset that are explained by a single latent. The algorithm outputs these clusters, which can then be used for + * further analysis, such as inferring structure over the latents. For the latter, see for instance the MimBuild + * algorithm. + *

+ * The reference for BPC is this: + *

+ * Silva, R., Scheines, R., Glymour, C., Spirtes, P., & Chickering, D. M. (2006). Learning the Structure of Linear + * Latent Variable Models. Journal of Machine Learning Research, 7(2). + *

+ * For a more detailed description of the algorithm, see the paper above. The algorithm is based on the idea of finding + * cliques in the graph of the covariance matrix. The algorithm is initialized by finding all maximal cliques in the + * graph of the covariance matrix. Then, the algorithm iterates over the cliques, and for each clique, it tests whether + * the clique is explained by a single latent. If so, the clique is added to the set of clusters. If not, the clique is + * partitioned into smaller cliques, and the process is repeated for each of the smaller cliques. The algorithm stops + * when all cliques have been tested. + *

+ * Some more References: + *

+ * Silva, R.; Scheines, R.; Spirtes, P.; Glymour, C. (2003). "Learning measurement models". Technical report + * CMU-CALD-03-100, Center for Automated Learning and Discovery, Carnegie Mellon University. + *

+ * Bollen, K. (1990). "Outlier screening and distribution-free test for vanishing tetrads." Sociological Methods and + * Research 19, 80-92. + *

+ * Wishart, J. (1928). "Sampling errors in the theory of two factors". British Journal of Psychology 19, 180-187. + *

+ * Bron, C. and Kerbosch, J. (1973) "Algorithm 457: Finding all cliques of an undirected graph". Communications of ACM + * 16, 575-577. + *

+ * This class is not configured to respect knowledge of forbidden and required edges. * * @author Ricardo Silva * @see Fofc diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Ccd.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Ccd.java index 4c98673ad6..5792fc2c45 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Ccd.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Ccd.java @@ -32,29 +32,28 @@ import java.util.*; /** - *

Implemented the Cyclic Causal Discovery (CCD) algorithm by Thomas Richardson. - * A reference for this is here:

- * - *

Richardson, T. S. (2013). A discovery algorithm for directed cyclic graphs. arXiv - * preprint arXiv:1302.3599.

- * - *

See also Chapter 7 of:

- * - *

Glymour, C. N., & Cooper, G. F. (Eds.). (1999). Computation, causation, and - * discovery. Aaai Press.

- * - *

The graph takes continuous data from a cyclic model as input and returns a cyclic - * PAG graphs, with various types of underlining, that represents a Markov equivalence of the true DAG.

- * - *

This class is not configured to respect knowledge of forbidden and required - * edges.

+ * Implemented the Cyclic Causal Discovery (CCD) algorithm by Thomas Richardson. A reference for this is here: + *

+ * Richardson, T. S. (2013). A discovery algorithm for directed cyclic graphs. arXiv preprint arXiv:1302.3599. + *

+ * See also Chapter 7 of: + *

+ * Glymour, C. N., & Cooper, G. F. (Eds.). (1999). Computation, causation, and discovery. Aaai Press. + *

+ * The graph takes continuous data from a cyclic model as input and returns a cyclic PAG graphs, with various types of + * underlining, that represents a Markov equivalence of the true DAG. + *

+ * This class is not configured to respect knowledge of forbidden and required edges. * * @author Frank C. Wimberly * @author josephramsey */ public final class Ccd implements IGraphSearch { + // The independence test to be used. private final IndependenceTest independenceTest; + // The nodes in the graph. private final List nodes; + // Whether the R1 rule should be applied. private boolean applyR1; /** diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Cfci.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Cfci.java index 69e575f82f..5476d18a1b 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Cfci.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Cfci.java @@ -34,12 +34,11 @@ /** - *

Adjusts FCI (see) to use conservative orientation as in CPC (see). Because the - * collider orientation is conservative, there may be ambiguous triples; these may be retrieved using that accessor - * method.

- * - *

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

+ * Adjusts FCI (see) to use conservative orientation as in CPC (see). Because the collider orientation is conservative, + * there may be ambiguous triples; these may be retrieved using that accessor method. + *

+ * This class is configured to respect knowledge of forbidden and required edges, including knowledge of temporal + * tiers. * * @author josephramsey * @see Fci @@ -49,55 +48,33 @@ */ public final class Cfci implements IGraphSearch { - /** - * The SepsetMap being constructed. - */ + // The SepsetMap being constructed. private final SepsetMap sepsets = new SepsetMap(); - /** - * The variables to search over (optional) - */ + // The variables to search over (optional) private final List variables = new ArrayList<>(); - /** - * The independence test. - */ + // The independence test. private final IndependenceTest independenceTest; - /** - * The logger to use. - */ + // The logger to use. private final TetradLogger logger = TetradLogger.getInstance(); - /** - * The PAG being constructed. - */ + // The PAG being constructed. private Graph graph; - /** - * The background knowledge. - */ + // The background knowledge. private Knowledge knowledge = new Knowledge(); - /** - * Flag for complete rule set, true if you should use complete rule set, false otherwise. - */ + // Flag for complete rule set, true if you should use complete rule set, false otherwise. private boolean completeRuleSetUsed = true; - /** - * True iff the possible msep search is done. - */ + // True iff the possible msep search is done. private boolean possibleMsepSearchDone = true; - /** - * The maximum length for any discriminating path. -1 if unlimited; otherwise, a positive integer. - */ + // The maximum length for any discriminating path. -1 if unlimited; otherwise, a positive integer. private int maxReachablePathLength = -1; - /** - * Set of ambiguous unshielded triples. - */ + // Set of ambiguous unshielded triples. private Set ambiguousTriples; - /** - * The depth for the fast adjacency search. - */ + // The depth for the fast adjacency search. private int depth = -1; - /** - * Elapsed time of last search. - */ + // Elapsed time of last search. private long elapsedTime; + // Whether verbose output (about independencies) is output. private boolean verbose; + // Whether to do the discriminating path rule. private boolean doDiscriminatingPathRule; diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/CheckKnowledge.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/CheckKnowledge.java new file mode 100644 index 0000000000..8889df82dd --- /dev/null +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/CheckKnowledge.java @@ -0,0 +1,81 @@ +package edu.cmu.tetrad.search; + +import edu.cmu.tetrad.data.Knowledge; +import edu.cmu.tetrad.data.KnowledgeEdge; +import edu.cmu.tetrad.graph.Edge; +import edu.cmu.tetrad.graph.Edges; +import edu.cmu.tetrad.graph.Graph; +import edu.cmu.tetrad.graph.Node; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +/** + * Identifies violations of knowledge for a given graph. Both forbidden and required knowledge is checked, by separate + * methods. Sorted lists of edges violating knowledge are returned. + * + * @author josephramsey + */ +public class CheckKnowledge { + + /** + * Private constructor to prevent instantiation. + */ + private CheckKnowledge() { + } + + /** + * Returns a sorted list of edges that violate the given knowledge. + * + * @param graph the graph. + * @param knowledge the knowledge. + * @return a sorted list of edges that violate the given knowledge. + */ + public static List forbiddenViolations(Graph graph, Knowledge knowledge) { + List forbiddenViolations = new ArrayList<>(); + + for (Edge edge : graph.getEdges()) { + if (edge.isDirected()) { + Node x = Edges.getDirectedEdgeTail(edge); + Node y = Edges.getDirectedEdgeHead(edge); + + if (knowledge.isForbidden(x.getName(), y.getName())) { + forbiddenViolations.add(edge); + } + } + } + + Collections.sort(forbiddenViolations); + + return forbiddenViolations; + } + + /** + * Returns a sorted list of edges that are required by knowledge but which do not appear in the graph. + * + * @param graph the graph. + * @param knowledge the knowledge. + * @return a sorted list of edges that are required by knowledge but which do not appear in the graph. + */ + public static List requiredViolations(Graph graph, Knowledge knowledge) { + List requiredViolations = new ArrayList<>(); + + Iterator knowledgeEdgeIterator = knowledge.requiredEdgesIterator(); + + while (knowledgeEdgeIterator.hasNext()) { + KnowledgeEdge edge = knowledgeEdgeIterator.next(); + Node x = graph.getNode(edge.getFrom()); + Node y = graph.getNode(edge.getTo()); + + if (!graph.containsEdge(Edges.directedEdge(x, y))) { + requiredViolations.add(Edges.directedEdge(x, y)); + } + } + + Collections.sort(requiredViolations); + + return requiredViolations; + } +} diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/CompositeIndependenceTest.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/CompositeIndependenceTest.java new file mode 100644 index 0000000000..5f18b940cb --- /dev/null +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/CompositeIndependenceTest.java @@ -0,0 +1,41 @@ +package edu.cmu.tetrad.search; + +import edu.cmu.tetrad.data.DataModel; +import edu.cmu.tetrad.graph.Node; +import edu.cmu.tetrad.search.test.IndependenceResult; + +import java.util.List; +import java.util.Set; + +public class CompositeIndependenceTest implements IndependenceTest { + private final IndependenceTest[] independenceTests; + + public CompositeIndependenceTest(IndependenceTest[] independenceTests) { + this.independenceTests = independenceTests; + } + + @Override + public IndependenceResult checkIndependence(Node x, Node y, Set z) { + return null; + } + + @Override + public List getVariables() { + return null; + } + + @Override + public DataModel getData() { + return null; + } + + @Override + public boolean isVerbose() { + return false; + } + + @Override + public void setVerbose(boolean verbose) { + + } +} diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Cstar.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Cstar.java index df608c89e7..f2076b5e9b 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Cstar.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Cstar.java @@ -16,33 +16,32 @@ import java.util.concurrent.*; /** - *

Implements the CStaR algorithm (Stekhoven et al., 2012), which finds a CPDAG of that - * data and then tries all orientations of the undirected edges about a variable in the CPDAG to estimate a minimum - * bound on the effect for a given edge. Some references include the following:

- * - *

Stekhoven, D. J., Moraes, I., Sveinbjörnsson, G., Hennig, L., Maathuis, M. H., and - * Bühlmann, P. (2012). Causal stability ranking. Bioinformatics, 28(21), 2819-2823.

- * - *

Meinshausen, N., and Bühlmann, P. (2010). Stability selection. Journal of the Royal - * Statistical Society: Series B (Statistical Methodology), 72(4), 417-473.

- * - *

Colombo, D., and Maathuis, M. H. (2014). Order-independent constraint-based causal - * structure learning. The Journal of Machine Learning Research, 15(1), 3741-3782.

- * - *

This class is not configured to respect knowledge of forbidden and required - * edges.

+ * Implements the CStaR algorithm (Stekhoven et al., 2012), which finds a CPDAG of that data and then tries all + * orientations of the undirected edges about a variable in the CPDAG to estimate a minimum bound on the effect for a + * given edge. Some references include the following: + *

+ * Stekhoven, D. J., Moraes, I., Sveinbjörnsson, G., Hennig, L., Maathuis, M. H., and Bühlmann, P. (2012). Causal + * stability ranking. Bioinformatics, 28(21), 2819-2823. + *

+ * Meinshausen, N., and Bühlmann, P. (2010). Stability selection. Journal of the Royal Statistical Society: Series B + * (Statistical Methodology), 72(4), 417-473. + *

+ * Colombo, D., and Maathuis, M. H. (2014). Order-independent constraint-based causal structure learning. The Journal of + * Machine Learning Research, 15(1), 3741-3782. + *

+ * This class is not configured to respect knowledge of forbidden and required edges. * * @author josephramsey * @see Ida */ public class Cstar { + private final IndependenceWrapper test; + private final ScoreWrapper score; + private final Parameters parameters; private boolean parallelized = false; private int numSubsamples = 30; private int topBracket = 5; private double selectionAlpha = 0.0; - private final IndependenceWrapper test; - private final ScoreWrapper score; - private final Parameters parameters; private CpdagAlgorithm cpdagAlgorithm = CpdagAlgorithm.PC_STABLE; private SampleStyle sampleStyle = SampleStyle.SUBSAMPLE; private boolean verbose; @@ -600,6 +599,7 @@ private Graph getPatternFges(DataSet sample) { private Graph getPatternBoss(DataSet sample) { Score score = this.score.getScore(sample, parameters); PermutationSearch boss = new PermutationSearch(new Boss(score)); + boss.setSeed(parameters.getLong(Params.SEED)); return boss.search(); } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Dagma.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Dagma.java index dc717c05c0..56be90398c 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Dagma.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Dagma.java @@ -26,34 +26,24 @@ import edu.cmu.tetrad.graph.Graph; import edu.cmu.tetrad.graph.Node; import edu.cmu.tetrad.search.utils.MeekRules; -import org.apache.commons.math3.linear.RealMatrix; import org.apache.commons.math3.linear.LUDecomposition; +import org.apache.commons.math3.linear.RealMatrix; -import java.util.*; +import java.util.List; import static org.apache.commons.math3.linear.MatrixUtils.*; import static org.apache.commons.math3.util.FastMath.*; /** - *

Implements the DAGMA algorithm. The reference is here:

- * - *

NEEDS DOCUMENTATION

+ * Implements the DAGMA algorithm. The reference is here: + *

+ * NEEDS DOCUMENTATION * * @author bryanandrews */ public class Dagma { - private RealMatrix cov; - private List variables; - private RealMatrix I; - private int d; - - private double lambda1; - private double wThreshold; - private boolean cpdag; - private final double[] T; - private final double muInit; private final double muFactor; private final int warmIter; @@ -63,6 +53,13 @@ public class Dagma { private final double b1; private final double b2; private final double tol; + private final RealMatrix cov; + private final List variables; + private final RealMatrix I; + private final int d; + private double lambda1; + private double wThreshold; + private boolean cpdag; /** @@ -80,7 +77,7 @@ public Dagma(DataSet dataset) { this.cpdag = true; // M-matrix s values - this.T = new double[] {1.0, .9, .8, .7}; + this.T = new double[]{1.0, .9, .8, .7}; // central path coefficient and decay factor this.muInit = 1.0; @@ -91,8 +88,8 @@ public Dagma(DataSet dataset) { this.maxIter = 70000; this.lr = 3e-4; this.checkpoint = 1000; - this.b1=0.99; - this.b2=0.999; + this.b1 = 0.99; + this.b2 = 0.999; this.tol = 1e-6; } @@ -266,10 +263,10 @@ private RealMatrix getMMatrix(RealMatrix W, double s) { RealMatrix M = this.I.scalarMultiply(s); for (int i = 0; i < this.d; i++) { - for (int j = 0; j < this.d; j++) { - M.addToEntry(i, j, -W.getEntry(i, j) * W.getEntry(i, j)); - } + for (int j = 0; j < this.d; j++) { + M.addToEntry(i, j, -W.getEntry(i, j) * W.getEntry(i, j)); } + } return M; } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Demixer.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Demixer.java index b3854ed823..f8acaa5af5 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Demixer.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Demixer.java @@ -16,19 +16,34 @@ * @author Madelyn Glymour */ public class Demixer { - + // number of variables in the data set private final int numVars; + // number of cases in the data set private final int numCases; - private final int numClusters; // number of clusters + // number of clusters + private final int numClusters; + // the data set private final DataSet data; - private final double[][] dataArray; // v-by-n data matrix + // the data set as a double array + private final double[][] dataArray; + // the means of each variable for each model private final Matrix[] variances; - private final double[][] meansArray; // k-by-v matrix representing means for each variable for each of k models - private final Matrix[] variancesArray; // k-by-v-by-v matrix representing covariance matrix for each of k models - private final double[] weightsArray; // array of length k representing weights for each model - private final double[][] gammaArray; // k-by-n matrix representing gamma for each data case in each model + // the means of each variable for each model + private final double[][] meansArray; + // the variances of each variable for each model + private final Matrix[] variancesArray; + // the weights of each model + private final double[] weightsArray; + // the gamma values for each case in each model + private final double[][] gammaArray; + // whether the algorithm has been run private boolean demixed = false; + /** + * Constructor. Initializes the means, weights, and covariance matrices for each model. + * @param data the data set + * @param k the number of models + */ public Demixer(DataSet data, int k) { this.numClusters = k; this.data = data; @@ -61,6 +76,22 @@ public Demixer(DataSet data, int k) { } } + static double getVar(int i, int v, int v2, int numCases, double[][] gammaArray, double[][] dataArray, double[][] meansArray) { + double varNumerator; + double varDivisor; + double var; + varNumerator = 0; + varDivisor = 0; + + for (int j = 0; j < numCases; j++) { + varNumerator += gammaArray[i][j] * (dataArray[j][v] - meansArray[i][v]) * (dataArray[j][v2] - meansArray[i][v2]); + varDivisor += gammaArray[i][j]; + } + + var = varNumerator / varDivisor; + return var; + } + /* * Runs the E-M algorithm iteratively until the weights array converges. Returns a MixtureModel object containing * the final values of the means, covariance matrices, weights, and gammas arrays. @@ -203,22 +234,6 @@ private void maximization() { } - static double getVar(int i, int v, int v2, int numCases, double[][] gammaArray, double[][] dataArray, double[][] meansArray) { - double varNumerator; - double varDivisor; - double var; - varNumerator = 0; - varDivisor = 0; - - for (int j = 0; j < numCases; j++) { - varNumerator += gammaArray[i][j] * (dataArray[j][v] - meansArray[i][v]) * (dataArray[j][v2] - meansArray[i][v2]); - varDivisor += gammaArray[i][j]; - } - - var = varNumerator / varDivisor; - return var; - } - /* * For an input case and model, returns the value of the model's normal PDF for that case, using the current * estimations of the means and covariance matrix diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/DirectLingam.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/DirectLingam.java index 70675a83d2..5155f8d529 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/DirectLingam.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/DirectLingam.java @@ -34,27 +34,30 @@ import static org.apache.commons.math3.util.FastMath.*; /** - *

Implements the Direct-LiNGAM algorithm. The reference is here:

- * - *

S. Shimizu, T. Inazumi, Y. Sogawa, A. Hyvärinen, Y. Kawahara, T. Washio, P. O. Hoyer and K. Bollen. - * DirectLiNGAM: A direct method for learning a linear non-Gaussian structural equation model. Journal of Machine - * Learning Research, 12(Apr): 1225–1248, 2011.

- * - *

A. Hyvärinen and S. M. Smith. Pairwise likelihood ratios for estimation of non-Gaussian - * structural evaluation models. Journal of Machine Learning Research 14:111-152, 2013.

- * - *

NEEDS DOCUMENTATION

+ * Implements the Direct-LiNGAM algorithm. The reference is here: + *

+ * S. Shimizu, T. Inazumi, Y. Sogawa, A. Hyvärinen, Y. Kawahara, T. Washio, P. O. Hoyer and K. Bollen. DirectLiNGAM: A + * direct method for learning a linear non-Gaussian structural equation model. Journal of Machine Learning Research, + * 12(Apr): 1225–1248, 2011. + *

+ * A. Hyvärinen and S. M. Smith. Pairwise likelihood ratios for estimation of non-Gaussian structural evaluation models. + * Journal of Machine Learning Research 14:111-152, 2013. * * @author bryanandrews */ public class DirectLingam { - + // the data set private final DataSet dataset; + // the variables private final List variables; + // the grow-shrink trees private final Map gsts; /** * Constructor. + * + * @param dataset the data set + * @param score the score */ public DirectLingam(DataSet dataset, Score score) { this.dataset = dataset; @@ -70,7 +73,9 @@ public DirectLingam(DataSet dataset, Score score) { } /** - * NEEDS DOCUMENTATION + * Performs the search. Returns a graph. + * + * @return a graph */ public Graph search() { List U = new ArrayList<>(this.variables); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/FactorAnalysis.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/FactorAnalysis.java index 0fa17ed559..73986adb59 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/FactorAnalysis.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/FactorAnalysis.java @@ -33,28 +33,28 @@ import static org.apache.commons.math3.util.FastMath.abs; /** - *

Implements the classical Factor Analysis algorithm. Some references include:

- *

Horst, P. (1965). Factor analysis of data matrices. Holt, Rinehart and Winston. - * This work has good specifications and explanations of factor analysis algorithm and methods of communality - * estimation.

- * - *

Rummel, R. J. (1988). Applied factor analysis. Northwestern University Press. This - * book is a good companion to the book listed above. While it doesn't specify any actual algorithm, it has a great - * introduction to the subject that gives the reader a good appreciation of the philosophy and the mathematics behind - * factor analysis.

- * - *

This class is not configured to respect knowledge of forbidden and required - * edges.

+ * Implements the classical Factor Analysis algorithm. Some references include: Horst, P. (1965). Factor analysis of + * data matrices. Holt, Rinehart and Winston. This work has good specifications and explanations of factor analysis + * algorithm and methods of communality estimation. + *

+ * Rummel, R. J. (1988). Applied factor analysis. Northwestern University Press. This book is a good companion to the + * book listed above. While it doesn't specify any actual algorithm, it has a great introduction to the subject that + * gives the reader a good appreciation of the philosophy and the mathematics behind factor analysis. + *

+ * This class is not configured to respect knowledge of forbidden and required edges. * * @author Mike Freenor */ public class FactorAnalysis { + // the covariance matrix private final CovarianceMatrix covariance; - // method-specific fields that get used private LinkedList factorLoadingVectors; + // the threshold for the algorithm private double threshold = 0.001; + // the number of factors to find private int numFactors = 2; + // the residual matrix private Matrix residual; /** @@ -75,80 +75,33 @@ public FactorAnalysis(DataSet dataSet) { this.covariance = new CovarianceMatrix(dataSet); } - - //designed for normalizing a vector. - //as usual, vectors are treated as matrices to simplify operations elsewhere - private static Matrix normalizeRows(Matrix matrix) { - LinkedList normalizedRows = new LinkedList<>(); - for (int i = 0; i < matrix.getNumRows(); i++) { - Vector vector = matrix.getRow(i); - Matrix colVector = new Matrix(matrix.getNumColumns(), 1); - for (int j = 0; j < matrix.getNumColumns(); j++) - colVector.set(j, 0, vector.get(j)); - - normalizedRows.add(FactorAnalysis.normalizeVector(colVector)); - } - - Matrix result = new Matrix(matrix.getNumRows(), matrix.getNumColumns()); - for (int i = 0; i < matrix.getNumRows(); i++) { - Matrix normalizedRow = normalizedRows.get(i); - for (int j = 0; j < matrix.getNumColumns(); j++) { - result.set(i, j, normalizedRow.get(j, 0)); - } - } - - return result; - } - - private static Matrix normalizeVector(Matrix vector) { - double scalar = FastMath.sqrt(vector.transpose().times(vector).get(0, 0)); - return vector.scalarMult(1.0 / scalar); - } - - private static Matrix matrixExp(Matrix matrix, double exponent) { - Matrix result = new Matrix(matrix.getNumRows(), matrix.getNumColumns()); - for (int i = 0; i < matrix.getNumRows(); i++) { - for (int j = 0; j < matrix.getNumColumns(); j++) { - result.set(i, j, FastMath.pow(matrix.get(i, j), exponent)); - } - } - return result; - } - /** * Successive method with residual matrix. *

- * This algorithm makes use of a helper algorithm. - * Together, they solve for an unrotated factor loading matrix. + * This algorithm makes use of a helper algorithm. Together, they solve for an unrotated factor loading matrix. *

* This method calls upon its helper to find column vectors, with which it constructs its factor loading matrix. * Upon receiving each successive column vector from its helper method, it makes sure that we want to keep this - * vector instead of discarding it. - * After keeping a vector, a residual matrix is calculated, upon which solving for + * vector instead of discarding it. After keeping a vector, a residual matrix is calculated, upon which solving for * the next column vector is directly dependent. *

* We stop looking for new vectors either when we've accounted for close to all the variance in the original * correlation matrix, or when the "d scalar" for a new vector is less than 1 (the d-scalar is the corresponding * diagonal for the factor loading matrix -- thus, when it's less than 1, the vector we've solved for barely - * accounts for any more variance). - * This means we've already "pulled out" all the variance we can from the - * residual matrix, and we should stop as further factors don't explain much more - * (and serve to complicate the - * model). + * accounts for any more variance). This means we've already "pulled out" all the variance we can from the residual + * matrix, and we should stop as further factors don't explain much more (and serve to complicate the model). *

* PSEUDO-CODE: *

* 0th Residual Matrix = Original Correlation Matrix Ask helper for the 1st factor (first column vector in our - * factor loading vector) Add 1st factor's d-scalar - * (for i'th factor, call its d-scalar the i'th d-scalar) to a list + * factor loading vector) Add 1st factor's d-scalar (for i'th factor, call its d-scalar the i'th d-scalar) to a list * of d-scalars. *

* While the ratio of the sum of d-scalars to the trace of the original correlation matrix is less than .99 (in * other words, while we haven't accounted for practically all the variance): *

* i'th residual matrix = (i - 1)'th residual matrix SUBTRACT the major product moment of (i - 1)'th factor loading - * vector Ask helper for i'th factor If i'th factor's d-value is less than 1, throw it out and end loop. - * Otherwise, + * vector Ask helper for i'th factor If i'th factor's d-value is less than 1, throw it out and end loop. Otherwise, * add it to the factor loading matrix and continue loop. *

* END PSEUDO-CODE @@ -286,8 +239,6 @@ public Matrix successiveFactorVarimax(Matrix factorLoadingMatrix) { return result; } - // ------------------Private methods-------------------// - /** * Sets the threshold. * @@ -315,21 +266,56 @@ public Matrix getResidual() { return this.residual; } + + //designed for normalizing a vector. + //as usual, vectors are treated as matrices to simplify operations elsewhere + private static Matrix normalizeRows(Matrix matrix) { + LinkedList normalizedRows = new LinkedList<>(); + for (int i = 0; i < matrix.getNumRows(); i++) { + Vector vector = matrix.getRow(i); + Matrix colVector = new Matrix(matrix.getNumColumns(), 1); + for (int j = 0; j < matrix.getNumColumns(); j++) + colVector.set(j, 0, vector.get(j)); + + normalizedRows.add(FactorAnalysis.normalizeVector(colVector)); + } + + Matrix result = new Matrix(matrix.getNumRows(), matrix.getNumColumns()); + for (int i = 0; i < matrix.getNumRows(); i++) { + Matrix normalizedRow = normalizedRows.get(i); + for (int j = 0; j < matrix.getNumColumns(); j++) { + result.set(i, j, normalizedRow.get(j, 0)); + } + } + + return result; + } + + private static Matrix normalizeVector(Matrix vector) { + double scalar = FastMath.sqrt(vector.transpose().times(vector).get(0, 0)); + return vector.scalarMult(1.0 / scalar); + } + + private static Matrix matrixExp(Matrix matrix, double exponent) { + Matrix result = new Matrix(matrix.getNumRows(), matrix.getNumColumns()); + for (int i = 0; i < matrix.getNumRows(); i++) { + for (int j = 0; j < matrix.getNumColumns(); j++) { + result.set(i, j, FastMath.pow(matrix.get(i, j), exponent)); + } + } + return result; + } + /** - * Helper method for the basic structure successive factor method above. - * Takes a residual matrix and an approximation - * vector, and finds both the factor loading vector and the "d scalar" - * which is used to determine the amount of - * total variance accounted for so far. + * Helper method for the basic structure successive factor method above. Takes a residual matrix and an + * approximation vector, and finds both the factor loading vector and the "d scalar" which is used to determine the + * amount of total variance accounted for so far. *

- * The helper takes, to begin with, the unit vector as its approximation to the factor column vector. - * With each - * iteration, it approximates a bit closer -- - * the d-scalar for each successive step eventually converges to a value + * The helper takes, to begin with, the unit vector as its approximation to the factor column vector. With each + * iteration, it approximates a bit closer -- the d-scalar for each successive step eventually converges to a value * (provably). *

- * Thus, the ratio between the last iteration's d-scalar and this iteration's d-scalar should approach 1. - * When this + * Thus, the ratio between the last iteration's d-scalar and this iteration's d-scalar should approach 1. When this * ratio gets sufficiently close to 1, the algorithm halts and returns its getModel approximation. *

* Important to note: the residual matrix stays fixed for this entire algorithm. @@ -346,8 +332,7 @@ public Matrix getResidual() { * times yet, a failsafe): *

* i'th U Vector = residual matrix * (i - 1)'th factor loading i'th L Scalar = transpose((i - 1)'th factor loading) - * * i'th U Vector i'th D Scalar = square root(i'th L Scalar) - * i'th factor loading = i'th U Vector / i'th D Scalar + * * i'th U Vector i'th D Scalar = square root(i'th L Scalar) i'th factor loading = i'th U Vector / i'th D Scalar *

* Return the final i'th factor loading as our best approximation. */ diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Fas.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Fas.java index 8942219381..b14950acb5 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Fas.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Fas.java @@ -34,27 +34,25 @@ import java.util.*; /** - *

Implements the Fast Adjacency Search (FAS), which is the adjacency search of the PC algorithm (see). This is a - * useful algorithm in many contexts, including as the first step of FCI (see).

- * - *

The idea of FAS is that 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.

- * - *

FAS may optionally use a heuristic from Causation, Prediction and Search, which (like PC-Stable) - * renders the output invariant to the order of the input variables.

- * - *

This algorithm was described in the earlier edition of this book:

- * - *

Spirtes, P., Glymour, C. N., Scheines, R., & Heckerman, D. (2000). Causation, prediction, and search. MIT - * press.

- * - *

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

+ * Implements the Fast Adjacency Search (FAS), which is the adjacency search of the PC algorithm (see). This is a useful + * algorithm in many contexts, including as the first step of FCI (see). + *

+ * The idea of FAS is that 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. + *

+ * FAS may optionally use a heuristic from Causation, Prediction and Search, which (like PC-Stable) renders the output + * invariant to the order of the input variables. + *

+ * This algorithm was described in the earlier edition of this book: + *

+ * Spirtes, P., Glymour, C. N., Scheines, R., & Heckerman, D. (2000). Causation, prediction, and search. MIT press. + *

+ * This class is configured to respect knowledge of forbidden and required edges, including knowledge of temporal + * tiers. * * @author peterspirtes * @author clarkglymour @@ -64,19 +62,29 @@ * @see Knowledge */ public class Fas implements IFas { + // The test to be used for conditional independence tests. private final IndependenceTest test; + // The logger. private final TetradLogger logger = TetradLogger.getInstance(); + // The knowledge. private Knowledge knowledge = new Knowledge(); + // The number of independence tests that were done. private int numIndependenceTests; + // The sepsets that were discovered in the search. private SepsetMap sepset = new SepsetMap(); + // The heuristic to use. private PcCommon.PcHeuristicType heuristic = PcCommon.PcHeuristicType.NONE; + // The depth of the search. private int depth = 1000; + // Whether the stable adjacency search should be used. private boolean stable = true; + // The elapsed time of the search. private long elapsedTime = 0L; + // Whether verbose output should be printed. private PrintStream out = System.out; + // Whether verbose output should be printed. private boolean verbose = false; - /** * Constructor. * @@ -99,10 +107,10 @@ public Graph search() { /** * 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 + * 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. * * @param nodes A list of nodes to search over. @@ -175,7 +183,9 @@ public Graph search(List nodes) { } for (int d = 0; d <= _depth; d++) { - System.out.println("Depth: " + d); + if (verbose) { + System.out.println("Depth: " + d); + } boolean more; @@ -321,11 +331,11 @@ public void setPcHeuristicType(PcCommon.PcHeuristicType pcHeuristic) { } /** - *

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.

+ * 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. */ diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Fasd.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Fasd.java index 01056c1fe4..79277d689a 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Fasd.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Fasd.java @@ -27,20 +27,20 @@ import edu.cmu.tetrad.search.utils.LogUtilsSearch; import edu.cmu.tetrad.search.utils.SepsetMap; import edu.cmu.tetrad.util.ChoiceGenerator; +import edu.cmu.tetrad.util.NumberFormatUtil; import edu.cmu.tetrad.util.TetradLogger; import java.io.PrintStream; -import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.*; /** - *

Adjusts FAS (see) for the deterministic case by refusing to removed edges - * based on conditional independence tests that are judged to be deterministic. That is, if X _||_ Y | Z, but Z - * determines X or Y, then the edge X---Y is not removed.

- * - *

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

+ * Adjusts FAS (see) for the deterministic case by refusing to removed edges based on conditional independence tests + * that are judged to be deterministic. That is, if X _||_ Y | Z, but Z determines X or Y, then the edge X---Y is not + * removed. + *

+ * This class is configured to respect knowledge of forbidden and required edges, including knowledge of temporal + * tiers. * * @author peterspirtes * @author josephramsey. @@ -49,49 +49,31 @@ */ public class Fasd implements IFas { - /** - * The independence test. This should be appropriate to the types - */ + // The independence test. This should be appropriate to the types private final IndependenceTest test; - /** - * The logger, by default the empty logger. - */ + // The logger, by default the empty logger. private final TetradLogger logger = TetradLogger.getInstance(); - private final NumberFormat nf = new DecimalFormat("0.00E0"); - /** - * The search graph. It is assumed going in that all 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. - */ + // The number formatter. + private final NumberFormat nf = NumberFormatUtil.getInstance().getNumberFormat(); + // The search graph. It is assumed going in that all 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; - /** - * Specification of which edges are forbidden or required. - */ + // 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. - */ + // 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. - */ + // The number of independence tests. private int numIndependenceTests; - /** - * The sepsets found during the search. - */ + // The sepsets found during the search. private SepsetMap sepset = new SepsetMap(); - /** - * The depth 0 graph, specified initially. - */ + // The depth 0 graph, specified initially. private Graph externalGraph; - /** - * True iff verbose output should be printed. - */ + // True iff verbose output should be printed. private boolean verbose; - + // The output stream. private PrintStream out = System.out; - /** * Constructs a new FastAdjacencySearch. * @@ -104,10 +86,10 @@ public Fasd(IndependenceTest test) { /** * 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 + * 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 graph which indicates which variables are independent conditional on which other variables @@ -299,7 +281,6 @@ private boolean searchAtDepth0(List nodes, IndependenceTest test, MapImplements the FASK (Fast Adjacency Skewness) algorithm, which makes decisions for adjacency - * and orientation using a combination of conditional independence testing, judgments of nonlinear adjacency, and - * pairwise orientation due to non-Gaussianity. The reference is this:

- * - *

Sanchez-Romero, R., Ramsey, J. D., Zhang, K., Glymour, M. R., Huang, B., and Glymour, C. - * (2019). Estimating feedforward and feedback effective connections from fMRI time series: Assessments of statistical - * methods. Network Neuroscience, 3(2), 274-30

- * - *

Some adjustments have been made in some ways from that version, and some additional pairwise options - * have been added from this reference:

- * - *

Hyvärinen, A., and Smith, S. M. (2013). Pairwise likelihood ratios for estimation of non-Gaussian structural - * equation models. Journal of Machine Learning Research, 14(Jan), 111-152.

- * - *

This method (and the Hyvarinen and Smith methods) make the assumption that the data are generated by - * a linear, non-Gaussian causal process and attempts to recover the causal graph for that process. They do not attempt - * to recover the parametrization of this graph; for this a separate estimation algorithm would be needed, such as - * linear regression regressing each node onto its parents. A further assumption is made, that there are no latent - * common causes of the algorithm. This is not a constraint on the pairwise orientation methods, since they orient with - * respect only to the two variables at the endpoints of an edge and so are happy with all other variables being - * considered latent with respect to that single edge. However, if the built-in adjacency search is used (FAS-Stable), - * the existence of latents will throw this method off.

- * + * Implements the FASK (Fast Adjacency Skewness) algorithm, which makes decisions for adjacency and orientation using a + * combination of conditional independence testing, judgments of nonlinear adjacency, and pairwise orientation due to + * non-Gaussianity. The reference is this: + *

+ * Sanchez-Romero, R., Ramsey, J. D., Zhang, K., Glymour, M. R., Huang, B., and Glymour, C. (2019). Estimating + * feedforward and feedback effective connections from fMRI time series: Assessments of statistical methods. Network + * Neuroscience, 3(2), 274-30 + *

+ * Some adjustments have been made in some ways from that version, and some additional pairwise options have been added + * from this reference: + *

+ * Hyvärinen, A., and Smith, S. M. (2013). Pairwise likelihood ratios for estimation of non-Gaussian structural equation + * models. Journal of Machine Learning Research, 14(Jan), 111-152. + *

+ * This method (and the Hyvarinen and Smith methods) make the assumption that the data are generated by a linear, + * non-Gaussian causal process and attempts to recover the causal graph for that process. They do not attempt to recover + * the parametrization of this graph; for this a separate estimation algorithm would be needed, such as linear + * regression regressing each node onto its parents. A further assumption is made, that there are no latent common + * causes of the algorithm. This is not a constraint on the pairwise orientation methods, since they orient with respect + * only to the two variables at the endpoints of an edge and so are happy with all other variables being considered + * latent with respect to that single edge. However, if the built-in adjacency search is used (FAS-Stable), the + * existence of latents will throw this method off. *

* As was shown in the Hyvarinen and Smith paper above, FASK works quite well even if the graph contains feedback loops * in most configurations, including 2-cycles. 2-cycles can be detected fairly well if the FASK left-right rule is @@ -124,10 +123,9 @@ * concat_BOLDfslfilter_60_FullMacaque.txt --prefix Fask_Test_MacaqueFull --algorithm fask --faskAdjacencyMethod 1 * --depth -1 --test sem-bic-test --score sem-bic-score --semBicRule 1 --penaltyDiscount 2 --skewEdgeThreshold 0.3 * --faskLeftRightRule 1 --faskDelta -0.3 --twoCycleScreeningThreshold 0 --orientationAlpha 0.1 -structurePrior 0 - *

- * - *

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

+ *

+ * This class is configured to respect knowledge of forbidden and required edges, including knowledge of temporal + * tiers. * * @author josephramsey * @author rubensanchez @@ -176,6 +174,7 @@ public final class Fask implements IGraphSearch { private LeftRight leftRight = LeftRight.RSKEW; // The graph resulting from search. private Graph graph; + private long seed = -1; /** * Constructor. @@ -201,40 +200,83 @@ public Fask(DataSet dataSet, Score score, IndependenceTest test) { this.orientationAlpha = 0.01; } - private static double cu(double[] x, double[] y, double[] condition) { - double exy = 0.0; - int n = 0; + public static double faskLeftRightV2(double[] x, double[] y, boolean empirical, double delta) { + double sx = skewness(x); + double sy = skewness(y); + double r = correlation(x, y); + double lr = Fask.correxp(x, y, x) - Fask.correxp(x, y, y); - for (int k = 0; k < x.length; k++) { - if (condition[k] > 0) { - exy += x[k] * y[k]; - n++; - } + if (empirical) { + lr *= signum(sx) * signum(sy); } - return exy / n; + if (r < delta) { + lr *= -1; + } + + return lr; } - // Returns E(XY | Z > 0); Z is typically either X or Y. - private static double E(double[] x, double[] y, double[] z) { - double exy = 0.0; - int n = 0; + public static double faskLeftRightV1(double[] x, double[] y, boolean empirical, double delta) { + double left = Fask.cu(x, y, x) / (sqrt(Fask.cu(x, x, x) * Fask.cu(y, y, x))); + double right = Fask.cu(x, y, y) / (sqrt(Fask.cu(x, x, y) * Fask.cu(y, y, y))); + double lr = left - right; - for (int k = 0; k < x.length; k++) { - if (z[k] > 0) { - exy += x[k] * y[k]; - n++; - } + double r = correlation(x, y); + double sx = skewness(x); + double sy = skewness(y); + + if (empirical) { + r *= signum(sx) * signum(sy); } - return exy / n; + lr *= signum(r); + if (r < delta) lr *= -1; + + return lr; } + public static double robustSkew(double[] x, double[] y, boolean empirical) { - // Returns E(XY | Z > 0) / sqrt(E(XX | Z > 0) * E(YY | Z > 0)). Z is typically either X or Y. - private static double correxp(double[] x, double[] y, double[] z) { - return Fask.E(x, y, z) / sqrt(Fask.E(x, x, z) * Fask.E(y, y, z)); + if (empirical) { + x = correctSkewness(x, skewness(x)); + y = correctSkewness(y, skewness(y)); + } + + double[] lr = new double[x.length]; + + for (int i = 0; i < x.length; i++) { + lr[i] = g(x[i]) * y[i] - x[i] * g(y[i]); + } + + return correlation(x, y) * mean(lr); + } + + public static double skew(double[] x, double[] y, boolean empirical) { + + if (empirical) { + x = correctSkewness(x, skewness(x)); + y = correctSkewness(y, skewness(y)); + } + + double[] lr = new double[x.length]; + + for (int i = 0; i < x.length; i++) { + lr[i] = x[i] * x[i] * y[i] - x[i] * y[i] * y[i]; + } + + return correlation(x, y) * mean(lr); + } + + public static double g(double x) { + return log(cosh(FastMath.max(x, 0))); + } + + public static double[] correctSkewness(double[] data, double sk) { + double[] data2 = new double[data.length]; + for (int i = 0; i < data.length; i++) data2[i] = data[i] * signum(sk); + return data2; } /** @@ -272,10 +314,12 @@ public Graph search() { if (this.adjacencyMethod == AdjacencyMethod.BOSS) { PermutationSearch fas = new PermutationSearch(new Boss(this.score)); + fas.setSeed(seed); fas.setKnowledge(this.knowledge); G = fas.search(); } else if (this.adjacencyMethod == AdjacencyMethod.GRASP) { Grasp fas = new Grasp(this.score); + fas.setSeed(seed); fas.setDepth(5); fas.setNonSingularDepth(1); fas.setUncoveredDepth(1); @@ -469,8 +513,8 @@ public double[][] getB() { } /** - * Returns a matrix of left-right scores for the search. If lr = getLrScores(), then lr[i][j] - * is the left right scores leftRight(data[i], data[j]); + * Returns a matrix of left-right scores for the search. If lr = getLrScores(), then lr[i][j] is the left right + * scores leftRight(data[i], data[j]); * * @return This matrix as a double[][] array. */ @@ -631,72 +675,41 @@ public double leftRight(double[] x, double[] y) { throw new IllegalStateException("Left right rule not configured: " + this.leftRight); } - public static double faskLeftRightV2(double[] x, double[] y, boolean empirical, double delta) { - double sx = skewness(x); - double sy = skewness(y); - double r = correlation(x, y); - double lr = Fask.correxp(x, y, x) - Fask.correxp(x, y, y); - if (empirical) { - lr *= signum(sx) * signum(sy); - } - - if (r < delta) { - lr *= -1; - } - - return lr; - } - - public static double faskLeftRightV1(double[] x, double[] y, boolean empirical, double delta) { - double left = Fask.cu(x, y, x) / (sqrt(Fask.cu(x, x, x) * Fask.cu(y, y, x))); - double right = Fask.cu(x, y, y) / (sqrt(Fask.cu(x, x, y) * Fask.cu(y, y, y))); - double lr = left - right; + private static double cu(double[] x, double[] y, double[] condition) { + double exy = 0.0; - double r = correlation(x, y); - double sx = skewness(x); - double sy = skewness(y); + int n = 0; - if (empirical) { - r *= signum(sx) * signum(sy); + for (int k = 0; k < x.length; k++) { + if (condition[k] > 0) { + exy += x[k] * y[k]; + n++; + } } - lr *= signum(r); - if (r < delta) lr *= -1; - - return lr; + return exy / n; } - public static double robustSkew(double[] x, double[] y, boolean empirical) { - - if (empirical) { - x = correctSkewness(x, skewness(x)); - y = correctSkewness(y, skewness(y)); - } - - double[] lr = new double[x.length]; + // Returns E(XY | Z > 0); Z is typically either X or Y. + private static double E(double[] x, double[] y, double[] z) { + double exy = 0.0; + int n = 0; - for (int i = 0; i < x.length; i++) { - lr[i] = g(x[i]) * y[i] - x[i] * g(y[i]); + for (int k = 0; k < x.length; k++) { + if (z[k] > 0) { + exy += x[k] * y[k]; + n++; + } } - return correlation(x, y) * mean(lr); + return exy / n; } - public static double skew(double[] x, double[] y, boolean empirical) { - - if (empirical) { - x = correctSkewness(x, skewness(x)); - y = correctSkewness(y, skewness(y)); - } - - double[] lr = new double[x.length]; - - for (int i = 0; i < x.length; i++) { - lr[i] = x[i] * x[i] * y[i] - x[i] * y[i] * y[i]; - } - return correlation(x, y) * mean(lr); + // Returns E(XY | Z > 0) / sqrt(E(XX | Z > 0) * E(YY | Z > 0)). Z is typically either X or Y. + private static double correxp(double[] x, double[] y, double[] z) { + return Fask.E(x, y, z) / sqrt(Fask.E(x, x, z) * Fask.E(y, y, z)); } private double tanh(double[] x, double[] y, boolean empirical) { @@ -715,10 +728,6 @@ private double tanh(double[] x, double[] y, boolean empirical) { return correlation(x, y) * mean(lr); } - public static double g(double x) { - return log(cosh(FastMath.max(x, 0))); - } - private boolean knowledgeOrients(Node X, Node Y) { return this.knowledge.isForbidden(Y.getName(), X.getName()) || this.knowledge.isRequired(X.getName(), Y.getName()); } @@ -727,12 +736,6 @@ private boolean edgeForbiddenByKnowledge(Node X, Node Y) { return this.knowledge.isForbidden(Y.getName(), X.getName()) && this.knowledge.isForbidden(X.getName(), Y.getName()); } - public static double[] correctSkewness(double[] data, double sk) { - double[] data2 = new double[data.length]; - for (int i = 0; i < data.length; i++) data2[i] = data[i] * signum(sk); - return data2; - } - private boolean twoCycleTest(int i, int j, double[][] D, Graph G0, List V) { Node X = V.get(i); Node Y = V.get(j); @@ -853,6 +856,10 @@ private void logTwoCycle(NumberFormat nf, List variables, double[][] d, No ); } + public void setSeed(long seed) { + this.seed = seed; + } + /** * Enumerates the options left-right rules to use for FASK. Options include the FASK left-right rule and three * left-right rules from the Hyvarinen and Smith pairwise orientation paper: Robust Skew, Skew, and Tanh. In that diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/FastIca.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/FastIca.java index 7692028629..9026f5bf9e 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/FastIca.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/FastIca.java @@ -31,21 +31,22 @@ import static org.apache.commons.math3.util.FastMath.*; /** - *

Translates a version of the FastICA algorithm used in R from Fortran - * into Java for use in Tetrad. This can be used in various algorithms that assume linearity and non-gaussianity, as for - * example LiNGAM and LiNG-D. There is one difference from the R, in that in R FastICA can operate over complex numbers, - * whereas here it is restricted to real numbers. A useful reference is this:

- * - *

Oja, E., & Hyvarinen, A. (2000). Independent component analysis: - * algorithms and applications. Neural networks, 13(4-5), 411-430.

- * - *

The documentation of the R version is as follows, all of which is true of this - * translation (so far as I know) except for its being in R and its allowing complex values. + * Translates a version of the FastICA algorithm used in R from Fortran into Java for use in Tetrad. This can be used in + * various algorithms that assume linearity and non-gaussianity, as for example LiNGAM and LiNG-D. There is one + * difference from the R, in that in R FastICA can operate over complex numbers, whereas here it is restricted to real + * numbers. A useful reference is this: + *

+ * Oja, E., & Hyvarinen, A. (2000). Independent component analysis: algorithms and applications. Neural networks, + * 13(4-5), 411-430. + *

+ * The documentation of the R version is as follows, all of which is true of this translation (so far as I know) except + * for its being in R and its allowing complex values. *

* Description: *

* This is an R and C code implementation of the FastICA algorithm of Aapo Hyvarinen et al. (URL: - * http://www.cis.hut.fi/aapo/) to perform Independent Component Analysis (ICA) and Projection Pursuit. + * http://www.cis.hut.fi/aapo/) to perform Independent Component Analysis + * (ICA) and Projection Pursuit. *

* Usage: *

@@ -98,8 +99,7 @@ * First, the data is centered by subtracting the mean of each column of the data matrix X. *

* The data matrix is then `whitened' by projecting the data onto it's principle component directions i.e. X -> XK - * where K is a pre-whitening matrix. - * The user can specify the number of components. + * where K is a pre-whitening matrix. The user can specify the number of components. *

* The ICA algorithm then estimates a matrix W s.t XKW = S . W is chosen to maximize the neg-entropy approximation under * the constraints that W is an orthonormal matrix. This constraint ensures that the estimated components are @@ -120,86 +120,57 @@ *

* A. Hyvarinen and E. Oja (2000) Independent Component Analysis: Algorithms and Applications, _Neural Networks_, * *13(4-5)*:411-430 - *

* * @author josephramsey */ public class FastIca { - /** - * The algorithm type where all components are extracted simultaneously. - */ + // The algorithm type where all components are extracted simultaneously. public static int PARALLEL; - /** - * The algorithm type where the components are extracted one at a time. - */ + // The algorithm type where the components are extracted one at a time. public static int DEFLATION = 1; - /** - * One of the function types that can be used to approximate negative entropy. - */ + // One of the function types that can be used to approximate negative entropy. public static int LOGCOSH = 2; - /** - * The other function type that can be used to approximate negative entropy. - */ + // The other function type that can be used to approximate negative entropy. public static int EXP = 3; - /** - * A data matrix with n rows representing observations and p columns representing variables. - */ + // A data matrix with n rows representing observations and p columns representing variables. private final Matrix X; - /** - * The number of independent components to be extracted. - */ + // The number of independent components to be extracted. private int numComponents; - /** - * If algorithmType == PARALLEL, the components are extracted simultaneously (the default). - * if algorithmType == DEFLATION, the components are extracted one at a time. - */ + // If algorithmType == PARALLEL, the components are extracted simultaneously (the default). if algorithmType == + // DEFLATION, the components are extracted one at a time. private int algorithmType = FastIca.PARALLEL; - /** - * The function type to be used, either LOGCOSH or EXP. - */ + // The function type to be used, either LOGCOSH or EXP. private int function = FastIca.LOGCOSH; - /** - * Constant in range [1, 2] used in approximation to neg-entropy when 'fun == "logcosh". Default = 1.0. - */ + // Constant in range [1, 2] used in approximation to neg-entropy when 'fun == "logcosh". Default = 1.0. private double alpha = 1.1; - /** - * A logical value indicating whether rows of the data matrix 'X' should be standardized beforehand. Default = - * false. - */ + // A logical value indicating whether rows of the data matrix 'X' should be standardized beforehand. Default = + // false. private boolean rowNorm; - /** - * Maximum number of iterations to perform. Default = 200. - */ + // Maximum number of iterations to perform. Default = 200. private int maxIterations = 200; - /** - * A positive scalar giving the tolerance at which the un-mixing matrix is considered to have converged. Default = - * 1e-04. - */ + // A positive scalar giving the tolerance at which the un-mixing matrix is considered to have converged. Default = + // 1e-04. private double tolerance = 1e-04; - /** - * A logical value indicating the level of output as the algorithm runs. Default = false. - */ + // A logical value indicating the level of output as the algorithm runs. Default = false. private boolean verbose; - /** - * Initial un-mixing matrix of dimension (n.comp,n.comp). If null (default), then a matrix of normal r.v.'s is used. - */ + // Initial un-mixing matrix of dimension (n.comp,n.comp). If null (default), then a matrix of normal r.v.'s is + // used. private Matrix wInit; - /** * Constructs an instance of the Fast ICA algorithm, taking as arguments the two arguments that cannot be defaulted: * the data matrix itself and the number of components to be extracted. @@ -211,10 +182,9 @@ public FastIca(Matrix X, int numComponents) { this.numComponents = numComponents; } - /** - * If algorithmType == PARALLEL, the components are extracted simultaneously (the default). - * if algorithmType == DEFLATION, the components are extracted one at a time. + * If algorithmType == PARALLEL, the components are extracted simultaneously (the default). if algorithmType == + * DEFLATION, the components are extracted one at a time. * * @param algorithmType This type. */ @@ -297,8 +267,8 @@ public void setVerbose(boolean verbose) { } /** - * Sets the initial un-mixing matrix of dimension (n.comp,n.comp). - * If NULL (default), then a random matrix of normal r.v.'s is used. + * Sets the initial un-mixing matrix of dimension (n.comp,n.comp). If NULL (default), then a random matrix of normal + * r.v.'s is used. * * @param wInit This matrix. */ diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Fci.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Fci.java index fee0ed8e8a..fc16f74b6b 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Fci.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Fci.java @@ -38,28 +38,25 @@ import java.util.Set; /** - *

Implements the Fast Causal Inference (FCI) algorithm due to Peter Spirtes, which addressed - * the case where latent common causes cannot be assumed not to exist with respect to the data set being analyzed. That - * is, it is assumed that there may be variables that are not included in the data that nonetheless may be causes of two - * or more variables that are included in data.

- * - *

Two alternatives are provided for doing the final orientation step, one due to Peter Spirtes, - * which is arrow complete, and another due to Jiji Zhang, which is arrow and tail complete.

- * - *

This algorithm, with the Spirtes final orientation rules, was given in an earlier version of - * this book:

- * - *

Spirtes, P., Glymour, C. N., Scheines, R., & Heckerman, D. (2000). Causation, - * prediction, and search. MIT press.

- * - *

The algorithm with the Zhang final orientation rules was given in this reference:

- * - *

Zhang, J. (2008). On the completeness of orientation rules for causal discovery in the presence - * of latent confounders and selection bias. Artificial Intelligence, 172(16-17), 1873-1896.

- * - * - *

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

+ * Implements the Fast Causal Inference (FCI) algorithm due to Peter Spirtes, which addressed the case where latent + * common causes cannot be assumed not to exist with respect to the data set being analyzed. That is, it is assumed that + * there may be variables that are not included in the data that nonetheless may be causes of two or more variables that + * are included in data. + *

+ * Two alternatives are provided for doing the final orientation step, one due to Peter Spirtes, which is arrow + * complete, and another due to Jiji Zhang, which is arrow and tail complete. + *

+ * This algorithm, with the Spirtes final orientation rules, was given in an earlier version of this book: + *

+ * Spirtes, P., Glymour, C. N., Scheines, R., & Heckerman, D. (2000). Causation, prediction, and search. MIT press. + *

+ * The algorithm with the Zhang final orientation rules was given in this reference: + *

+ * Zhang, J. (2008). On the completeness of orientation rules for causal discovery in the presence of latent confounders + * and selection bias. Artificial Intelligence, 172(16-17), 1873-1896. + *

+ * This class is configured to respect knowledge of forbidden and required edges, including knowledge of temporal + * tiers. * * @author peterspirtes * @author clarkglymour @@ -72,22 +69,35 @@ * @see Knowledge */ public final class Fci implements IGraphSearch { + // The variables to search over. private final List variables = new ArrayList<>(); + // The independence test to use. private final IndependenceTest independenceTest; + // The logger. private final TetradLogger logger = TetradLogger.getInstance(); + // The sepsets from FAS. private SepsetMap sepsets; + // The background knowledge. private Knowledge knowledge = new Knowledge(); + // Whether the Zhang complete rule set should be used. private boolean completeRuleSetUsed = true; + // Whether the possible msep step should be done. private boolean possibleMsepSearchDone = true; + // The maximum length of any discriminating path. private int maxPathLength = -1; + // The depth of search. private int depth = -1; + // The elapsed time of search. private long elapsedTime; + // Whether verbose output should be printed. private boolean verbose; + // The PC heuristic type to use. private PcCommon.PcHeuristicType heuristic = PcCommon.PcHeuristicType.NONE; + // Whether the stable options should be used. private boolean stable = true; + // Whether the discriminating path rule should be used. private boolean doDiscriminatingPathRule = true; - /** * Constructor. * @@ -136,7 +146,11 @@ public Fci(IndependenceTest independenceTest, List searchVars) { this.variables.removeAll(remVars); } - + /** + * Performs the search. + * + * @return The graph. + */ public Graph search() { long start = MillisecondTimes.timeMillis(); @@ -246,8 +260,8 @@ public void setKnowledge(Knowledge knowledge) { } /** - * Sets whether the Zhang complete rule set should be used; false if only R1-R4 (the rule set of the original - * FCI) should be used. False by default. + * Sets whether the Zhang complete rule set should be used; false if only R1-R4 (the rule set of the original FCI) + * should be used. False by default. * * @param completeRuleSetUsed True for the complete Zhang rule set. */ diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/FciMax.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/FciMax.java index 362d9906b7..16fd4af3e8 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/FciMax.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/FciMax.java @@ -29,6 +29,7 @@ import edu.cmu.tetrad.search.utils.SepsetMap; import edu.cmu.tetrad.search.utils.SepsetsSet; import edu.cmu.tetrad.util.*; +import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; @@ -38,25 +39,24 @@ import java.util.concurrent.RecursiveTask; /** - *

Modifies FCI to do orientation of unshielded colliders (X*-*Y*-*Z with X and Z - * not adjacent) using the max-P rule (see the PC-Max algorithm). This reference is relevant:

- * - *

Raghu, V. K., Zhao, W., Pu, J., Leader, J. K., Wang, R., Herman, J., ... & - * Wilson, D. O. (2019). Feasibility of lung cancer prediction from low-dose CT scan and smoking factors using causal - * models. Thorax, 74(7), 643-649.

- * - *

Max-P triple orientation is a method for orienting unshielded triples - * X*=-*Y*-*Z as one of the following: (a) Collider, X->Y<-Z, or (b) Noncollider, X-->Y-->Z, or X<-Y<-Z, or X<-Y->Z. 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, and lists the p-values for each test. Then, one chooses the conditioning set - * out of all of these that maximizes the p-value. If this conditioning set contains Y, then the triple is judged to be - * a noncollider; otherwise, it is judged to be a collider.

- * - *

All unshielded triples in the graph given by FAS are judged as colliders - * or non-colliders and the colliders oriented. Then the final FCI orientation rules are applied, as in FCI.

- * - *

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

+ * Modifies FCI to do orientation of unshielded colliders (X*-*Y*-*Z with X and Z not adjacent) using the max-P rule + * (see the PC-Max algorithm). This reference is relevant: + *

+ * Raghu, V. K., Zhao, W., Pu, J., Leader, J. K., Wang, R., Herman, J., ... & Wilson, D. O. (2019). Feasibility of + * lung cancer prediction from low-dose CT scan and smoking factors using causal models. Thorax, 74(7), 643-649. + *

+ * Max-P triple orientation is a method for orienting unshielded triples X*=-*Y*-*Z as one of the following: (a) + * Collider, X->Y<-Z, or (b) Noncollider, X-->Y-->Z, or X<-Y<-Z, or X<-Y->Z. 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, and lists the p-values for each test. Then, one chooses the conditioning set out of all of these + * that maximizes the p-value. If this conditioning set contains Y, then the triple is judged to be a noncollider; + * otherwise, it is judged to be a collider. + *

+ * All unshielded triples in the graph given by FAS are judged as colliders or non-colliders and the colliders oriented. + * Then the final FCI orientation rules are applied, as in FCI. + *

+ * This class is configured to respect knowledge of forbidden and required edges, including knowledge of temporal + * tiers. * * @author josephramsey * @see Fci @@ -65,21 +65,33 @@ * @see Knowledge */ public final class FciMax implements IGraphSearch { + // The independence test. private final IndependenceTest independenceTest; + // The logger. private final TetradLogger logger = TetradLogger.getInstance(); + // The sepsets from the FAS search. private SepsetMap sepsets; + // The background knowledge. private Knowledge knowledge = new Knowledge(); + // The elapsed time of search. private long elapsedTime; + // The PC heuristic from PC used in search. private PcCommon.PcHeuristicType pcHeuristicType = PcCommon.PcHeuristicType.NONE; + // Whether the stable option will be used for search. private boolean stable = false; + // Whether the discriminating path rule will be used in search. private boolean completeRuleSetUsed = true; + // Whether the discriminating path rule will be used in search. private boolean doDiscriminatingPathRule = false; + // Whether the discriminating path rule will be used in search. private boolean possibleMsepSearchDone = true; + // The maximum length of any discriminating path, or -1 if unlimited. private int maxPathLength = -1; + // The maximum number of variables conditioned in any test. private int depth = -1; + // Whether verbose output should be printed. private boolean verbose = false; - /** * Constructor. */ @@ -91,7 +103,6 @@ public FciMax(IndependenceTest independenceTest) { this.independenceTest = independenceTest; } - /** * Performs the search and returns the PAG. * @@ -129,14 +140,7 @@ public Graph search() { // Step CI C (Zhang's step F3.) - FciOrient fciOrient = new FciOrient(new SepsetsSet(this.sepsets, this.independenceTest)); - - fciOrient.setCompleteRuleSetUsed(this.completeRuleSetUsed); - fciOrient.setMaxPathLength(this.maxPathLength); - fciOrient.setDoDiscriminatingPathColliderRule(this.doDiscriminatingPathRule); - fciOrient.setDoDiscriminatingPathTailRule(this.doDiscriminatingPathRule); - fciOrient.setVerbose(this.verbose); - fciOrient.setKnowledge(this.knowledge); + FciOrient fciOrient = getFciOrient(); fciOrient.fciOrientbk(this.knowledge, graph, graph.getNodes()); addColliders(graph); @@ -281,6 +285,19 @@ public void setDoDiscriminatingPathRule(boolean doDiscriminatingPathRule) { this.doDiscriminatingPathRule = doDiscriminatingPathRule; } + @NotNull + private FciOrient getFciOrient() { + FciOrient fciOrient = new FciOrient(new SepsetsSet(this.sepsets, this.independenceTest)); + + fciOrient.setCompleteRuleSetUsed(this.completeRuleSetUsed); + fciOrient.setMaxPathLength(this.maxPathLength); + fciOrient.setDoDiscriminatingPathColliderRule(this.doDiscriminatingPathRule); + fciOrient.setDoDiscriminatingPathTailRule(this.doDiscriminatingPathRule); + fciOrient.setVerbose(this.verbose); + fciOrient.setKnowledge(this.knowledge); + return fciOrient; + } + private void addColliders(Graph graph) { Map scores = new ConcurrentHashMap<>(); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Fges.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Fges.java index 094758eeb9..e3324f03e6 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Fges.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Fges.java @@ -43,37 +43,33 @@ import static org.apache.commons.math3.util.FastMath.min; /** - *

Implements the Fast Greedy Equivalence Search (FGES) algorithm. This is - * an implementation of the Greedy Equivalence Search algorithm, originally due to Chris Meek but developed - * significantly by Max Chickering. FGES uses with some optimizations that allow it to scale accurately to thousands of - * variables accurately for the sparse case. The reference for FGES is this:

- * - *

Ramsey, J., Glymour, M., Sanchez-Romero, R., & Glymour, C. (2017). - * A million variables and more: the fast greedy equivalence search algorithm for learning high-dimensional graphical - * causal models, with an application to functional magnetic resonance images. International journal of data science and - * analytics, 3, 121-129.

- * - *

The reference for Chickering's GES is this:

- * - *

Chickering (2002) "Optimal structure identification with greedy search" - * Journal of Machine Learning Research.

- * - *

FGES works for the continuous case, the discrete case, and the mixed - * continuous/discrete case, so long as a BIC score is available for the type of data in question.

- * - *

To speed things up, it has been assumed that variables X and Y with zero - * correlation do not correspond to edges in the graph. This is a restricted form of the heuristic speedup assumption, - * something GES does not assume. This heuristic speedup assumption needs to be explicitly turned on using - * setHeuristicSpeedup(true).

- * - *

Also, edges to be added or remove from the graph in the forward or - * backward phase, respectively are cached, together with the ancillary information needed to do the additions or - * removals, to reduce rescoring.

- * - *

A number of other optimizations were also. See code for details.

- * - *

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

+ * Implements the Fast Greedy Equivalence Search (FGES) algorithm. This is an implementation of the Greedy Equivalence + * Search algorithm, originally due to Chris Meek but developed significantly by Max Chickering. FGES uses with some + * optimizations that allow it to scale accurately to thousands of variables accurately for the sparse case. The + * reference for FGES is this: + *

+ * Ramsey, J., Glymour, M., Sanchez-Romero, R., & Glymour, C. (2017). A million variables and more: the fast greedy + * equivalence search algorithm for learning high-dimensional graphical causal models, with an application to functional + * magnetic resonance images. International journal of data science and analytics, 3, 121-129. + *

+ * The reference for Chickering's GES is this: + *

+ * Chickering (2002) "Optimal structure identification with greedy search" Journal of Machine Learning Research. + *

+ * FGES works for the continuous case, the discrete case, and the mixed continuous/discrete case, so long as a BIC score + * is available for the type of data in question. + *

+ * To speed things up, it has been assumed that variables X and Y with zero correlation do not correspond to edges in + * the graph. This is a restricted form of the heuristic speedup assumption, something GES does not assume. This + * heuristic speedup assumption needs to be explicitly turned on using setHeuristicSpeedup(true). + *

+ * Also, edges to be added or remove from the graph in the forward or backward phase, respectively are cached, together + * with the ancillary information needed to do the additions or removals, to reduce rescoring. + *

+ * A number of other optimizations were also. See code for de tails. + *

+ * This class is configured to respect knowledge of forbidden and required edges, including knowledge of temporal + * tiers. * * @author Ricardo Silva * @author josephramsey @@ -83,17 +79,16 @@ * @see Knowledge */ public final class Fges implements IGraphSearch, DagScorer { + // Used to find semidirected paths for cycle checking. private final Set emptySet = new HashSet<>(); + // Used to find semidirected paths for cycle checking. private final int[] count = new int[1]; + // Used to find semidirected paths for cycle checking. private final int depth = 10000; - /** - * The logger for this class. The config needs to be set. - */ + // The logger for this class. The config needs to be set. private final TetradLogger logger = TetradLogger.getInstance(); - /** - * The top n graphs found by the algorithm, where n is numPatternsToStore. - */ + // The top n graphs found by the algorithm, where n is numPatternsToStore. private final LinkedList topGraphs = new LinkedList<>(); // Potential arrows sorted by bump high to low. The first one is a candidate for adding to the graph. private final SortedSet sortedArrows = new ConcurrentSkipListSet<>(); @@ -101,63 +96,41 @@ public final class Fges implements IGraphSearch, DagScorer { private final Map arrowsMap = new ConcurrentHashMap<>(); // private final Map arrowsMapBackward = new ConcurrentHashMap<>(); private boolean faithfulnessAssumed = false; - /** - * Specification of forbidden and required edges. - */ + // Specification of forbidden and required edges. private Knowledge knowledge = new Knowledge(); - /** - * List of variables in the data set, in order. - */ + // List of variables in the data set, in order. private List variables; - /** - * An initial graph to start from. - */ + // An initial graph to start from. private Graph initialGraph; - /** - * If non-null, edges not adjacent in this graph will not be added. - */ + // If non-null, edges not adjacent in this graph will not be added. private Graph boundGraph = null; - /** - * Elapsed time of the most recent search. - */ + // Elapsed time of the most recent search. private long elapsedTime; - /** - * The totalScore for discrete searches. - */ + // The totalScore for discrete searches. private Score score; - /** - * True if verbose output should be printed. - */ + // True if verbose output should be printed. private boolean verbose = false; private boolean meekVerbose = false; // Map from variables to their column indices in the data set. private ConcurrentMap hashIndices; // A graph where X--Y means that X and Y have non-zero total effect on one another. private Graph effectEdgesGraph; - // Where printed output is sent. private PrintStream out = System.out; - // The graph being constructed. private Graph graph; - // Arrows with the same totalScore are stored in this list to distinguish their order in sortedArrows. // The ordering doesn't matter; it just has to be transitive. private int arrowIndex = 0; - // The score of the model. private double modelScore; - // Internal. private Mode mode = Mode.heuristicSpeedup; - // Bounds the degree of the graph. private int maxDegree = -1; - // True if the first step of adding an edge to an empty graph should be scored in both directions // for each edge with the maximum score chosen. private boolean symmetricFirstStep = false; - // True, if FGES should run in a single thread, no if parallelized. private boolean parallelized = false; @@ -195,8 +168,8 @@ private static Node traverseSemiDirected(Node node, Edge edge) { } /** - * Greedy equivalence search: Start from the empty graph, add edges till the model is significant. - * Then start deleting edges till a minimum is achieved. + * Greedy equivalence search: Start from the empty graph, add edges till the model is significant. Then start + * deleting edges till a minimum is achieved. * * @return the resulting Pattern. */ @@ -240,7 +213,7 @@ public Graph search() { this.logger.forceLogMessage("Elapsed time = " + (elapsedTime) / 1000. + " s"); } - this.modelScore = scoreDag(GraphTransforms.dagFromCPDAG(graph, null), true); + this.modelScore = scoreDag(GraphTransforms.dagFromCpdag(graph, null), true); return graph; } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/FgesMb.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/FgesMb.java index b78b44f668..cf3940d42c 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/FgesMb.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/FgesMb.java @@ -43,37 +43,33 @@ import static org.apache.commons.math3.util.FastMath.min; /** - *

Implements the Fast Greedy Equivalence Search (FGES) algorithm. This is - * an implementation of the Greedy Equivalence Search algorithm, originally due to Chris Meek but developed - * significantly by Max Chickering. FGES uses with some optimizations that allow it to scale accurately to thousands of - * variables accurately for the sparse case. The reference for FGES is this:

- * - *

Ramsey, J., Glymour, M., Sanchez-Romero, R., & Glymour, C. (2017). - * A million variables and more: the fast greedy equivalence search algorithm for learning high-dimensional graphical - * causal models, with an application to functional magnetic resonance images. International journal of data science and - * analytics, 3, 121-129.

- * - *

The reference for Chickering's GES is this:

- * - *

Chickering (2002) "Optimal structure identification with greedy search" - * Journal of Machine Learning Research.

- * - *

FGES works for the continuous case, the discrete case, and the mixed - * continuous/discrete case, so long as a BIC score is available for the type of data in question.

- * - *

To speed things up, it has been assumed that variables X and Y with zero - * correlation do not correspond to edges in the graph. This is a restricted form of the heuristic speedup assumption, - * something GES does not assume. This heuristic speedup assumption needs to be explicitly turned on using - * setHeuristicSpeedup(true).

- * - *

Also, edges to be added or remove from the graph in the forward or - * backward phase, respectively are cached, together with the ancillary information needed to do the additions or - * removals, to reduce rescoring.

- * - *

A number of other optimizations were also. See code for details.

- * - *

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

+ * Implements the Fast Greedy Equivalence Search (FGES) algorithm. This is an implementation of the Greedy Equivalence + * Search algorithm, originally due to Chris Meek but developed significantly by Max Chickering. FGES uses with some + * optimizations that allow it to scale accurately to thousands of variables accurately for the sparse case. The + * reference for FGES is this: + *

+ * Ramsey, J., Glymour, M., Sanchez-Romero, R., & Glymour, C. (2017). A million variables and more: the fast greedy + * equivalence search algorithm for learning high-dimensional graphical causal models, with an application to functional + * magnetic resonance images. International journal of data science and analytics, 3, 121-129. + *

+ * The reference for Chickering's GES is this: + *

+ * Chickering (2002) "Optimal structure identification with greedy search" Journal of Machine Learning Research. + *

+ * FGES works for the continuous case, the discrete case, and the mixed continuous/discrete case, so long as a BIC score + * is available for the type of data in question. + *

+ * To speed things up, it has been assumed that variables X and Y with zero correlation do not correspond to edges in + * the graph. This is a restricted form of the heuristic speedup assumption, something GES does not assume. This + * heuristic speedup assumption needs to be explicitly turned on using setHeuristicSpeedup(true). + *

+ * Also, edges to be added or remove from the graph in the forward or backward phase, respectively are cached, together + * with the ancillary information needed to do the additions or removals, to reduce rescoring. + *

+ * A number of other optimizations were also. See code for details. + *

+ * This class is configured to respect knowledge of forbidden and required edges, including knowledge of temporal + * tiers. * * @author Ricardo Silva * @author josephramsey @@ -83,45 +79,42 @@ * @see Knowledge */ public final class FgesMb implements DagScorer { - public enum TrimmingStyle { - NONE, ADJACENT_TO_TARGETS, MARKOV_BLANKET_GRAPH, SEMIDIRECTED_PATHS_TO_TARGETS - } - + //===internal===// + private final Set emptySet = new HashSet<>(); + private final int[] count = new int[1]; + private final int depth = 10000; + //The top n graphs found by the algorithm, where n is numPatternsToStore. + private final LinkedList topGraphs = new LinkedList<>(); + // Potential arrows sorted by bump high to low. The first one is a candidate for adding to the graph. + private final SortedSet sortedArrows = new ConcurrentSkipListSet<>(); + private final TetradLogger logger = TetradLogger.getInstance(); + private final Map arrowsMap = new ConcurrentHashMap<>(); + List targets = new ArrayList<>(); // The number of times the forward phase is iterated to expand to new adjacencies. private int numExpansions = 2; - // The style of trimming to use. private int trimmingStyle = 3; // default MB trimming. - // Bounds the degree of the graph. private int maxDegree = -1; - // Whether one-edge faithfulness is assumed (less general but faster). private boolean faithfulnessAssumed = false; - // The knowledge to use in the search. private Knowledge knowledge = new Knowledge(); - // True, if FGES should run in a single thread, no if parallelized. private boolean parallelized = false; - - //===internal===// - private final Set emptySet = new HashSet<>(); - private final int[] count = new int[1]; - private final int depth = 10000; - //The top n graphs found by the algorithm, where n is numPatternsToStore. - private final LinkedList topGraphs = new LinkedList<>(); - // Potential arrows sorted by bump high to low. The first one is a candidate for adding to the graph. - private final SortedSet sortedArrows = new ConcurrentSkipListSet<>(); - private final TetradLogger logger = TetradLogger.getInstance(); - private final Map arrowsMap = new ConcurrentHashMap<>(); - List targets = new ArrayList<>(); + // The variables to use in the search. private List variables; + // The initial graph. private Graph initialGraph; + // The graph to which the search is bound. private Graph boundGraph = null; + // The elapsed time of the search. private long elapsedTime; + // The score of the graph. private Score score; + // Whether verbose output should be produced. private boolean verbose = false; + // Whether verbose output should be produced for the Meek rules. private boolean meekVerbose = false; // Map from variables to their column indices in the data set. private ConcurrentMap hashIndices; @@ -138,10 +131,10 @@ public enum TrimmingStyle { private double modelScore; // Internal. private Mode mode = Mode.heuristicSpeedup; - // True if the first step of adding an edge to an empty graph should be scored in both directions // for each edge with the maximum score chosen. private boolean symmetricFirstStep = false; + // The list of all targets. private ArrayList allTargets; /** @@ -230,7 +223,7 @@ public Graph search(List targets) { this.logger.forceLogMessage("Elapsed time = " + (elapsedTime) / 1000. + " s"); } - this.modelScore = scoreDag(GraphTransforms.dagFromCPDAG(graph, null), true); + this.modelScore = scoreDag(GraphTransforms.dagFromCpdag(graph, null), true); graph = GraphUtils.trimGraph(targets, graph, trimmingStyle); return graph; } @@ -386,7 +379,6 @@ public void setSymmetricFirstStep(boolean symmetricFirstStep) { this.symmetricFirstStep = symmetricFirstStep; } - /** * Returns the score of the final search model. * @@ -1093,6 +1085,10 @@ public void setNumExpansions(int numExpansions) { this.numExpansions = numExpansions; } + public enum TrimmingStyle { + NONE, ADJACENT_TO_TARGETS, MARKOV_BLANKET_GRAPH, SEMIDIRECTED_PATHS_TO_TARGETS + } + /** * Internal. */ diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Fofc.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Fofc.java index db99e653de..c946077d0a 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Fofc.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Fofc.java @@ -37,20 +37,18 @@ /** - *

Implements the Find One Factor Clusters (FOFC) algorithm by Erich Kummerfeld, which - * uses reasoning about vanishing tetrads of algorithms to infer clusters of the measured variables in a dataset that - * each be explained by a single latent variable. A reference is the following

- * - *

Kummerfeld, E., & Ramsey, J. (2016, August). Causal clustering for 1-factor measurement - * models. In Proceedings of the 22nd ACM SIGKDD international conference on knowledge discovery and data mining (pp. - * 1655-1664).

- * - *

The algorithm employs tests of vanishing tetrads (list of 4 variables that follow - * a certain pattern in the exchangeability of latent paths with respect to the data). The notion of vanishing tetrads is - * old one but is explained in this book:

- * - *

Spirtes, P., Glymour, C. N., Scheines, R., & Heckerman, D. (2000). Causation, - * prediction, and search. MIT press.

+ * Implements the Find One Factor Clusters (FOFC) algorithm by Erich Kummerfeld, which uses reasoning about vanishing + * tetrads of algorithms to infer clusters of the measured variables in a dataset that each be explained by a single + * latent variable. A reference is the following + *

+ * Kummerfeld, E., & Ramsey, J. (2016, August). Causal clustering for 1-factor measurement models. In Proceedings of + * the 22nd ACM SIGKDD international conference on knowledge discovery and data mining (pp. 1655-1664). + *

+ * The algorithm employs tests of vanishing tetrads (list of 4 variables that follow a certain pattern in the + * exchangeability of latent paths with respect to the data). The notion of vanishing tetrads is old one but is + * explained in this book: + *

+ * Spirtes, P., Glymour, C. N., Scheines, R., & Heckerman, D. (2000). Causation, prediction, and search. MIT press. * * @author peterspirtes * @author erichkummerfeld @@ -175,6 +173,17 @@ public void setCheckType(ClusterSignificance.CheckType checkType) { this.checkType = checkType; } + /** + * The clusters that are output by the algorithm from the last call to search(). + */ + public List> getClusters() { + return this.clusters; + } + + public void setVerbose(boolean verbose) { + this.verbose = verbose; + } + // renjiey private int findFrequentestIndex(Integer[] outliers) { Map map = new HashMap<>(); @@ -946,17 +955,6 @@ private boolean zeroCorr(List cluster) { return count >= 1; } - /** - * The clusters that are output by the algorithm from the last call to search(). - */ - public List> getClusters() { - return this.clusters; - } - - public void setVerbose(boolean verbose) { - this.verbose = verbose; - } - private boolean vanishes(int x, int y, int z, int w) { if (this.testType == BpcTestType.TETRAD_DELTA) { Tetrad t1 = new Tetrad(this.variables.get(x), this.variables.get(y), this.variables.get(z), this.variables.get(w)); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Ftfc.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Ftfc.java index 0e4886ceda..ecf51b231f 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Ftfc.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Ftfc.java @@ -44,18 +44,17 @@ /** - *

Implements the Find Two Factor Clusters (FOFC) algorithm, which uses reasoning - * about vanishing tetrads of algorithms to infer clusters of the measured variables in a dataset that each be explained - * by a single latent variable. The reference is as follows:

- * - *

Kummerfeld, E. & Ramsey, J. & Yang, R. & Spirtes, P. & Scheines, R. (2014). - * Causal Clustering for 2-Factor Measurement Models. In T. Calders, F. Esposito, E. Hullermeier, and R. Meo, editors, - * Machine Learning and Knowledge Discovery in Databases, volume 8725 of Lecture Notes in Computer Science, pages 34-49. - * Springer Berlin Heidelberg.

- * - *

The two-factor version of the algorithm substitutes sextad tests for - * tetrad tests and searches for clusters of at least 6 variables that can be explained by two latent factors by - * calculating vanishing sextads.

+ * Implements the Find Two Factor Clusters (FOFC) algorithm, which uses reasoning about vanishing tetrads of algorithms + * to infer clusters of the measured variables in a dataset that each be explained by a single latent variable. The + * reference is as follows: + *

+ * Kummerfeld, E. & Ramsey, J. & Yang, R. & Spirtes, P. & Scheines, R. (2014). Causal Clustering for + * 2-Factor Measurement Models. In T. Calders, F. Esposito, E. Hullermeier, and R. Meo, editors, Machine Learning and + * Knowledge Discovery in Databases, volume 8725 of Lecture Notes in Computer Science, pages 34-49. Springer Berlin + * Heidelberg. + *

+ * The two-factor version of the algorithm substitutes sextad tests for tetrad tests and searches for clusters of at + * least 6 variables that can be explained by two latent factors by calculating vanishing sextads. * * @author peterspirtes * @author erichkummerfeld @@ -64,7 +63,7 @@ * @see Bpc */ public class Ftfc { - + // The correlation matrix. private final CorrelationMatrix corr; // The list of all variables. private final List variables; @@ -74,9 +73,11 @@ public class Ftfc { private final DeltaSextadTest test; // The data. private final transient DataModel dataModel; + // The algorithm used. private final Algorithm algorithm; + // The clusters found. private List> clusters; - + // Whether verbose output should be printed. private boolean verbose; /** diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/GFci.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/GFci.java index 8e966cb006..4c9c8d55c0 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/GFci.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/GFci.java @@ -37,28 +37,25 @@ import static edu.cmu.tetrad.graph.GraphUtils.gfciExtraEdgeRemovalStep; /** - *

Implements a modification of FCI that started by running the FGES algorithm and - * then fixes that result to be correct for latent variables models. First, colliders from the FGES results are copied - * into the final circle-circle graph, and some independence reasoning is used to add the remaining colliders into the - * graph. Then, the FCI final orientation rules are applied. The reference is here:

- * - *

Ogarrio, J. M., Spirtes, P., & Ramsey, J. (2016, August). A hybrid causal - * search algorithm for latent variable models. In Conference on probabilistic graphical models (pp. 368-379). - * PMLR.

- * - *

Because the method both runs FGES (a score-based algorithm) and does - * additional checking of conditional independencies, both as part of its collider orientation step and also as part of - * the the definite discriminating path step in the final FCI orientation rules, both a score and a test need to be used - * to construct a GFCI algorithm.

- * - *

Note that various score-based algorithms could be used in place of FGES - * for the initial step; in this repository we give three other options, GRaSP-FCI, BFCI (BOSS FCI), and SP-FCI - * (see).

- * - *

For more information on the algorithm, see the reference above.

- * - *

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

+ * Implements a modification of FCI that started by running the FGES algorithm and then fixes that result to be correct + * for latent variables models. First, colliders from the FGES results are copied into the final circle-circle graph, + * and some independence reasoning is used to add the remaining colliders into the graph. Then, the FCI final + * orientation rules are applied. The reference is here: + *

+ * Ogarrio, J. M., Spirtes, P., & Ramsey, J. (2016, August). A hybrid causal search algorithm for latent variable + * models. In Conference on probabilistic graphical models (pp. 368-379). PMLR. + *

+ * Because the method both runs FGES (a score-based algorithm) and does additional checking of conditional + * independencies, both as part of its collider orientation step and also as part of the the definite discriminating + * path step in the final FCI orientation rules, both a score and a test need to be used to construct a GFCI algorithm. + *

+ * Note that various score-based algorithms could be used in place of FGES for the initial step; in this repository we + * give three other options, GRaSP-FCI, BFCI (BOSS FCI), and SP-FCI (see). + *

+ * For more information on the algorithm, see the reference above. + *

+ * This class is configured to respect knowledge of forbidden and required edges, including knowledge of temporal + * tiers. * * @author Juan Miguel Ogarrio * @author peterspirtes @@ -72,18 +69,29 @@ * @see Knowledge */ public final class GFci implements IGraphSearch { + // The independence test used in search. private final IndependenceTest independenceTest; + // The logger. private final TetradLogger logger = TetradLogger.getInstance(); + // The score used in search. private final Score score; + // The knowledge used in search. private Knowledge knowledge = new Knowledge(); + // Whether Zhang's complete rules are used. private boolean completeRuleSetUsed = true; + // The maximum path length for the discriminating path rule. private int maxPathLength = -1; + // The maximum degree of the output graph. private int maxDegree = -1; + // Whether verbose output should be printed. private boolean verbose; + // The print stream used for output. private PrintStream out = System.out; + // Whether one-edge faithfulness is assumed. private boolean faithfulnessAssumed = true; + // Whether the discriminating path rule should be used. private boolean doDiscriminatingPathRule = true; - private boolean possibleMsepSearchDone = true; + // The depth of the search for the possible m-sep search. private int depth = -1; @@ -255,7 +263,6 @@ public void setDoDiscriminatingPathRule(boolean doDiscriminatingPathRule) { * @param possibleMsepSearchDone True, if so. */ public void setPossibleMsepSearchDone(boolean possibleMsepSearchDone) { - this.possibleMsepSearchDone = possibleMsepSearchDone; } /** diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Grasp.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Grasp.java index cf7716c968..6f38486952 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Grasp.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Grasp.java @@ -7,12 +7,10 @@ import edu.cmu.tetrad.search.score.Score; import edu.cmu.tetrad.search.utils.TeyssierScorer; import edu.cmu.tetrad.util.MillisecondTimes; -import edu.cmu.tetrad.util.NumberFormatUtil; import edu.cmu.tetrad.util.RandomUtil; import edu.cmu.tetrad.util.TetradLogger; import org.jetbrains.annotations.NotNull; -import java.text.NumberFormat; import java.util.*; import static java.lang.Double.NEGATIVE_INFINITY; @@ -20,35 +18,32 @@ /** - *

Implements the GRaSP algorithms, which uses a certain procedure to search - * in the space of permutations of variables for ones that imply CPDAGs that are especially close to the CPDAG of the - * true model. The reference is here:

- * - *

Lam, W. Y., Andrews, B., & Ramsey, J. (2022, August). Greedy relaxations of - * the sparsest permutation algorithm. In Uncertainty in Artificial Intelligence (pp. 1052-1062). PMLR.

- * - *

GRaSP can use either a score or an independence test; you can provide - * both, though if you do you need to use the parameters to choose which one will be used. The score options is more - * scalable and accurate, though the independence option is perhaps a little easier ot deal with theoretically and are - * useful for generating unit test results.

- * - *

As shown the reference above, GRaSP generates results for the linear, Gaussian - * case for N = 1000 with precisions for adjacencies and arrowheads near 1 and recalls of about 0.85, when the linear, - * Gaussian BIC score is used with a penalty of 2. For N = 10,000 recalls also rise up to about 1, so it can be an - * extraordinarily accurate search for the linear, Gaussian case. But in principle, it can be used with any sort of - * data, so long as a BIC score is available for that data. So it can be used for the discrete case and for the mixed - * continuous/discrete case as well.

- * - *

The version of GRaSP described in the above reference is limited to about 100 - * variables in execution time, after which it become impracticably slow. Recent optimizations allow it to scale further - * than that; hopefully these will be written up soon and made available.

- * - *

Knowledge can be used with this search. If tiered knowledge is used, then - * the procedure is carried out for each tier separately, given the variable preceding that tier, which allows the SP - * algorithm to address tiered (e.g., time series) problems with larger numbers of variables.

- * - *

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

+ * Implements the GRaSP algorithms, which uses a certain procedure to search in the space of permutations of variables + * for ones that imply CPDAGs that are especially close to the CPDAG of the true model. The reference is here: + *

+ * Lam, W. Y., Andrews, B., & Ramsey, J. (2022, August). Greedy relaxations of the sparsest permutation algorithm. + * In Uncertainty in Artificial Intelligence (pp. 1052-1062). PMLR. + *

+ * GRaSP can use either a score or an independence test; you can provide both, though if you do you need to use the + * parameters to choose which one will be used. The score options is more scalable and accurate, though the independence + * option is perhaps a little easier ot deal with theoretically and are useful for generating unit test results. + *

+ * As shown the reference above, GRaSP generates results for the linear, Gaussian case for N = 1000 with precisions for + * adjacencies and arrowheads near 1 and recalls of about 0.85, when the linear, Gaussian BIC score is used with a + * penalty of 2. For N = 10,000 recalls also rise up to about 1, so it can be an extraordinarily accurate search for the + * linear, Gaussian case. But in principle, it can be used with any sort of data, so long as a BIC score is available + * for that data. So it can be used for the discrete case and for the mixed continuous/discrete case as well. + *

+ * The version of GRaSP described in the above reference is limited to about 100 variables in execution time, after + * which it become impracticably slow. Recent optimizations allow it to scale further than that; hopefully these will be + * written up soon and made available. + *

+ * Knowledge can be used with this search. If tiered knowledge is used, then the procedure is carried out for each tier + * separately, given the variable preceding that tier, which allows the SP algorithm to address tiered (e.g., time + * series) problems with larger numbers of variables. + *

+ * This class is configured to respect knowledge of forbidden and required edges, including knowledge of temporal + * tiers. * * @author bryanandrews * @author josephramsey @@ -58,22 +53,39 @@ * @see Knowledge */ public class Grasp { + // The variables to be permuted. private final List variables; + // The score or test to be used. private Score score; + // The test to be used. private IndependenceTest test; + // The knowledge to be used. private Knowledge knowledge = new Knowledge(); + // The scorer to be used. private TeyssierScorer scorer; + // The time at which the algorithm started. private long start; + // Whether to use the score or the test. private boolean useScore = true; + // Whether to use the Raskutti-Uhler method or the Verma-Pearl method. private boolean useRaskuttiUhler; + // Whether to impose an ordering on the three GRaSP algorithms. private boolean ordered = false; + // Whether to use verbose output. private boolean verbose; + // The maximum depth of the depth-first search for tucks. private int uncoveredDepth = 1; + // The maximum depth of the depth-first search for uncovered tucks. private int nonSingularDepth = 1; + // Whether to use the data order or a random order for the initial permutation. private boolean useDataOrder = true; + // The maximum depth of the depth-first search for singular tucks. private int depth = 3; + // The number of times to run the algorithm with different starting permutations. private int numStarts = 1; + // Whether to allow internal randomness in the algorithm. private boolean allowInternalRandomness = false; + private long seed = -1; /** * Constructor for a score. @@ -117,6 +129,10 @@ public Grasp(@NotNull IndependenceTest test, Score score) { * @return The discovered permutation at the end of the procedure. */ public List bestOrder(@NotNull List order) { + if (seed != -1) { + RandomUtil.getInstance().setSeed(seed); + } + long start = MillisecondTimes.timeMillis(); order = new ArrayList<>(order); @@ -161,6 +177,8 @@ public List bestOrder(@NotNull List order) { } } + if (bestPerm == null) return null; + this.scorer.score(bestPerm); long stop = MillisecondTimes.timeMillis(); @@ -191,11 +209,7 @@ public int getNumEdges() { @NotNull public Graph getGraph(boolean cpDag) { if (this.scorer == null) throw new IllegalArgumentException("Please run algorithm first."); - Graph graph = this.scorer.getGraph(cpDag); - - NumberFormat nf = NumberFormatUtil.getInstance().getNumberFormat(); - graph.addAttribute("score ", nf.format(this.scorer.score())); - return graph; + return this.scorer.getGraph(cpDag); } /** @@ -439,6 +453,7 @@ private void graspDfs(@NotNull TeyssierScorer scorer, double sOld, int[] depth, } for (Node x : parents) { + if (Thread.currentThread().isInterrupted()) return; boolean covered = scorer.coveredEdge(x, y); boolean singular = true; @@ -511,4 +526,8 @@ private void graspDfs(@NotNull TeyssierScorer scorer, double sOld, int[] depth, } } } + + public void setSeed(long seed) { + this.seed = seed; + } } \ No newline at end of file diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/GraspFci.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/GraspFci.java index c5b5405fc4..ac08a4e0b3 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/GraspFci.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/GraspFci.java @@ -36,23 +36,21 @@ import static edu.cmu.tetrad.graph.GraphUtils.gfciExtraEdgeRemovalStep; /** - *

Uses GRaSP in place of FGES for the initial step in the GFCI algorithm. - * This tends to produce a accurate PAG than GFCI as a result, for the latent variables case. This is a simple - * substitution; the reference for GFCI is here:

- *

J.M. Ogarrio and P. Spirtes and J. Ramsey, "A Hybrid Causal Search Algorithm - * for Latent Variable Models," JMLR 2016. Here, BOSS has been substituted for FGES.

- * - *

For the first step, the GRaSP algorithm is used, with the same - * modifications as in the GFCI algorithm.

- * - *

For the second step, the FCI final orientation algorithm is used, with the same - * modifications as in the GFCI algorithm.

- * - *

For GRaSP only a score is needed, but there are steps in GFCI that require - * a test, so for this method, both a test and a score need to be given.

- * - *

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

+ * Uses GRaSP in place of FGES for the initial step in the GFCI algorithm. This tends to produce a accurate PAG than + * GFCI as a result, for the latent variables case. This is a simple substitution; the reference for GFCI is here: J.M. + * Ogarrio and P. Spirtes and J. Ramsey, "A Hybrid Causal Search Algorithm for Latent Variable Models," JMLR 2016. Here, + * BOSS has been substituted for FGES. + *

+ * For the first step, the GRaSP algorithm is used, with the same modifications as in the GFCI algorithm. + *

+ * For the second step, the FCI final orientation algorithm is used, with the same modifications as in the GFCI + * algorithm. + *

+ * For GRaSP only a score is needed, but there are steps in GFCI that require a test, so for this method, both a test + * and a score need to be given. + *

+ * This class is configured to respect knowledge of forbidden and required edges, including knowledge of temporal + * tiers. * * @author josephramsey * @author bryanandrews @@ -77,16 +75,33 @@ public final class GraspFci implements IGraphSearch { private int maxPathLength = -1; // True iff verbose output should be printed. private boolean verbose; + // The number of starts for GRaSP. private int numStarts = 1; - private int depth = -1; + + // Whether to use Raskutti and Uhler's modification of GRaSP. private boolean useRaskuttiUhler = false; + // Whether to use data order. private boolean useDataOrder = true; + // Whether to use score. private boolean useScore = true; + // Whether to use the discriminating path rule. private boolean doDiscriminatingPathRule = true; + // Whether to use the ordered version of GRaSP. private boolean ordered = false; + // The depth for GRaSP. + private int depth = -1; + // The depth for singular variables. private int uncoveredDepth = 1; + // The depth for non-singular variables. private int nonSingularDepth = 1; + private long seed = -1; + /** + * Constructs a new GraspFci object. + * + * @param test The independence test. + * @param score + */ public GraspFci(IndependenceTest test, Score score) { if (score == null) { throw new NullPointerException(); @@ -114,6 +129,7 @@ public Graph search() { // The PAG being constructed. // Run GRaSP to get a CPDAG (like GFCI with FGES)... Grasp alg = new Grasp(independenceTest, score); + alg.setSeed(seed); alg.setOrdered(ordered); alg.setUseScore(useScore); alg.setUseRaskuttiUhler(useRaskuttiUhler); @@ -195,41 +211,90 @@ public void setVerbose(boolean verbose) { this.verbose = verbose; } + /** + * Sets the number of starts for GRaSP. + * + * @param numStarts The number of starts. + */ public void setNumStarts(int numStarts) { this.numStarts = numStarts; } + /** + * Sets the depth for GRaSP. + * + * @param depth The depth. + */ public void setDepth(int depth) { this.depth = depth; } + /** + * Sets whether to use Raskutti and Uhler's modification of GRaSP. + * + * @param useRaskuttiUhler True, if so. + */ public void setUseRaskuttiUhler(boolean useRaskuttiUhler) { this.useRaskuttiUhler = useRaskuttiUhler; } + /** + * Sets whether to use data order for GRaSP (as opposed to random order) for the first step of GRaSP + * + * @param useDataOrder True, if so. + */ public void setUseDataOrder(boolean useDataOrder) { this.useDataOrder = useDataOrder; } + /** + * Sets whether to use score for GRaSP (as opposed to independence test) for GRaSP. + * + * @param useScore True, if so. + */ public void setUseScore(boolean useScore) { this.useScore = useScore; } + /** + * Sets whether to use the discriminating path rule for GRaSP. + * + * @param doDiscriminatingPathRule True, if so. + */ public void setDoDiscriminatingPathRule(boolean doDiscriminatingPathRule) { this.doDiscriminatingPathRule = doDiscriminatingPathRule; } + /** + * Sets depth for singular tucks. + * + * @param uncoveredDepth The depth for singular tucks. + */ public void setSingularDepth(int uncoveredDepth) { if (uncoveredDepth < -1) throw new IllegalArgumentException("Uncovered depth should be >= -1."); this.uncoveredDepth = uncoveredDepth; } + /** + * Sets depth for non-singular tucks. + * + * @param nonSingularDepth The depth for non-singular tucks. + */ public void setNonSingularDepth(int nonSingularDepth) { if (nonSingularDepth < -1) throw new IllegalArgumentException("Non-singular depth should be >= -1."); this.nonSingularDepth = nonSingularDepth; } + /** + * Sets whether to use the ordered version of GRaSP. + * + * @param ordered True, if so. + */ public void setOrdered(boolean ordered) { this.ordered = ordered; } + + public void setSeed(long seed) { + this.seed = seed; + } } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/GrowShrink.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/GrowShrink.java index ad6de83903..93f8138f1c 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/GrowShrink.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/GrowShrink.java @@ -29,29 +29,27 @@ import java.util.Set; /** - *

Implements the Grow-Shrink algorithm of Margaritis and Thrun, a simple yet - * correct and useful Markov blanket search.

+ * Implements the Grow-Shrink algorithm of Margaritis and Thrun, a simple yet correct and useful Markov blanket search. + *

+ * Margaritis, D., & Thrun, S. (1999). Bayesian network induction via local neighborhoods. Advances in neural + * information processing systems, 12. + *

+ * Grow-Shrink learns the Markov blanket of a node, given a conditional independence test over a list of possible nodes. + * The Markov blanket is a set of nodes (or, in this case a list of distinct nodes), conditional on which every other + * node in the set is independent of X. In this case, a minimal Markov blanket is learned, which is to say, a Markov + * boundary of X. + *

+ * Graphically, in a DAG, the Markov blanket of X is the set of parents, children, and parents of children of X; + * GrowShrink will, for a faithful test, learn this set for X. However, a graph over the nodes together with X is not + * learned; other algorithms are available to do that (see, e.g., FgesMb, PcMb). + *

+ * We include GrowShrink in our algorithm suite mainly because it is a CMU algorithm (see the above reference). Markov + * blanket search has been explored in some detail in the literature and several algorithms are available. See for + * instance the BNLEARN package in R: * - *

Margaritis, D., & Thrun, S. (1999). Bayesian network induction via local - * neighborhoods. Advances in neural information processing systems, 12.

- * - *

Grow-Shrink learns the Markov blanket of a node, given a conditional independence - * test over a list of possible nodes. The Markov blanket is a set of nodes (or, in this case a list of distinct nodes), - * conditional on which every other node in the set is independent of X. In this case, a minimal Markov blanket is - * learned, which is to say, a Markov boundary of X.

- * - *

Graphically, in a DAG, the Markov blanket of X is the set of parents, children, and - * parents of children of X; GrowShrink will, for a faithful test, learn this set for X. However, a graph over the nodes - * together with X is not learned; other algorithms are available to do that (see, e.g., FgesMb, PcMb).

- * - *

We include GrowShrink in our algorithm suite mainly because it is a CMU algorithm - * (see the above reference). Markov blanket search has been explored in some detail in the literature and several - * algorithms are available. See for instance the BNLEARN package in R:

- * - *

https://www.bnlearn.com

- * - *

This class is not configured to respect knowledge of forbidden and required - * edges.

+ * https://www.bnlearn.com + *

+ * This class is not configured to respect knowledge of forbidden and required edges. * * @author josephramsey * @see FgesMb @@ -59,16 +57,9 @@ */ public class GrowShrink implements IMbSearch { - /** - * The independence test used to perform the search. - */ + // The independence test used to perform the search. private final IndependenceTest independenceTest; - /** - * The list of variables being searched over. Must contain the target. - */ - private final List variables; - /** * Constructs a new search. * @@ -80,7 +71,8 @@ public GrowShrink(IndependenceTest test) { } this.independenceTest = test; - this.variables = test.getVariables(); + // The list of variables being searched over. Must contain the target. + List variables = test.getVariables(); } /** @@ -92,36 +84,19 @@ public GrowShrink(IndependenceTest test) { public Set findMb(Node target) { Set blanket = new HashSet<>(); - boolean changed = true; - - while (changed) { - changed = false; + List nodes = independenceTest.getVariables(); - List remaining = new LinkedList<>(this.variables); - remaining.removeAll(blanket); - remaining.remove(target); - - for (Node node : remaining) { - if (!this.independenceTest.checkIndependence(node, target, blanket).isIndependent()) { - blanket.add(node); - changed = true; - } + for (Node node : nodes) { + if (node == target) continue; + if (!independenceTest.checkIndependence(node, target, blanket).isIndependent()) { + blanket.add(node); } } - changed = true; - - while (changed) { - changed = false; - - for (Node node : new LinkedList<>(blanket)) { - blanket.remove(node); - - if (this.independenceTest.checkIndependence(node, target, blanket).isIndependent()) { - changed = true; - continue; - } - + for (Node node : new LinkedList<>(blanket)) { + HashSet z = new HashSet<>(blanket); + blanket.remove(node); + if (!independenceTest.checkIndependence(node, target, z).isIndependent()) { blanket.add(node); } } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/IcaLingD.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/IcaLingD.java index 39c5ec9db1..5def17ef13 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/IcaLingD.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/IcaLingD.java @@ -45,50 +45,49 @@ import static org.apache.commons.math3.util.FastMath.*; /** - *

Implements the ICA-LiNG-D algorithm as well as a number of ancillary methods for - * LiNG-D and LiNGAM. The reference is here:

- * - *

Lacerda, G., Spirtes, P. L., Ramsey, J., & Hoyer, P. O. (2012). Discovering - * cyclic causal models by independent components analysis. arXiv preprint arXiv:1206.3273.

- * - *

ICA-LING-D is a method for estimating a possible cyclic linear models graph - * from a dataset. It is based on the assumption that the data are generated by a linear model with non-Gaussian noise. - * The method is based on the following assumptions:

- * + * Implements the ICA-LiNG-D algorithm as well as a number of ancillary methods for LiNG-D and LiNGAM. The reference is + * here: + *

+ * Lacerda, G., Spirtes, P. L., Ramsey, J., & Hoyer, P. O. (2012). Discovering cyclic causal models by independent + * components analysis. arXiv preprint arXiv:1206.3273. + *

+ * ICA-LING-D is a method for estimating a possible cyclic linear models graph from a dataset. It is based on the + * assumption that the data are generated by a linear model with non-Gaussian noise. The method is based on the + * following assumptions: *

    *
  1. The data are generated by a linear model with non-Gaussian noise.
  2. *
  3. The noise is independent across variables.
  4. *
  5. The noises for all but possibly one variable are non-Gaussian.
  6. *
  7. There is no unobserved confounding.
  8. *
- * - *

lower bound of the absolute value of the coefficients in the W matrix.

- * - *

Under these assumptions, the method estimates a matrix W such that WX = e, where + *

+ * lower bound of the absolute value of the coefficients in the W matrix. + *

+ * Under these assumptions, the method estimates a matrix W such that WX = e, where * X is the data matrix, e is a matrix of noise, and W is a matrix of coefficients. * The matrix W is then used to estimate a matrix B Hat, where B Hat is the matrix * of coefficients in the linear model that generated the data. The graph is then - * estimated by finding edges in B Hat.

- * - *

We use the N Rooks algorithm to find alternative diagonals for + * estimated by finding edges in B Hat. + *

+ * We use the N Rooks algorithm to find alternative diagonals for * permutations of the W matrix. The parameter that N Rooks requires is a * threshold for entries in W to be included in possible diagonals, which * is the lowest number in absolute value that a W matrix entry can take * to be part of a diagonal; the implied permutations is the permutations * that permutes rows so that these combination lies along the their * respective diagonals in W, which are then scaled, and the separate - * satisfactory B Hat matrices reported.

- * - *

ICA-LiNG-D, which takes this W as an impute, is a method for estimating + * satisfactory B Hat matrices reported. + *

+ * ICA-LiNG-D, which takes this W as an impute, is a method for estimating * a directed graph (DG) from a dataset. The graph is estimated by finding a * permutation of the columns of the dataset so that the resulting matrix has * a strong diagonal. This permutation is then used to estimate a DG. The method * is an relaxation of LiNGAM, which estimates a DAG from a dataset using * independent components analysis (ICA). LiNG-D is particularly useful when the - * underlying data may have multiple consistent cyclic models.

- * - *

This class is not configured to respect knowledge of forbidden and required - * edges.

+ * underlying data may have multiple consistent cyclic models. + *

+ * This class is not configured to respect knowledge of forbidden and required + * edges. * * @author peterspirtes * @author gustavolacerda @@ -97,7 +96,9 @@ * @see IcaLingam */ public class IcaLingD { + // The threshold for the spine of the W matrix. private double spineThreshold = 0.5; + // The threshold to use for set small elements to zero in the B Hat matrices. private double bThreshold = 0.1; /** @@ -196,8 +197,8 @@ public static PermutationMatrixPair hungarianDiagonal(Matrix W) { } /** - * Whether the BHat matrix represents a stable model. - * The eigenvalues are checked to make sure they are all less than 1 in modulus. + * Whether the BHat matrix represents a stable model. The eigenvalues are checked to make sure they are all less + * than 1 in modulus. * * @param bHat The bHat matrix. * @return True iff the model is stable. diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/IcaLingam.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/IcaLingam.java index a7de3704cb..5d07a078fc 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/IcaLingam.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/IcaLingam.java @@ -32,19 +32,18 @@ import static org.apache.commons.math3.util.FastMath.abs; /** - *

Implements the ICA-LiNGAM algorithm. The reference is here:

- * - *

Shimizu, S., Hoyer, P. O., Hyvärinen, A., Kerminen, A., & Jordan, M. (2006). - * A linear non-Gaussian acyclic model for causal discovery. Journal of Machine Learning Research, 7(10).

- * - *

The focus for this implementation was to make a version of ICA-LiNGAM that - * would be compatible with LiNG-D (see). There are two parameters, one to choose whether an acyclic result will be - * guaranteed, and another to set a threshold on the lower bound of the absolute value of the coefficients in the B Hat - * matrix. The latter is used to find edges in the final graph.

- * - *

ICA-LiNGAM is a method for estimating a causal graph from a dataset. It is based on - * the assumption that the data are generated by a linear model with non-Gaussian noise. The method is based on the - * following assumptions:

+ * Implements the ICA-LiNGAM algorithm. The reference is here: + *

+ * Shimizu, S., Hoyer, P. O., Hyvärinen, A., Kerminen, A., & Jordan, M. (2006). A linear non-Gaussian acyclic model + * for causal discovery. Journal of Machine Learning Research, 7(10). + *

+ * The focus for this implementation was to make a version of ICA-LiNGAM that would be compatible with LiNG-D (see). + * There are two parameters, one to choose whether an acyclic result will be guaranteed, and another to set a threshold + * on the lower bound of the absolute value of the coefficients in the B Hat matrix. The latter is used to find edges in + * the final graph. + *

+ * ICA-LiNGAM is a method for estimating a causal graph from a dataset. It is based on the assumption that the data are + * generated by a linear model with non-Gaussian noise. The method is based on the following assumptions: * *

    *
  1. The data are generated by a linear model with non-Gaussian noise.
  2. @@ -52,27 +51,27 @@ *
  3. The noises for all but possibly one variable are non-Gaussian.
  4. *
  5. There is no unobserved confounding.
  6. *
- * - *

Under these assumptions, the method estimates a matrix W such that WX = e, where + *

+ * Under these assumptions, the method estimates a matrix W such that WX = e, where * X is the data matrix, e is a matrix of noise, and W is a matrix of coefficients. * The matrix W is then used to estimate a matrix B Hat, where B Hat is the matrix * of coefficients in the linear model that generated the data. The graph is then - * estimated by finding edges in B Hat.

- * - *

There is an option to guarantee the acyclicity of the output, which will set + * estimated by finding edges in B Hat. + *

+ * There is an option to guarantee the acyclicity of the output, which will set * small coefficients to zero until an acyclic model is achieved. If this option * is not selected, coefficients below the selected threshold will be set to - * zero, which allows for certain cyclic structures to be recovered.

- * - *

There are two methods for estimating W. The first is the default method, + * zero, which allows for certain cyclic structures to be recovered. + *

+ * There are two methods for estimating W. The first is the default method, * which is to use the ICA-LiNG-D algorithm to estimate W. The second is to provide * a W matrix estimated by some other method. The latter method is useful for - * comparing the performance of ICA-LiNGAM to other methods.

- * - *

There is an option to set a threshold on the coefficients in B Hat. This - * threshold is used to find edges in the final graph.

- * - *

The method is implemented as follows:

+ * comparing the performance of ICA-LiNGAM to other methods. + *

+ * There is an option to set a threshold on the coefficients in B Hat. This + * threshold is used to find edges in the final graph. + *

+ * The method is implemented as follows: * *

    *
  1. Estimate W using LiNG-D or using a user-provided W matrix.
  2. @@ -82,19 +81,21 @@ *
  3. If acyclicity is guaranteed, set small coefficients to zero until an acyclic * model is achieved.
  4. *
- * - *

We are using the Hungarian Algorithm to solve the linear assignment problem - * for finding the best diagonal for W.

- * - *

This class is not configured to respect knowledge of forbidden and required - * edges.

+ *

+ * We are using the Hungarian Algorithm to solve the linear assignment problem + * for finding the best diagonal for W. + *

+ * This class is not configured to respect knowledge of forbidden and required + * edges. * * @author josephramsey * @see IcaLingD * @see edu.cmu.tetrad.search.utils.HungarianAlgorithm */ public class IcaLingam { + // The threshold to use for set small elements to zero in the B Hat matrices. private double bThreshold = 0.1; + // Whether the ICA-LiNGAM algorithm is guaranteed to produce an acyclic graph. private boolean acyclicityGuaranteed = true; /** diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Ida.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Ida.java index 586627ef7a..ce897e3353 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Ida.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Ida.java @@ -1,6 +1,9 @@ package edu.cmu.tetrad.search; -import edu.cmu.tetrad.data.*; +import edu.cmu.tetrad.data.CovarianceMatrix; +import edu.cmu.tetrad.data.DataSet; +import edu.cmu.tetrad.data.DataTransforms; +import edu.cmu.tetrad.data.ICovarianceMatrix; import edu.cmu.tetrad.graph.Graph; import edu.cmu.tetrad.graph.GraphUtils; import edu.cmu.tetrad.graph.Node; @@ -17,24 +20,28 @@ import static org.apache.commons.math3.util.FastMath.min; /** - *

Implements the IDA algorithm. The reference is here:

- * - *

Maathuis, Marloes H., Markus Kalisch, and Peter Bühlmann. - * "Estimating high-dimensional intervention effects from observational data." The Annals of Statistics 37.6A (2009): - * 3133-3164.

- * - *

The IDA algorithm seeks to give a list of possible parents - * of a given variable Y and their corresponding lower-bounded effects on Y.

+ * Implements the IDA algorithm. The reference is here: + *

+ * Maathuis, Marloes H., Markus Kalisch, and Peter Bühlmann. "Estimating high-dimensional intervention effects from + * observational data." The Annals of Statistics 37.6A (2009): 3133-3164. + *

+ * The IDA algorithm seeks to give a list of possible parents of a given variable Y and their corresponding + * lower-bounded effects on Y. * * @author josephramsey * @see Cstar * @see NodeEffects */ public class Ida { + // The dataset being searched over. private final DataSet dataSet; - private final Graph pattern; + // The CPDAG (found, e.g., by running PC, or some other CPDAG producing algorithm. + private final Graph cpdag; + // The possible causes to be considered. private final List possibleCauses; + // A map from node names to indices in the covariance matrix. private final Map nodeIndices; + // The covariance matrix for the dataset. private final ICovarianceMatrix allCovariances; /** @@ -46,7 +53,7 @@ public class Ida { */ public Ida(DataSet dataSet, Graph cpdag, List possibleCauses) { this.dataSet = DataTransforms.convertNumericalDiscreteToContinuous(dataSet); - this.pattern = cpdag; + this.cpdag = cpdag; possibleCauses = GraphUtils.replaceNodes(possibleCauses, dataSet.getVariables()); this.possibleCauses = possibleCauses; @@ -144,10 +151,10 @@ public double distance(LinkedList effects, double trueEffect) { * @return a list of the possible effects of X on Y. */ private LinkedList getEffects(Node x, Node y) { - List parents = this.pattern.getParents(x); - List children = this.pattern.getChildren(x); + List parents = this.cpdag.getParents(x); + List children = this.cpdag.getChildren(x); - List siblings = new ArrayList<>(this.pattern.getAdjacentNodes(x)); + List siblings = new ArrayList<>(this.cpdag.getAdjacentNodes(x)); siblings.removeAll(parents); siblings.removeAll(children); @@ -167,14 +174,14 @@ private LinkedList getEffects(Node x, Node y) { while ((choice2 = gen2.next()) != null) { List adj = GraphUtils.asList(choice2, sibbled); - if (!this.pattern.isAdjacentTo(adj.get(0), adj.get(1))) continue CHOICE; + if (!this.cpdag.isAdjacentTo(adj.get(0), adj.get(1))) continue CHOICE; } } if (!sibbled.isEmpty()) { for (Node p : parents) { for (Node s : sibbled) { - if (!this.pattern.isAdjacentTo(p, s)) continue CHOICE; + if (!this.cpdag.isAdjacentTo(p, s)) continue CHOICE; } } } @@ -209,7 +216,7 @@ public Map calculateMinimumEffectsOnY(Node y) { SortedMap minEffects = new TreeMap<>(); for (Node x : this.possibleCauses) { - if (!(this.pattern.containsNode(x) && this.pattern.containsNode(y))) continue; + if (!(this.cpdag.containsNode(x) && this.cpdag.containsNode(y))) continue; LinkedList effects = getEffects(x, y); minEffects.put(x, effects.getFirst()); @@ -249,30 +256,63 @@ private double getBeta(List regressors, Node child) { * @author josephramsey */ public static class NodeEffects { + // The nodes. private List nodes; + // The effects. private LinkedList effects; + /** + * Constructor. + * + * @param nodes The nodes. + * @param effects The effects. + */ NodeEffects(List nodes, LinkedList effects) { this.setNodes(nodes); this.setEffects(effects); } + /** + * Returns the nodes. + * + * @return The nodes. + */ public List getNodes() { return this.nodes; } + /** + * Sets the nodes. + * + * @param nodes The nodes. + */ public void setNodes(List nodes) { this.nodes = nodes; } + /** + * Returns the effects. + * + * @return The effects. + */ public LinkedList getEffects() { return this.effects; } + /** + * Sets the effects. + * + * @param effects The effects. + */ public void setEffects(LinkedList effects) { this.effects = effects; } + /** + * Returns a string representation of this object. + * + * @return A string representation of this object. + */ public String toString() { StringBuilder b = new StringBuilder(); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/IndTestIod.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/IndTestIod.java index bd5cd3e3e0..bd8d625afe 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/IndTestIod.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/IndTestIod.java @@ -33,25 +33,27 @@ /** - *

Checks independence result by listing all tests with those variables, testing each one, and returning the - * resolution of these test results. The reference is here:

- * - *

Tillman, R., & Spirtes, P. (2011, June). Learning equivalence classes of acyclic models with latent and selection + * Checks independence result by listing all tests with those variables, testing each one, and returning the resolution + * of these test results. The reference is here: + *

+ * Tillman, R., & Spirtes, P. (2011, June). Learning equivalence classes of acyclic models with latent and selection * variables from multiple datasets with overlapping variables. In Proceedings of the Fourteenth International - * Conference on Artificial Intelligence and Statistics (pp. 3-15). JMLR Workshop and Conference Proceedings.

- * - *

The idea of this implementation is that one initializes this test with multiple independence tests (for multiple + * Conference on Artificial Intelligence and Statistics (pp. 3-15). JMLR Workshop and Conference Proceedings. + *

+ * The idea of this implementation is that one initializes this test with multiple independence tests (for multiple * datasets), then a call to the independence check method for X _||_ Y | Z list the independence tests from among - * these, calls each and gets a p-value, then uses a resolution method (such as Fisher's) to resolve these - * p-values.

- * - *

Based on work by Rob Tillman, Peter Spirtes, and referencing earlier work by David Danks.

+ * these, calls each and gets a p-value, then uses a resolution method (such as Fisher's) to resolve these p-values. + *

+ * Based on work by Rob Tillman, Peter Spirtes, and referencing earlier work by David Danks. * * @author josephramsey */ public class IndTestIod implements IndependenceTest { + // The list of nodes over which this independence checker is capable of determining independence relations. private final List nodeList; + // The list of independence tests. private final List tests; + // Whether the test is verbose. private boolean verbose; /** diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/IndependenceTest.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/IndependenceTest.java index 35db551a9a..dc51027613 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/IndependenceTest.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/IndependenceTest.java @@ -34,9 +34,9 @@ import java.util.Set; /** - *

Gives an interface that can be implemented by classes that do conditional - * independence testing. These classes are capable of serving as conditional independence "oracles" for constraint-based - * searches. Many methods are given defaults so that such a test will be easy to implement in Python using JPype.

+ * Gives an interface that can be implemented by classes that do conditional independence testing. These classes are + * capable of serving as conditional independence "oracles" for constraint-based searches. Many methods are given + * defaults so that such a test will be easy to implement in Python using JPype. * * @author josephramsey */ diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Lofs.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Lofs.java index 7cee5b015a..27f6769d37 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Lofs.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Lofs.java @@ -41,18 +41,17 @@ import static org.apache.commons.math3.util.FastMath.*; /** - *

Implements a number of methods which take a fixed graph as input and use linear, - * non-Gaussian methods to orient the edges in the graph. where the acronym stands for linear, non-Gaussian Orientation - * with a Fixed graph Structure (LOFS). The options for different types of scores are given in the enum Lofs.Score. The - * options for rules to use to do the orientations are given in the enum, Lofs.Rule. Most of these are taken from the - * literature and can be googled, though we should certainly give this reference for several of them, to which we are - * indebted:

- * - *

Hyvärinen, A., & Smith, S. M. (2013). Pairwise likelihood ratios for estimation - * of non-Gaussian structural equation models. The Journal of Machine Learning Research, 14(1), 111-152.

- * - *

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

+ * Implements a number of methods which take a fixed graph as input and use linear, non-Gaussian methods to orient the + * edges in the graph. where the acronym stands for linear, non-Gaussian Orientation with a Fixed graph Structure + * (LOFS). The options for different types of scores are given in the enum Lofs.Score. The options for rules to use to + * do the orientations are given in the enum, Lofs.Rule. Most of these are taken from the literature and can be googled, + * though we should certainly give this reference for several of them, to which we are indebted: + *

+ * Hyvärinen, A., & Smith, S. M. (2013). Pairwise likelihood ratios for estimation of non-Gaussian structural + * equation models. The Journal of Machine Learning Research, 14(1), 111-152. + *

+ * This class is configured to respect knowledge of forbidden and required edges, including knowledge of temporal + * tiers. * * @author josephramsey * @see Score @@ -60,22 +59,37 @@ * @see Knowledge */ public class Lofs { - + // The graph to be oriented. private final Graph cpdag; + // The square root of 2 * pi. private final double SQRT = sqrt(2. * PI); + // The data to use to do the orientation. Matrix _data; + // The data to use to do the orientation. private List dataSets; + // The matrices to use to do the orientation. private List matrices; + // The alpha to use, where applicable. private double alpha = 1.1; + // The regressions to use to do the orientation. private List regressions; + // The variables to use to do the orientation. private List variables; + // Whether orientation should be done in the stronger direction, where applicable. private boolean orientStrongerDirection; + // For R2, whether cycles should be oriented. private boolean r2Orient2Cycles = true; + // The (LoFS) score to use. private Lofs.Score score = Lofs.Score.andersonDarling; + // The self-loop strength, if applicable. private double epsilon = 1.0; + // The knowledge to use to do the orientation. private Knowledge knowledge = new Knowledge(); + // The rule to use to do the orientation. private Rule rule = Rule.R1; + // The number of variables. private double selfLoopStrength; + // The number of variables. private double[] col; /** diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/MarkovCheck.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/MarkovCheck.java index bca58d5fcc..f5427cad65 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/MarkovCheck.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/MarkovCheck.java @@ -1,14 +1,20 @@ package edu.cmu.tetrad.search; +import edu.cmu.tetrad.data.GeneralAndersonDarlingTest; +import edu.cmu.tetrad.data.Knowledge; import edu.cmu.tetrad.graph.Graph; import edu.cmu.tetrad.graph.GraphUtils; import edu.cmu.tetrad.graph.IndependenceFact; import edu.cmu.tetrad.graph.Node; import edu.cmu.tetrad.search.test.IndependenceResult; import edu.cmu.tetrad.search.test.MsepTest; +import edu.cmu.tetrad.search.test.RowsSettable; import edu.cmu.tetrad.util.SublistGenerator; import edu.cmu.tetrad.util.UniformityTest; +import org.apache.commons.math3.distribution.BinomialDistribution; +import org.apache.commons.math3.distribution.UniformRealDistribution; import org.apache.commons.math3.util.FastMath; +import org.apache.commons.math3.util.Pair; import org.jetbrains.annotations.NotNull; import java.util.*; @@ -17,143 +23,110 @@ import java.util.concurrent.ForkJoinPool; import java.util.concurrent.Future; -import static org.apache.commons.math3.util.FastMath.min; - /** - *

Checks whether a graph is locally Markov or locally Faithful given a data set. First a lists of m-separation - * predictions are made for each pair of variables in the graph given the parents of one of the variables, one list (for - * local Markov) where the m-separation holds and another list (for local Faithfulness) where the m-separation does not - * hold. Then the predictions are tested against the data set using the independence test. For the Markov test, since an - * independence test yielding p-values should be Uniform under the null hypothesis, these p-values are tested for - * Uniformity using the Kolmogorov-Smirnov test. Also, a fraction of dependent judgments is returned, which should equal - * the alpha level of the independence test if the test is Uniform under the null hypothesis. For the Faithfulness test, - * the p-values are tested for Uniformity using the Kolmogorov-Smirnov test; these should be dependent. Also, a fraction - * of dependent judgments is returned, which should be maximal./p> - * - *

A "Markov adequacy score" is also given, which simply returns zero if the Markov p-value Uniformity test - * fails and the fraction of dependent judgments for the local Faithfulness check otherwise. Maximizing this score picks - * out models for which Markov holds and faithfulness holds to the extend possible; these model should generally have - * good accuracy scores.

+ * Checks whether a graph is locally Markov or locally Faithful given a data set. First, a list of m-separation + * predictions are made for each pair of variables in the graph given the parents of one of the variables. One list (for + * local Markov) is for where the m-separation holds and another list (for local Faithfulness) where the m-separation + * does not hold. Then the predictions are tested against the data set using the independence test. For the Markov test, + * since an independence test yielding p-values should be Uniform under the null hypothesis, these p-values are tested + * for Uniformity using the Kolmogorov-Smirnov test. Also, a fraction of dependent judgments is returned, which should + * equal the alpha level of the independence test if the test is Uniform under the null hypothesis. For the Faithfulness + * test, the p-values are tested for Uniformity using the Kolmogorov-Smirnov test; these should be dependent. Also, a + * fraction of dependent judgments is returned, which should be maximal. + *

+ * Knowledge may be supplied to the Markov check. This knowledge is used to specify independence and conditioning + * ranges. For facts of the form X _||_ Y | Z, X and Y should be in the last tier of the knowledge, and Z should be in + * previous tiers. Additional forbidden or required edges are not allowed. * * @author josephramsey */ public class MarkovCheck { - + // The graph. private final Graph graph; + // The independence test. private final IndependenceTest independenceTest; - private final MsepTest msep; + // The results of the Markov check for the independent case. private final List resultsIndep = new ArrayList<>(); + // The results of the Markov check for the dependent case. private final List resultsDep = new ArrayList<>(); + // The type of conditioning sets to use in the Markov check. private ConditioningSetType setType; + // True if the checks should be parallelized. (Not always a good idea.) private boolean parallelized = false; + // The fraction of dependent judgments for the independent case. private double fractionDependentIndep = Double.NaN; + // The fraction of dependent judgments for the dependent case. private double fractionDependentDep = Double.NaN; + // The Kolmogorov-Smirnov p-value for the independent case. private double ksPValueIndep = Double.NaN; + // The Kolmogorov-Smirnov p-value for the dependent case. private double ksPValueDep = Double.NaN; + // The Anderson-Darling A^2 statistic for the independent case. + private double aSquaredIndep = Double.NaN; + // The Anderson-Darling A^2 statistic for the dependent case. + private double aSquaredDep = Double.NaN; + // The Anderson-Darling A^2* statistic for the independent case. + private double aSquaredStarIndep = Double.NaN; + // The Anderson-Darling A^2* statistic for the dependent case. + private double aSquaredStarDep = Double.NaN; + // The Anderson-Darling p-value for the independent case. + private double andersonDarlingPIndep = Double.NaN; + // The Anderson-Darling p-value for the dependent case. + private double andersonDarlingPDep = Double.NaN; + // The Binomial p-value for the independent case. + private double binomialPIndep = Double.NaN; + // The Binomial p-value for the dependent case. + private double binomialPDep = Double.NaN; + // The percentage of all samples to use when resampling for each conditional independence test. + private double percentResample = 0.5; + // The number of tests for the independent case. + private int numTestsIndep = 0; + // The number of tests for the dependent case. + private int numTestsDep = 0; + // A knowledge object to specify independence and conditioning ranges. Empty by default. + private Knowledge knowledge = new Knowledge(); + // For X _||_ Y | Z, X and Y must come from this set if knowledge is used. + private List independenceNodes; + // For X _||_ Y | Z, the nodes in Z must come from this set if knowledge is used. + private List conditioningNodes; /** * Constructor. Takes a graph and an independence test over the variables of the graph. * * @param graph The graph. * @param independenceTest The test over the variables of the graph. + * @param setType The type of conditioning sets to use in the Markov check. */ public MarkovCheck(Graph graph, IndependenceTest independenceTest, ConditioningSetType setType) { this.graph = GraphUtils.replaceNodes(graph, independenceTest.getVariables()); this.independenceTest = independenceTest; - this.msep = new MsepTest(this.graph); this.setType = setType; + this.independenceNodes = new ArrayList<>(independenceTest.getVariables()); + this.conditioningNodes = new ArrayList<>(independenceTest.getVariables()); } /** - * Generates all results, for both the local Markov and local Faithfulness checks, for each node in the graph given - * the parents of that node. These results are stored in the resultsIndep and resultsDep lists. + * Returns the set of independence facts used in the Markov check, for dseparation and dconnection separately. * - * @see #getResults(boolean) + * @return The set of independence facts used in the Markov check, for dseparation and dconnection separately. */ - public void generateResults() { - resultsIndep.clear(); - resultsDep.clear(); - - if (setType == ConditioningSetType.GLOBAL_MARKOV) { - AllSubsetsIndependenceFacts result = getAllSubsetsIndependenceFacts(graph); - generateResultsAllSubsets(true, result.msep, result.mconn); - generateResultsAllSubsets(false, result.msep, result.mconn); - } else { - List variables = independenceTest.getVariables(); - List nodes = new ArrayList<>(variables); - Collections.sort(nodes); - - List order = graph.paths().getValidOrder(graph.getNodes(), true); - - for (Node x : nodes) { - Set z; - - switch (setType) { - case LOCAL_MARKOV: - z = new HashSet<>(graph.getParents(x)); - break; - case ORDERED_LOCAL_MARKOV: - if (order == null) throw new IllegalArgumentException("No valid order found."); - z = new HashSet<>(graph.getParents(x)); - - // Keep only the parents in Prefix(x). - for (Node w : new ArrayList<>(z)) { - int i1 = order.indexOf(x); - int i2 = order.indexOf(w); - - if (i2 >= i1) { - z.remove(w); - } - } - - break; - case MARKOV_BLANKET: - z = GraphUtils.markovBlanket(x, graph); - break; - default: - throw new IllegalArgumentException("Unknown separation set type: " + setType); - } - - Set msep = new HashSet<>(); - Set mconn = new HashSet<>(); - - List other = new ArrayList<>(graph.getNodes()); - Collections.sort(other); - other.removeAll(z); - - for (Node y : other) { - if (y == x) continue; - if (z.contains(x) || z.contains(y)) continue; - if (this.msep.isMSeparated(x, y, z)) { - msep.add(y); - } else { - mconn.add(y); - } - } + @NotNull + public AllSubsetsIndependenceFacts getAllSubsetsIndependenceFacts() { + List variables = new ArrayList<>(getVariables(graph.getNodes(), independenceNodes, conditioningNodes)); - generateResults(true, x, z, msep, mconn); - generateResults(false, x, z, msep, mconn); - } + for (Node node : variables) { + if (node == null) throw new NullPointerException("Null node in graph."); } - calcStats(true); - calcStats(false); - } - @NotNull - public static AllSubsetsIndependenceFacts getAllSubsetsIndependenceFacts(Graph graph) { - List variables = new ArrayList<>(graph.getNodes()); MsepTest msepTest = new MsepTest(graph); List nodes = new ArrayList<>(variables); - Collections.sort(nodes); - - List msep = new ArrayList<>(); - List mconn = new ArrayList<>(); + Set msep = new HashSet<>(); + Set mconn = new HashSet<>(); for (Node x : nodes) { List other = new ArrayList<>(variables); - Collections.sort(other); other.remove(x); for (Node y : other) { @@ -166,6 +139,11 @@ public static AllSubsetsIndependenceFacts getAllSubsetsIndependenceFacts(Graph g while ((list = generator.next()) != null) { Set z = GraphUtils.asSet(list, _other); + if (!(getIndependenceNodes().contains(x) && getIndependenceNodes().contains(y) + && new HashSet<>(getConditioningNodes()).containsAll(z))) { + continue; + } + if (msepTest.isMSeparated(x, y, z)) { msep.add(new IndependenceFact(x, y, z)); } else { @@ -174,46 +152,115 @@ public static AllSubsetsIndependenceFacts getAllSubsetsIndependenceFacts(Graph g } } } + return new AllSubsetsIndependenceFacts(msep, mconn); } - public static class AllSubsetsIndependenceFacts { - private final List msep; - private final List mconn; + /** + * Returns the variables of the independence test. + * + * @return The variables of the independence test. + */ + public List getVariables(List graphNodes, List independenceNodes, List conditioningNodes) { + List vars = new ArrayList<>(graphNodes); - public AllSubsetsIndependenceFacts(List msep, List mconn) { - this.msep = msep; - this.mconn = mconn; - } + conditioningNodes = new ArrayList<>(conditioningNodes); + independenceNodes = new ArrayList<>(independenceNodes); - public String toStringIndep() { - StringBuilder builder = new StringBuilder("All subsets independence facts:\n"); + List sublistedVariables = independenceNodes; + sublistedVariables.addAll(conditioningNodes); + vars.retainAll(sublistedVariables); - for (IndependenceFact fact : msep) { - builder.append(fact).append("\n"); + return vars; + } + + /** + * Generates all results, for both the local Markov and local Faithfulness checks, for each node in the graph given + * the parents of that node. These results are stored in the resultsIndep and resultsDep lists. This should be + * called before any of the result methods. Note that only results for X _||_ Y | Z1,...,Zn are generated, where X + * and Y are in the independenceNodes list and Z1,...,Zn are in the conditioningNodes list. + * + * @see #getResults(boolean) + */ + public void generateResults() { + resultsIndep.clear(); + resultsDep.clear(); + + if (setType == ConditioningSetType.GLOBAL_MARKOV) { + AllSubsetsIndependenceFacts result = getAllSubsetsIndependenceFacts(); + generateResultsAllSubsets(result.msep, result.mconn); + generateResultsAllSubsets(result.msep, result.mconn); + } else { + List variables = getVariables(graph.getNodes(), independenceNodes, conditioningNodes); + List nodes = new ArrayList<>(variables); + + List order = null; + + try { + order = graph.paths().getValidOrder(graph.getNodes(), true); + } catch (Exception e) { + // Leave null. Not an error here. Just means we can't use the ordered local Markov check. } - return builder.toString(); - } + Set allIndependenceFacts = new HashSet<>(); + Set msep = new HashSet<>(); + Set mconn = new HashSet<>(); + + for (int i = 0; i < nodes.size(); i++) { + for (int j = 0; j < nodes.size(); j++) { + if (i == j) continue; + Node x = nodes.get(i); + Node y = nodes.get(j); + + Set z; + + switch (setType) { + case LOCAL_MARKOV: + z = new HashSet<>(graph.getParents(x)); + break; + case ORDERED_LOCAL_MARKOV: + if (order == null) throw new IllegalArgumentException("No valid order found."); + z = new HashSet<>(graph.getParents(x)); + + // Keep only the parents in Prefix(x). + for (Node w : new ArrayList<>(z)) { + int i1 = order.indexOf(x); + int i2 = order.indexOf(w); + + if (i2 >= i1) { + z.remove(w); + } + } + break; + case MARKOV_BLANKET: + z = GraphUtils.markovBlanket(x, graph); + break; + default: + throw new IllegalArgumentException("Unknown separation set type: " + setType); + } - public String toStringDep() { - StringBuilder builder = new StringBuilder("All subsets independence facts:\n"); + if (x == y || z.contains(x) || z.contains(y)) continue; - for (IndependenceFact fact : mconn) { - builder.append(fact).append("\n"); + if (!(getIndependenceNodes().contains(x) && getIndependenceNodes().contains(y) + && new HashSet<>(getConditioningNodes()).containsAll(z))) { + continue; + } + + allIndependenceFacts.add(new IndependenceFact(x, y, z)); + } } - return builder.toString(); - } + generateMseps(new ArrayList<>(allIndependenceFacts), msep, mconn, new MsepTest(graph)); + generateResults(msep, true); + generateResults(mconn, false); - public List getMsep() { - return msep; + this.numTestsIndep = msep.size(); + this.numTestsDep = mconn.size(); } - public List getMconn() { - return mconn; - } + calcStats(true); + calcStats(false); } /** @@ -305,29 +352,73 @@ public double getKsPValue(boolean indep) { } /** - * Returns the Markov Adequacy Score for the graph. This is zero if the p-value of the KS test of Uniformity is less - * than alpha, and the fraction of dependent pairs otherwise. This is only for continuous Gaussian data, as it - * hard-codes the Fisher Z test for the local Markov and Faithfulness check. + * Returns the Anderson-Darling A^2 statistic for the given list of results. * - * @param alpha The alpha level for the KS test of Uniformity. An alpha level greater than this will be considered - * uniform. - * @return The Markov Adequacy Score for this graph given the data. + * @param indep True if for implied independencies, false if for implied dependencies. + * @return The Anderson-Darling A^2 statistic for the given list of results. */ - public double getMarkovAdequacyScore(double alpha) { - if (getKsPValue(true) > alpha) { - return getFractionDependent(false); + public double getAndersonDarlingA2(boolean indep) { + if (indep) { + return aSquaredIndep; } else { - return 0.0; + return aSquaredDep; } } /** - * Returns the variables of the independence test. + * Returns the Anderson-Darling A^2* statistic for the given list of results. * - * @return The variables of the independence test. + * @param indep True if for implied independencies, false if for implied dependencies. + * @return The Anderson-Darling A^2* statistic for the given list of results. */ - public List getVariables() { - return new ArrayList<>(independenceTest.getVariables()); + public double getAndersonDarlingA2Star(boolean indep) { + if (indep) { + return aSquaredStarIndep; + } else { + return aSquaredStarDep; + } + } + + /** + * Returns the Anderson-Darling p-value for the given list of results. + * + * @param indep True if for implied independencies, false if for implied dependencies. + * @return The Anderson-Darling p-value for the given list of results. + */ + public double getAndersonDarlingP(boolean indep) { + if (indep) { + return andersonDarlingPIndep; + } else { + return andersonDarlingPDep; + } + } + + /** + * Returns the Binomial p-value for the given list of results. + * + * @param indep True if for implied independencies, false if for implied dependencies. + * @return The Binomial p-value for the given list of results. + */ + public double getBinomialP(boolean indep) { + if (indep) { + return binomialPIndep; + } else { + return binomialPDep; + } + } + + /** + * Returns the number of tests for the given list of results. + * + * @param indep True if for implied independencies, false if for implied dependencies. + * @return The number of tests for the given list of results. + */ + public int getNumTests(boolean indep) { + if (indep) { + return numTestsIndep; + } else { + return numTestsDep; + } } /** @@ -349,88 +440,82 @@ public IndependenceTest getIndependenceTest() { return this.independenceTest; } - private void generateResults(boolean indep, Node x, Set z, Set msep, Set mconn) { - List facts = new ArrayList<>(); - - // Listing all facts before checking any (in preparation for parallelization). - if (indep) { - for (Node y : msep) { - if (z.contains(y)) continue; - facts.add(new IndependenceFact(x, y, z)); - } - } else { - for (Node y : mconn) { - if (z.contains(y)) continue; - facts.add(new IndependenceFact(x, y, z)); - } - } + /** + * Sets the percentage of all samples to use when resampling for each conditional independence test. + * + * @param percentResample The percentage of all samples to use when resampling for each conditional independence + * test. + */ + public void setPercentResample(double percentResample) { + this.percentResample = percentResample; + } - class IndCheckTask implements Callable> { - private final int from; - private final int to; + /** + * Generates the m-separation sets for the given list of independence facts. The m-separation sets are stored in the + * msep and mconn sets. + * + * @param allIndependenceFacts The list of independence facts. + * @param msep The set of m-separation facts. + * @param mconn The set of m-connection facts. + * @param msepTest The m-separation test. + */ + private void generateMseps(List allIndependenceFacts, Set msep, Set mconn, + MsepTest msepTest) { + class IndCheckTask implements Callable, Set>> { + private final int index; private final List facts; - private final IndependenceTest independenceTest; + private final MsepTest msepTest; - IndCheckTask(int from, int to, List facts, IndependenceTest test) { - this.from = from; - this.to = to; + IndCheckTask(int index, List facts, MsepTest test) { + this.index = index; this.facts = facts; - this.independenceTest = test; + this.msepTest = test; } @Override - public List call() { - List results = new ArrayList<>(); - - for (int i = from; i < to; i++) { - if (Thread.interrupted()) break; - IndependenceFact fact = facts.get(i); - - Node x = fact.getX(); - Node y = fact.getY(); - Set z = fact.getZ(); - boolean verbose = independenceTest.isVerbose(); - independenceTest.setVerbose(false); - IndependenceResult result; - try { - result = independenceTest.checkIndependence(x, y, z); - } catch (Exception e) { - throw new RuntimeException(e); - } - boolean indep = result.isIndependent(); - double pValue = result.getPValue(); - independenceTest.setVerbose(verbose); + public Pair, Set> call() { + Set msep = new HashSet<>(); + Set mconn = new HashSet<>(); - if (!Double.isNaN(pValue)) { - results.add(new IndependenceResult(fact, indep, pValue, Double.NaN)); - } + IndependenceFact fact = facts.get(index); + + Node x = fact.getX(); + Node y = fact.getY(); + Set z = fact.getZ(); + + if (this.msepTest.isMSeparated(x, y, z)) { + msep.add(fact); + } else { + mconn.add(fact); } - return results; + return new Pair<>(msep, mconn); } } - List>> tasks = new ArrayList<>(); + List, Set>>> tasks = new ArrayList<>(); - int chunkSize = getChunkSize(facts.size()); - - for (int i = 0; i < facts.size() && !Thread.currentThread().isInterrupted(); i += chunkSize) { - IndCheckTask task = new IndCheckTask(i, min(facts.size(), i + chunkSize), facts, independenceTest); + for (int i = 0; i < allIndependenceFacts.size() && !Thread.currentThread().isInterrupted(); i++) { + IndCheckTask task = new IndCheckTask(i, allIndependenceFacts, msepTest); if (!parallelized) { - List _results = task.call(); - getResultsLocal(indep).addAll(_results); + Pair, Set> _results = task.call(); + msep.addAll(_results.getFirst()); + mconn.addAll(_results.getSecond()); } else { tasks.add(task); } } if (parallelized) { - List>> theseResults = ForkJoinPool.commonPool().invokeAll(tasks); + List, Set>>> theseResults + = ForkJoinPool.commonPool().invokeAll(tasks); - for (Future> future : theseResults) { + for (Future, Set>> future : theseResults) { try { - getResultsLocal(indep).addAll(future.get()); + Pair, Set> setPair = future.get(); + msep.addAll(setPair.getFirst()); + mconn.addAll(setPair.getSecond()); } catch (InterruptedException | ExecutionException e) { throw new RuntimeException(e); } @@ -438,75 +523,90 @@ public List call() { } } - private void generateResultsAllSubsets(boolean indep, List msep, List mconn) { - List facts = indep ? msep : mconn; - - class IndCheckTask implements Callable> { - private final int from; - private final int to; + /** + * Generates the results for the given set of independence facts. + * + * @param facts The set of independence facts. + * @param msep True if for implied independencies, false if for implied dependencies. + */ + private void generateResults(Set facts, boolean msep) { + class IndCheckTask implements Callable, Set>> { + private final int index; private final List facts; private final IndependenceTest independenceTest; - IndCheckTask(int from, int to, List facts, IndependenceTest test) { - this.from = from; - this.to = to; + IndCheckTask(int index, List facts, IndependenceTest test) { + this.index = index; this.facts = facts; this.independenceTest = test; } @Override - public List call() { - List results = new ArrayList<>(); - - for (int i = from; i < to; i++) { - if (Thread.interrupted()) break; - IndependenceFact fact = facts.get(i); - - Node x = fact.getX(); - Node y = fact.getY(); - Set z = fact.getZ(); - boolean verbose = independenceTest.isVerbose(); - independenceTest.setVerbose(false); - IndependenceResult result; - try { - result = independenceTest.checkIndependence(x, y, z); - } catch (Exception e) { - throw new RuntimeException(e); - } - boolean indep = result.isIndependent(); - double pValue = result.getPValue(); - independenceTest.setVerbose(verbose); + public Pair, Set> call() { + Set resultsIndep = new HashSet<>(); + Set resultsDep = new HashSet<>(); + + IndependenceFact fact = facts.get(index); + + Node x = fact.getX(); + Node y = fact.getY(); + Set z = fact.getZ(); + + if (independenceTest instanceof RowsSettable) { + List rows = getSubsampleRows(percentResample); + ((RowsSettable) independenceTest).setRows(rows); + addResults(resultsIndep, resultsDep, fact, x, y, z); + } else { + addResults(resultsIndep, resultsDep, fact, x, y, z); + } - if (!Double.isNaN(pValue)) { - results.add(new IndependenceResult(fact, indep, pValue, Double.NaN)); - } + return new Pair<>(resultsIndep, resultsDep); + } + + private void addResults(Set resultsIndep, Set resultsDep, IndependenceFact fact, Node x, Node y, Set z) { + boolean verbose = independenceTest.isVerbose(); + independenceTest.setVerbose(false); + IndependenceResult result; + try { + result = independenceTest.checkIndependence(x, y, z); + } catch (Exception e) { + throw new RuntimeException(e); } + boolean indep = result.isIndependent(); + double pValue = result.getPValue(); + independenceTest.setVerbose(verbose); - return results; + if (!Double.isNaN(pValue)) { + if (msep) { + resultsIndep.add(new IndependenceResult(fact, indep, pValue, Double.NaN)); + } else { + resultsDep.add(new IndependenceResult(fact, indep, pValue, Double.NaN)); + } + } } } - List>> tasks = new ArrayList<>(); + List, Set>>> tasks = new ArrayList<>(); - int chunkSize = getChunkSize(facts.size()); - - for (int i = 0; i < facts.size() && !Thread.currentThread().isInterrupted(); i += chunkSize) { - IndCheckTask task = new IndCheckTask(i, min(facts.size(), i + chunkSize), facts, independenceTest); + for (int i = 0; i < facts.size() && !Thread.currentThread().isInterrupted(); i++) { + IndCheckTask task = new IndCheckTask(i, new ArrayList<>(facts), independenceTest); if (!parallelized) { - List _results = task.call(); - getResultsLocal(indep).addAll(_results); + Pair, Set> _results = task.call(); + resultsIndep.addAll(_results.getFirst()); + resultsDep.addAll(_results.getSecond()); } else { tasks.add(task); } } if (parallelized) { - List>> theseResults = ForkJoinPool.commonPool().invokeAll(tasks); + List, Set>>> theseResults = ForkJoinPool.commonPool().invokeAll(tasks); - for (Future> future : theseResults) { + for (Future, Set>> future : theseResults) { try { - getResultsLocal(indep).addAll(future.get()); + resultsIndep.addAll(future.get().getFirst()); + resultsDep.addAll(future.get().getSecond()); } catch (InterruptedException | ExecutionException e) { throw new RuntimeException(e); } @@ -514,8 +614,13 @@ public List call() { } } + /** + * Calculates the statistics for the given list of results. + * + * @param indep True if for implied independencies, false if for implied dependencies. + */ private void calcStats(boolean indep) { - List results = getResultsLocal(indep); + List results = new ArrayList<>(getResultsLocal(indep)); int dependent = 0; @@ -530,28 +635,101 @@ private void calcStats(boolean indep) { } List pValues = getPValues(results); + GeneralAndersonDarlingTest generalAndersonDarlingTest = new GeneralAndersonDarlingTest(pValues, new UniformRealDistribution(0, 1)); + double aSquared = generalAndersonDarlingTest.getASquared(); + double aSquaredStar = generalAndersonDarlingTest.getASquaredStar(); if (indep) { if (pValues.size() < 2) { ksPValueIndep = Double.NaN; + binomialPIndep = Double.NaN; + aSquaredIndep = Double.NaN; + aSquaredStarIndep = Double.NaN; + andersonDarlingPIndep = Double.NaN; } else { - ksPValueIndep = UniformityTest.getPValue(pValues); + ksPValueIndep = UniformityTest.getPValue(pValues, 0.0, 1.0); + binomialPIndep = getBinomialP(pValues, independenceTest.getAlpha()); + aSquaredIndep = aSquared; + aSquaredStarIndep = aSquaredStar; + andersonDarlingPIndep = 1. - generalAndersonDarlingTest.getProbTail(pValues.size(), aSquaredStar); } } else { if (pValues.size() < 2) { ksPValueDep = Double.NaN; + binomialPDep = Double.NaN; + aSquaredDep = Double.NaN; + aSquaredStarDep = Double.NaN; + andersonDarlingPDep = Double.NaN; + } else { - ksPValueDep = UniformityTest.getPValue(pValues); + ksPValueDep = UniformityTest.getPValue(pValues, 0.0, 1.0); + binomialPDep = getBinomialP(pValues, independenceTest.getAlpha()); + aSquaredDep = aSquared; + aSquaredStarDep = aSquaredStar; + andersonDarlingPDep = 1. - generalAndersonDarlingTest.getProbTail(pValues.size(), aSquaredStar); } } } - private int getChunkSize(int n) { - int chunk = (int) FastMath.ceil((n / ((double) (5 * Runtime.getRuntime().availableProcessors())))); - if (chunk < 1) chunk = 1; - return chunk; + /** + * Returns a list of row indices for a subsample of the data set. + * + * @param v The fraction of the data set to use. + * @return A list of row indices for a subsample of the data set. + */ + private List getSubsampleRows(double v) { + int sampleSize = independenceTest.getSampleSize(); + int subsampleSize = (int) FastMath.floor(sampleSize * v); + List rows = new ArrayList<>(sampleSize); + for (int i = 0; i < sampleSize; i++) { + rows.add(i); + } + Collections.shuffle(rows); + return rows.subList(0, subsampleSize); + } + + /** + * Generates the results for the given set of independence facts, for both the local Markov and local Faithfulness + * + * @param msep The set of m-separation facts. + * @param mconn The set of m-connection facts. + */ + private void generateResultsAllSubsets(Set msep, Set mconn) { + generateResults(msep, true); + generateResults(mconn, false); } + /** + * Returns a Binomial p-value for the hypothesis that the distribution of p-values is not Uniform under the null + * hypothesis. Values less than alpha imply non-uniform distributions. + * + * @param pValues The p-values. + * @param alpha The alpha level. Rejections with p-values less than this are considered dependent. + * @return The Binomial p-value for non-uniformity. + */ + private double getBinomialP(List pValues, double alpha) { + int independentJudgements = 0; + + for (double pValue : pValues) { + if (pValue > alpha) independentJudgements++; + } + + int p = pValues.size(); + + // The left tail of this binomial distribution is a p-value for getting too few dependent judgments for + // the distribution to count as uniform. + BinomialDistribution bd = new BinomialDistribution(p, alpha); + + // We want the area to the right of this, so we subtract from 1. + return (1.0 - bd.cumulativeProbability(independentJudgements)) + (bd.probability(p - independentJudgements)); + } + + /** + * Returns the list of results for the given condition. + * + * @param indep True if for implied independencies, false if for implied dependencies. + * @return The list of results for the given condition. + */ private List getResultsLocal(boolean indep) { if (indep) { return this.resultsIndep; @@ -560,5 +738,120 @@ private List getResultsLocal(boolean indep) { } } + public Knowledge getKnowledge() { + return knowledge; + } + + /** + * Sets the knowledge object for the Markov checker. The knowledge object should contain the tier knowledge for the + * Markov checker. The last tier contains the possible X and Y for X _||_ Y | Z1,...,Zn, and the previous tiers + * contain the possible Z1,...,Zn for X _||_ Y | Z1,...,Zn. Additional forbidden or required edges are ignored. + * + * @param knowledge The knowledge object. + */ + public void setKnowledge(Knowledge knowledge) { + if (!(knowledge.getListOfExplicitlyForbiddenEdges().isEmpty() && knowledge.getListOfRequiredEdges().isEmpty())) { + throw new IllegalArgumentException("Knowledge object for the Markov checker cannot contain required of " + + "explicitly forbidden edges; only tier knowledge is used. The last tier contains the possible X " + + "and Y for X _||_ Y | Z1,..,Zn, and the previous tiers contain the possible Z1,..,Zn for X _||_ Y " + + "| Z1,..,Zn."); + } + int lastTier = 0; + + for (int t = 0; t < knowledge.getNumTiers(); t++) { + if (!knowledge.getTier(t).isEmpty()) { + lastTier = t; + } + } + + List independenceNames = knowledge.getTier(lastTier); + + List conditioningNames = new ArrayList<>(); + + // Assuming all named nodes go into thd conditioning set. + for (int i = 0; i <= lastTier; i++) { + conditioningNames.addAll(knowledge.getTier(i)); + } + + List independenceNodes = new ArrayList<>(); + for (String name : independenceNames) { + Node variable = getVariable(name); + if (variable != null) { + independenceNodes.add(variable); + } + } + + List conditioningNodes = new ArrayList<>(); + for (String name : conditioningNames) { + Node variable = getVariable(name); + if (variable != null) { + conditioningNodes.add(variable); + } + } + + this.independenceNodes = independenceNodes; + this.conditioningNodes = conditioningNodes; + + this.knowledge = knowledge.copy(); + } + + /** + * Returns the nodes that are possible X and Y for X _||_ Y | Z1,...,Zn. + * + * @return The nodes that are possible X and Y for X _||_ Y | Z1,...,Zn. + */ + public List getIndependenceNodes() { + return independenceNodes; + } + + /** + * Returns the nodes that are possible Z1,...,Zn for X _||_ Y | Z1,...,Zn. + * + * @return The nodes that are possible Z1,...,Zn for X _||_ Y | Z1,...,Zn. + */ + public List getConditioningNodes() { + return conditioningNodes; + } + + /** + * Stores the set of m-separation facts and the set of m-connection facts for a graph, for the global check. + */ + public static class AllSubsetsIndependenceFacts { + private final Set msep; + private final Set mconn; + + public AllSubsetsIndependenceFacts(Set msep, Set mconn) { + this.msep = msep; + this.mconn = mconn; + } + + public String toStringIndep() { + StringBuilder builder = new StringBuilder("All subsets independence facts:\n"); + + for (IndependenceFact fact : msep) { + builder.append(fact).append("\n"); + } + + return builder.toString(); + } + + public String toStringDep() { + StringBuilder builder = new StringBuilder("All subsets independence facts:\n"); + + for (IndependenceFact fact : mconn) { + builder.append(fact).append("\n"); + } + + return builder.toString(); + } + + public List getMsep() { + return new ArrayList<>(msep); + } + + public List getMconn() { + return new ArrayList<>(mconn); + } + } } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Mimbuild.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Mimbuild.java index 69ef425743..2e3ee1c672 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Mimbuild.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Mimbuild.java @@ -42,23 +42,21 @@ import java.util.List; /** - *

Provides an implementation of Mimbuild, an algorithm that takes a clustering - * of variables, each of which is explained by a single latent, then forms the implied covariance matrix over the latent - * variables, then runs a CPDAG search to in the structure over the latent themselves.

- * - *

Specifically, the search will first infer the covariance matrix over the - * latents and then will use the GRaSP algorithm (see) to infer the structure graph over the latents, using the SEM Bic - * score with the given penalty discount (default 2).

- * - *

One may wish to obtain the implied correlation matrix over the latents and - * run one's own choice of CPDAG algorithm on it with one's own test or score; a method is available to return this - * covariance matrix.

- * - *

A suitable clustering for Mimbuild may be obtained using the BPC or FOFC - * algorithm (see).

- * - *

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

+ * Provides an implementation of Mimbuild, an algorithm that takes a clustering of variables, each of which is explained + * by a single latent, then forms the implied covariance matrix over the latent variables, then runs a CPDAG search to + * in the structure over the latent themselves. + *

+ * Specifically, the search will first infer the covariance matrix over the latents and then will use the GRaSP + * algorithm (see) to infer the structure graph over the latents, using the SEM Bic score with the given penalty + * discount (default 2). + *

+ * One may wish to obtain the implied correlation matrix over the latents and run one's own choice of CPDAG algorithm on + * it with one's own test or score; a method is available to return this covariance matrix. + *

+ * A suitable clustering for Mimbuild may be obtained using the BPC or FOFC algorithm (see). + *

+ * This class is configured to respect the knowledge of forbidden and required edges, including knowledge of temporal + * tiers. * * @author josephramsey * @see Bpc @@ -68,37 +66,29 @@ * @see Knowledge */ public class Mimbuild { - - /** - * The clustering from BPC or equivalent. Small clusters are removed. - */ + // The clustering from BPC or equivalent. Small clusters are removed. private List> clustering; - - /** - * The graph over the latents. - */ + // The graph over the latents. private Graph structureGraph; - - /** - * Background knowledge for CPC. - */ + // Background knowledge for CPC. private Knowledge knowledge = new Knowledge(); - + // The covariance matrix over the latent variables. private ICovarianceMatrix latentsCov; - - /** - * The minimum function (Fgsl) value achieved. - */ + // The minimum function (Fgsl) value achieved. private double minimum; - - /** - * The p value of the optimization. - */ + // The p value of the optimization. private double pValue; + // The latents. private List latents; + // The penalty discount of the score used to infer the structure graph. private double penaltyDiscount = 1; + // jf Clusters smaller than this size will be tossed out. private int minClusterSize = 3; + private long seed = -1; + /** + * Constructs a new Mimbuild search. + */ public Mimbuild() { } @@ -160,6 +150,7 @@ public Graph search(List> clustering, List latentNames, ICova SemBicScore score = new SemBicScore(latentscov); score.setPenaltyDiscount(this.penaltyDiscount); Grasp search = new Grasp(score); + search.setSeed(seed); search.setKnowledge(this.knowledge); search.bestOrder(latentscov.getVariables()); graph = search.getGraph(true); @@ -520,6 +511,10 @@ private double sumOfDifferences(int[][] indicatorIndices, Matrix cov, double[][] return sum; } + public void setSeed(long seed) { + this.seed = seed; + } + private class Function1 implements org.apache.commons.math3.analysis.MultivariateFunction { private final int[][] indicatorIndices; private final Matrix measurescov; diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/MimbuildTrek.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/MimbuildTrek.java index 44bcbf59a0..466adb3531 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/MimbuildTrek.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/MimbuildTrek.java @@ -43,57 +43,40 @@ /** * Implements Mimbuild using the theory of treks and ranks. - * - *

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

+ *

+ * This class is configured to respect knowledge of forbidden and required edges, including knowledge of temporal + * tiers. * * @author adambrodie * @see Knowledge * @see Mimbuild */ public class MimbuildTrek { - - /** - * The clustering from BPC or equivalent. Small clusters are removed. - */ + // The clustering from BPC or equivalent. Small clusters are removed. private List> clustering; - - /** - * The graph over the latents. - */ + // The graph over the latents. private Graph structureGraph; - - /** - * The alpha level used for CPC - */ + // The alpha level used for CPC private double alpha = 0.001; - - /** - * Background knowledge for CPC. - */ + // Background knowledge for CPC. private Knowledge knowledge = new Knowledge(); - - /** - * The estimated covariance matrix over the latents. - */ + // The estimated covariance matrix over the latents. private ICovarianceMatrix latentsCov; - - /** - * The minimum function (Fgsl) value achieved. - */ + // The minimum function (Fgsl) value achieved. private double minimum; - - /** - * The p value of the optimization. - */ + // The p value of the optimization. private double pValue; + // The latents. private List latents; + // The minimum cluster size. private int minClusterSize = 3; + /** + * Empty constructor. + */ public MimbuildTrek() { } - /** * Does the search and returns the graph. * diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/MixtureModel.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/MixtureModel.java index 8a1516ef38..f110a32cc8 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/MixtureModel.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/MixtureModel.java @@ -14,16 +14,36 @@ * @author Madelyn Glymour */ public class MixtureModel { + // The mixed data set private final DataSet data; + // The individual data sets private final int[] cases; + // The number of cases in each individual data set private final int[] caseCounts; - private final double[][] dataArray; // v-by-n data matrix - private final double[][] meansArray; // k-by-v matrix representing means for each variable for each of k models - private final double[] weightsArray; // array of length k representing weights for each model - private final double[][] gammaArray; // k-by-n matrix representing gamma for each data case in each model - private final Matrix[] variancesArray; // k-by-v-by-v matrix representing covariance matrix for each of k models - private final int numModels; // number of models in mixture + // The data set in array form + private final double[][] dataArray; + // The means matrix + private final double[][] meansArray; + // The weights array + private final double[] weightsArray; + // The gamma matrix + private final double[][] gammaArray; + // The variance matrix + private final Matrix[] variancesArray; + // The number of models in the mixture + private final int numModels; + /** + * Constructs a mixture model from a mixed data set, a means matrix, a weights array, a variance matrix, and a gamma + * matrix. + * + * @param data the mixed data set + * @param dataArray the mixed data set in array form + * @param meansArray the means matrix + * @param weightsArray the weights array + * @param variancesArray the variance matrix + * @param gammaArray the gamma matrix + */ public MixtureModel(DataSet data, double[][] dataArray, double[][] meansArray, double[] weightsArray, Matrix[] variancesArray, double[][] gammaArray) { this.data = data; this.dataArray = dataArray; diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Pc.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Pc.java index e1f143d1d9..9d4cacc354 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Pc.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Pc.java @@ -30,32 +30,30 @@ import edu.cmu.tetrad.search.utils.SepsetMap; import edu.cmu.tetrad.util.MillisecondTimes; import edu.cmu.tetrad.util.TetradLogger; +import org.jetbrains.annotations.NotNull; import java.util.HashSet; import java.util.List; import java.util.Set; /** - *

Implements the Peter/Clark (PC) algorithm, which uses conditional independence testing as an oracle to first of - * all remove extraneous edges from a complete graph, then to orient the unshielded colliders in the graph, and finally - * to make any additional orientations that are capable of avoiding additional unshielded colliders in the graph. An + * Implements the Peter/Clark (PC) algorithm, which uses conditional independence testing as an oracle to first of all + * remove extraneous edges from a complete graph, then to orient the unshielded colliders in the graph, and finally to + * make any additional orientations that are capable of avoiding additional unshielded colliders in the graph. An * version of this algorithm was proposed earlier than this, but the standard reference for the algorithm is in Chapter - * 6 of the following book:

- * - *

Spirtes, P., Glymour, C. N., Scheines, R., & Heckerman, D. (2000). Causation, - * prediction, and search. MIT press.

- * - *

A modified rule set capable of dealing effectively with knowledge of required - * and forbidden edges is due to Chris Meek, with this reference: - * - *

Meek, C. (1995), "Causal inference and causal explanation with background - * knowledge."

- * - *

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.

+ * 6 of the following book: + *

+ * Spirtes, P., Glymour, C. N., Scheines, R., & Heckerman, D. (2000). Causation, prediction, and search. MIT press. + *

+ * A modified rule set capable of dealing effectively with knowledge of required and forbidden edges is due to Chris + * Meek, with this reference: + *

+ * Meek, C. (1995), "Causal inference and causal explanation with background knowledge." + *

+ * 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 peterspirtes * @author chrismeek @@ -65,22 +63,35 @@ * @see Knowledge */ public class Pc implements IGraphSearch { + // The oracle for conditional independence facts. private final IndependenceTest independenceTest; + // The logger. private final TetradLogger logger = TetradLogger.getInstance(); + // The knowledge specification. private Knowledge knowledge = new Knowledge(); + // The sepset map from the most recent search. private SepsetMap sepsets; + // The depth of the search. private int depth = 1000; + // The graph from the most recent search. private Graph graph; + // The elapsed time of the most recent search. private long elapsedTime; + // The number of independence tests performed in the most recent search. private int numIndependenceTests; + // Whether the search is verbose. private boolean verbose = false; + // The rule to use for resolving collider orientation conflicts. private PcCommon.ConflictRule conflictRule = PcCommon.ConflictRule.PRIORITIZE_EXISTING; + // Whether the stable adjacency search should be used. private boolean stable = true; + // Whether cycles should be checked in the Meek rules. private boolean meekPreventCycles = true; + // Whether the max-p heuristic should be used for collider discovery. private boolean useMaxPHeuristic = false; + // The PC heuristic type. private PcCommon.PcHeuristicType pcHeuristicType = PcCommon.PcHeuristicType.NONE; - /** * Constructs a new PC search using the given independence test as oracle. * @@ -145,8 +156,10 @@ public Graph search(Set nodes) { * @see IFas */ public Graph search(IFas fas, Set nodes) { - this.logger.forceLogMessage("Starting PC algorithm"); - this.logger.forceLogMessage("Independence test = " + getIndependenceTest() + "."); + if (verbose) { + this.logger.forceLogMessage("Starting PC algorithm"); + this.logger.forceLogMessage("Independence test = " + getIndependenceTest() + "."); + } long startTime = MillisecondTimes.timeMillis(); @@ -160,6 +173,26 @@ public Graph search(IFas fas, Set nodes) { "be in the domain of the independence test provided."); } + PcCommon search = getPcCommon(); + + this.graph = search.search(); + this.sepsets = fas.getSepsets(); + + this.numIndependenceTests = fas.getNumIndependenceTests(); + + this.elapsedTime = MillisecondTimes.timeMillis() - startTime; + + if (verbose) { + this.logger.forceLogMessage("Elapsed time = " + (this.elapsedTime) / 1000. + " s"); + this.logger.forceLogMessage("Finishing PC Algorithm."); + this.logger.flush(); + } + + return this.graph; + } + + @NotNull + private PcCommon getPcCommon() { PcCommon search = new PcCommon(independenceTest); search.setDepth(depth); search.setMeekPreventCycles(meekPreventCycles); @@ -181,19 +214,7 @@ public Graph search(IFas fas, Set nodes) { search.setConflictRule(conflictRule); search.setPcHeuristicType(pcHeuristicType); search.setVerbose(verbose); - - this.graph = search.search(); - this.sepsets = fas.getSepsets(); - - this.numIndependenceTests = fas.getNumIndependenceTests(); - - this.elapsedTime = MillisecondTimes.timeMillis() - startTime; - - this.logger.forceLogMessage("Elapsed time = " + (this.elapsedTime) / 1000. + " s"); - this.logger.forceLogMessage("Finishing PC Algorithm."); - this.logger.flush(); - - return this.graph; + return search; } /** @@ -325,11 +346,11 @@ public void setVerbose(boolean 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.

+ * 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. */ @@ -349,11 +370,11 @@ public void setConflictRule(PcCommon.ConflictRule conflictRule) { } /** - *

Sets whether the max-p heuristic should be used for collider discovery. Default is true. See the following - * reference for this:

- * - *

Ramsey, J. (2016). Improving accuracy and scalability of the pc algorithm by maximizing p-value. arXiv - * preprint arXiv:1610.00378.

+ * Sets whether the max-p heuristic should be used for collider discovery. Default is true. See the following + * reference for this: + *

+ * Ramsey, J. (2016). Improving accuracy and scalability of the pc algorithm by maximizing p-value. arXiv preprint + * arXiv:1610.00378. * * @param useMaxPHeuristic True, if so. */ diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/PcMb.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/PcMb.java index bd29fbeb07..d64af8b2cf 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/PcMb.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/PcMb.java @@ -32,16 +32,15 @@ import java.util.*; /** - *

Searches for a CPDAG representing all the Markov blankets for a given target T consistent - * with the given independence information. This CPDAG may be used to generate the actual list of DAG's that might be - * Markov blankets. Note that this code has been converted to be consistent with the CPC algorithm. The reference is - * here:

- * - *

Bai, X., Padman, R., Ramsey, J., & Spirtes, P. (2008). Tabu search-enhanced graphical models - * for classification in high dimensions. INFORMS Journal on Computing, 20(3), 423-437.

- * - *

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

+ * Searches for a CPDAG representing all the Markov blankets for a given target T consistent with the given independence + * information. This CPDAG may be used to generate the actual list of DAG's that might be Markov blankets. Note that + * this code has been converted to be consistent with the CPC algorithm. The reference is here: + *

+ * Bai, X., Padman, R., Ramsey, J., & Spirtes, P. (2008). Tabu search-enhanced graphical models for classification + * in high dimensions. INFORMS Journal on Computing, 20(3), 423-437. + *

+ * This class is configured to respect knowledge of forbidden and required edges, including knowledge of temporal + * tiers. * * @author josephramsey * @see FgesMb @@ -49,63 +48,37 @@ */ public final class PcMb implements IMbSearch, IGraphSearch { - /** - * The independence test used to perform the search. - */ + // The independence test used to perform the search. private final IndependenceTest test; - /** - * The logger for this class. The config needs to be set. - */ + // The logger for this class. The config needs to be set. private final TetradLogger logger = TetradLogger.getInstance(); - /** - * The list of variables being searched over. Must contain the target. - */ + // The list of variables being searched over. Must contain the target. private List variables; - /** - * The target variable. - */ + // The target variable. private List targets; - /** - * The depth to which independence tests should be performed--i.e., the maximum number of conditioning variables for - * any independence test. - */ + // The depth to which independence tests should be performed--i.e., the maximum number of conditioning variables for + // any independence test. private int depth; - /** - * The CPDAG output by the most recent search. This is saved in case the user wants to generate the list of MB - * DAGs. - */ + // The CPDAG output by the most recent search. This is saved in case the user wants to generate the list of MB + // DAGs. private Graph resultGraph; - /** - * A count of the number of independence tests performed in the course of the most recent search. - */ + // A count of the number of independence tests performed in the course of the most recent search. private int numIndependenceTests; - /** - * Information to help understand what part of the search is taking the most time. - */ + // Information to help understand what part of the search is taking the most time. private int[] maxRemainingAtDepth; - /** - * The set of nodes that edges should not be drawn to in the addDepthZeroAssociates method. - */ + // The set of nodes that edges should not be drawn to in the addDepthZeroAssociates method. private Set a; - /** - * Elapsed time for the last run of the algorithm. - */ + // Elapsed time for the last run of the algorithm. private long elapsedTime; - /** - * Knowledge. - */ + // Knowledge. private Knowledge knowledge = new Knowledge(); - /** - * Set of ambiguous unshielded triples. - */ + // Set of ambiguous unshielded triples. private Set ambiguousTriples; - /** - * True if cycles are to be prevented. Maybe expensive for large graphs (but also useful for large graphs). - */ + // True if cycles are to be prevented. Maybe expensive for large graphs (but also useful for large graphs). private boolean meekPreventCycles; + // True if the search should return the MB, not the MB CPDAG. private boolean findMb = false; - /** * Constructs a new search. * @@ -130,17 +103,6 @@ public PcMb(IndependenceTest test, int depth) { this.variables = test.getVariables(); } - - private static boolean isArrowheadAllowed1(Node from, Node to, - Knowledge knowledge) { - if (knowledge == null) { - return true; - } - - return !knowledge.isRequired(to.toString(), from.toString()) && - !knowledge.isForbidden(from.toString(), to.toString()); - } - /** * Sets whether cycles should be prevented, using a cycle checker. * @@ -349,8 +311,6 @@ public Graph search() { this.maxRemainingAtDepth = new int[20]; Arrays.fill(this.maxRemainingAtDepth, -1); -// logger.info("target = " + getTarget()); - Graph graph = new EdgeListGraph(); // Each time the addDepthZeroAssociates method is called for a node @@ -511,6 +471,17 @@ public void setKnowledge(Knowledge knowledge) { this.knowledge = new Knowledge(knowledge); } + private static boolean isArrowheadAllowed1(Node from, Node to, + Knowledge knowledge) { + if (knowledge == null) { + return true; + } + + return !knowledge.isRequired(to.toString(), from.toString()) && + !knowledge.isForbidden(from.toString(), to.toString()); + } + + private Set getA() { return this.a; } @@ -557,8 +528,8 @@ private void prune(Node node, Graph graph) { } /** - * Tries to remove the edge node---from using adjacent nodes of node 'from.' then tries to remove each other - * edge adjacent node 'from' using remaining edges adjacent node 'from.' If the edge 'node' is removed, the method + * Tries to remove the edge node---from using adjacent nodes of node 'from.' then tries to remove each other edge + * adjacent node 'from' using remaining edges adjacent node 'from.' If the edge 'node' is removed, the method * immediately returns. * * @param node The node about which pruning it to take place. diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Pcd.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Pcd.java index f3fc53ac4e..f1925815e3 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Pcd.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Pcd.java @@ -39,11 +39,11 @@ import java.util.Set; /** - *

Modifies the PC algorithm to handle the deterministic case. Edges removals - * or orientations based on conditional independence test involving deterministic relationships are not done.

- * - *

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

+ * Modifies the PC algorithm to handle the deterministic case. Edges removals or orientations based on conditional + * independence test involving deterministic relationships are not done. + *

+ * This class is configured to respect knowledge of forbidden and required edges, including knowledge of temporal + * tiers. * * @author peterspirtes * @author josephramsey. @@ -53,58 +53,33 @@ */ public class Pcd implements IGraphSearch { - /** - * The independence test used for the PC search. - */ + // The independence test used for the PC search. private final IndependenceTest independenceTest; - /** - * The logger for this class. The config needs to be set. - */ + // The logger for this class. The config needs to be set. private final TetradLogger logger = TetradLogger.getInstance(); - /** - * Forbidden and required edges for the search. - */ + // Forbidden and required edges for the search. private Knowledge knowledge = new Knowledge(); - /** - * Sepset information accumulated in the search. - */ + // Sepset information accumulated in the search. private SepsetMap sepsets; - /** - * The maximum number of nodes conditioned on in the search. The default it 1000. - */ + // The maximum number of nodes conditioned on in the search. The default it 1000. private int depth = 1000; - /** - * The graph that's constructed during the search. - */ + // The graph that's constructed during the search. private Graph graph; - /** - * Elapsed time of the most recent search. - */ + // Elapsed time of the most recent search. private long elapsedTime; - /** - * True if cycles are to be prevented. Maybe expensive for large graphs (but also useful for large graphs). - */ + // True if cycles are to be prevented. Maybe expensive for large graphs (but also useful for large graphs). private boolean meekPreventCycles; - /** - * In an enumeration of triple types, these are the collider triples. - */ + // In an enumeration of triple types, these are the collider triples. private Set unshieldedColliders; - - /** - * In an enumeration of triple types, these are the noncollider triples. - */ + // In an enumeration of triple types, these are the noncollider triples. private Set unshieldedNoncolliders; - - /** - * The number of independence tests in the last search. - */ + // The number of independence tests in the last search. private int numIndependenceTests; - + // True iff the algorithm should be run with verbose output. private boolean verbose; - + // True iff the algorithm should be run with False Discovery Rate tests. private boolean fdr; - /** * Constructs a new PC search using the given independence test as oracle. * @@ -290,10 +265,64 @@ public Set getUnshieldedNoncolliders() { return this.unshieldedNoncolliders; } + /** + * @return the graph returned by search(). Non-null after search is called. + */ public Set getAdjacencies() { return new HashSet<>(this.graph.getEdges()); } + /** + * @return the number of independence tests performed in the last search. + */ + public int getNumIndependenceTests() { + return this.numIndependenceTests; + } + + /** + * @return the list of nodes in the graph returned by search(). Non-null after search is + * called. + */ + public List getNodes() { + return this.graph.getNodes(); + } + + /** + * True iff the algorithm should be run with verbose output. + * + * @return True, if so. + */ + public boolean isVerbose() { + return this.verbose; + } + + /** + * Sets whether this test will print verbose output. + * + * @param verbose True, if so. + */ + public void setVerbose(boolean verbose) { + this.verbose = verbose; + } + + /** + * True iff the algorithm should be run with False Discovery Rate tests. + * + * @return True, if so. + */ + public boolean isFdr() { + return this.fdr; + } + + /** + * Sets whether this test will run with False Discovery Rate tests. + * + * @param fdr True, if so. + */ + public void setFdr(boolean fdr) { + this.fdr = fdr; + } + private void enumerateTriples() { this.unshieldedColliders = new HashSet<>(); this.unshieldedNoncolliders = new HashSet<>(); @@ -328,33 +357,6 @@ private void enumerateTriples() { } } } - - public int getNumIndependenceTests() { - return this.numIndependenceTests; - } - - public List getNodes() { - return this.graph.getNodes(); - } - - public boolean isVerbose() { - return this.verbose; - } - - public void setVerbose(boolean verbose) { - this.verbose = verbose; - } - - /** - * True iff the algorithm should be run with False Discovery Rate tests. - */ - public boolean isFdr() { - return this.fdr; - } - - public void setFdr(boolean fdr) { - this.fdr = fdr; - } } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/PermutationSearch.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/PermutationSearch.java index 48846acf30..90ec4f9cfc 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/PermutationSearch.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/PermutationSearch.java @@ -7,20 +7,21 @@ import edu.cmu.tetrad.search.score.Score; import edu.cmu.tetrad.search.utils.GrowShrinkTree; import edu.cmu.tetrad.search.utils.MeekRules; +import edu.cmu.tetrad.util.RandomUtil; import java.util.*; /** - *

Implements common elements of a permutation search. The specific parts - * for each permutation search are implemented as a SuborderSearch.

- * - *

This class specifically handles an optimization for tiered knowledge, whereby - * tiers in the knowledge can be searched one at a time in order from the lowest to highest, taking all variables from - * previous tiers as a fixed for a later tier. This allows these permutation searches to search over many more - * variables than otherwise, so long as tiered knowledge is available to organize the search.

- * - *

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

+ * Implements common elements of a permutation search. The specific parts for each permutation search are implemented as + * a SuborderSearch. + *

+ * This class specifically handles an optimization for tiered knowledge, whereby tiers in the knowledge can be searched + * one at a time in order from the lowest to highest, taking all variables from previous tiers as a fixed for a later + * tier. This allows these permutation searches to search over many more variables than otherwise, so long as tiered + * knowledge is available to organize the search. + *

+ * This class is configured to respect the knowledge of forbidden and required edges, including knowledge of temporal + * tiers. * * @author bryanandrews * @see SuborderSearch @@ -34,6 +35,7 @@ public class PermutationSearch { private final List order; private final Map gsts; private Knowledge knowledge = new Knowledge(); + private long seed = -1; /** * Constructs a new PermutationSearch using the given SuborderSearch. @@ -107,6 +109,10 @@ public static Graph getGraph(List nodes, Map> parents, Kno * @return The CPDAG. */ public Graph search() { + if (this.seed != -1) { + RandomUtil.getInstance().setSeed(this.seed); + } + List prefix; if (!this.knowledge.isEmpty() && this.knowledge.getVariablesNotInTiers().isEmpty()) { List order = new ArrayList<>(this.order); @@ -123,7 +129,8 @@ public Graph search() { this.order.add(node); if (!this.knowledge.isTierForbiddenWithin(i)) continue; suborder = this.order.subList(start++, this.order.size()); - this.suborderSearch.searchSuborder(prefix, suborder, this.gsts);; + this.suborderSearch.searchSuborder(prefix, suborder, this.gsts); + ; } if (this.knowledge.isTierForbiddenWithin(i)) continue; @@ -182,4 +189,8 @@ public void setKnowledge(Knowledge knowledge) { this.gsts.get(node).setKnowledge(required, forbidden); } } + + public void setSeed(long seed) { + this.seed = seed; + } } \ No newline at end of file diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Rfci.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Rfci.java index de529b3972..ce45162a86 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Rfci.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Rfci.java @@ -34,17 +34,16 @@ /** - *

Implements the Really Fast Causal Inference (RFCI) algorithm, which aims to - * do a correct inference of inferrable causal structure under the assumption that unmeasured common causes of variables - * in the data may exist. The graph returned is slightly different from the partial ancestral graph (PAG) returned by - * the FCI algorithm. The goal of of the algorithm is to avoid certain expensive steps in the FCI procedure in a correct - * way. This was introduced here:

- * - *

Colombo, D., Maathuis, M. H., Kalisch, M., & Richardson, T. S. (2012). Learning - * high-dimensional directed acyclic graphs with latent and selection variables. The Annals of Statistics, 294-321.

- * - *

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

+ * Implements the Really Fast Causal Inference (RFCI) algorithm, which aims to do a correct inference of inferrable + * causal structure under the assumption that unmeasured common causes of variables in the data may exist. The graph + * returned is slightly different from the partial ancestral graph (PAG) returned by the FCI algorithm. The goal of of + * the algorithm is to avoid certain expensive steps in the FCI procedure in a correct way. This was introduced here: + *

+ * Colombo, D., Maathuis, M. H., Kalisch, M., & Richardson, T. S. (2012). Learning high-dimensional directed acyclic + * graphs with latent and selection variables. The Annals of Statistics, 294-321. + *

+ * This class is configured to respect knowledge of forbidden and required edges, including knowledge of temporal + * tiers. * * @author Erin Korber, June 2004 * @author Alex Smith, December 2008 @@ -54,46 +53,27 @@ * @see Knowledge */ public final class Rfci implements IGraphSearch { - - /** - * The variables to search over (optional) - */ + // The variables to search over (optional) private final List variables = new ArrayList<>(); + // The independence test to use. private final IndependenceTest independenceTest; - /** - * The logger to use. - */ + // The logger to use. private final TetradLogger logger = TetradLogger.getInstance(); - /** - * The RFCI-PAG being constructed. - */ + // The RFCI-PAG being constructed. private Graph graph; - /** - * The SepsetMap being constructed. - */ + // The SepsetMap being constructed. private SepsetMap sepsets; - /** - * The background knowledge. - */ + // The background knowledge. private Knowledge knowledge = new Knowledge(); - /** - * The maximum length for any discriminating path. -1 if unlimited; otherwise, a positive integer. - */ + // 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. - */ + // The depth for the fast adjacency search. private int depth = -1; - /** - * Elapsed time of last search. - */ + // Elapsed time of last search. private long elapsedTime; - /** - * True iff verbose output should be printed. - */ + // True iff verbose output should be printed. private boolean verbose; - /** * Constructs a new RFCI search for the given independence test and background knowledge. */ diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Sp.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Sp.java index ab1eae7a44..6caf9967ba 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Sp.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/Sp.java @@ -8,27 +8,27 @@ import java.util.*; /** - *

Implements the SP (Sparsest Permutation) algorithm. This procedure goes through every - * permutation of the variables (so can be slow for more than 11 variables with no knowledge) looking for a permutation - * such that when a DAG is built it has the fewest number of edges (i.e., is a most 'frugal' or a 'sparsest' DAG). The - * procedure can in principle return all such sparsest permutations and their corresponding DAGs, but in this version it - * return one of them, and converts the result into a CPDAG.

- * - *

Note that SP considers all permutations of the algorithm, which is exponential in the - * number of variables. So SP without knowledge is limited to about 10 variables per knowledge tier.

- * - *

However, notably, tiered Knowledge can be used with this search. If tiered knowledge - * is used, then the procedure is carried out for each tier separately, given the variable preceding that tier, which - * allows the SP algorithm to address tiered (e.g., time series) problems with more than 11 variables.

- * - *

This class is meant to be used in the context of the PermutationSearch class (see). - * the proper use is PermutationSearch search = new PermutationSearch(new Sp(score));

- * - *

Raskutti, G., & Uhler, C. (2018). Learning directed acyclic graph models based on - * sparsest permutations. Stat, 7(1), e183.

- * - *

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

+ * Implements the SP (Sparsest Permutation) algorithm. This procedure goes through every permutation of the variables + * (so can be slow for more than 11 variables with no knowledge) looking for a permutation such that when a DAG is built + * it has the fewest number of edges (i.e., is a most 'frugal' or a 'sparsest' DAG). The procedure can in principle + * return all such sparsest permutations and their corresponding DAGs, but in this version it return one of them, and + * converts the result into a CPDAG. + *

+ * Note that SP considers all permutations of the algorithm, which is exponential in the number of variables. So SP + * without knowledge is limited to about 10 variables per knowledge tier. + *

+ * However, notably, tiered Knowledge can be used with this search. If tiered knowledge is used, then the procedure is + * carried out for each tier separately, given the variable preceding that tier, which allows the SP algorithm to + * address tiered (e.g., time series) problems with more than 11 variables. + *

+ * This class is meant to be used in the context of the PermutationSearch class (see). the proper use is + * PermutationSearch search = new PermutationSearch(new Sp(score)); + *

+ * Raskutti, G., & Uhler, C. (2018). Learning directed acyclic graph models based on sparsest permutations. Stat, + * 7(1), e183. + *

+ * This class is configured to respect knowledge of forbidden and required edges, including knowledge of temporal + * tiers. * * @author bryanandrews * @author josephramsey @@ -38,10 +38,15 @@ * @see Knowledge */ public class Sp implements SuborderSearch { + // The score to use. private final Score score; + // The variables to search over. private final List variables; + // The parents of each variable. private final Map> parents; + // The GrowShrinkTree for each variable. private Map gsts; + // The knowledge. private Knowledge knowledge = new Knowledge(); /** @@ -106,6 +111,44 @@ public void searchSuborder(List prefix, List suborder, Map getVariables() { + return variables; + } + + /** + * Returns the parents of each variable. + * + * @return The parents of each variable. + */ + @Override + public Map> getParents() { + return parents; + } + + /** + * Returns the score being used. + * + * @return The score being used. + */ + @Override + public Score getScore() { + return score; + } + + /** + * Set the knowledge to used. + */ + @Override + public void setKnowledge(Knowledge knowledge) { + this.knowledge = knowledge; + } + private void makeValidKnowledgeOrder(List order) { if (!this.knowledge.isEmpty()) { order.sort((a, b) -> { @@ -131,10 +174,6 @@ private boolean violatesKnowledge(List suborder, Map> requ return false; } - @Override - public void setKnowledge(Knowledge knowledge) { - this.knowledge = knowledge; - } private double update(List prefix, List suborder) { double score = 0; @@ -153,21 +192,6 @@ private double update(List prefix, List suborder) { return score; } - @Override - public List getVariables() { - return variables; - } - - @Override - public Map> getParents() { - return parents; - } - - @Override - public Score getScore() { - return score; - } - static class SwapIterator implements Iterator { private final int n; diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/SpFci.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/SpFci.java index fd33a5e157..120f59ffe5 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/SpFci.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/SpFci.java @@ -39,26 +39,25 @@ import static edu.cmu.tetrad.graph.GraphUtils.gfciExtraEdgeRemovalStep; /** - *

Uses SP in place of FGES for the initial step in the GFCI algorithm. - * This tends to produce a accurate PAG than GFCI as a result, for the latent variables case. This is a simple - * substitution; the reference for GFCI is here:

- * - *

J.M. Ogarrio and P. Spirtes and J. Ramsey, "A Hybrid Causal Search Algorithm - * for Latent Variable Models," JMLR 2016. Here, SP has been substituted for FGES.

- * - *

The reference for the SP algorithm is here:

- * - *

Raskutti, G., & Uhler, C. (2018). Learning directed acyclic graph models based - * on sparsest permutations. Stat, 7(1), e183.

- * - *

For SP only a score is needed, but there are steps in GFCI that require - * a test, so for this method, both a test and a score need to be given.

- * - *

Note that SP considers all permutations of the algorithm, which is - * exponential in the number of variables. So SP is limited to about 10 variables.

- * - *

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

+ * Uses SP in place of FGES for the initial step in the GFCI algorithm. This tends to produce a accurate PAG than GFCI + * as a result, for the latent variables case. This is a simple substitution; the reference for GFCI is here: + *

+ * J.M. Ogarrio and P. Spirtes and J. Ramsey, "A Hybrid Causal Search Algorithm for Latent Variable Models," JMLR 2016. + * Here, SP has been substituted for FGES. + *

+ * The reference for the SP algorithm is here: + *

+ * Raskutti, G., & Uhler, C. (2018). Learning directed acyclic graph models based on sparsest permutations. Stat, + * 7(1), e183. + *

+ * For SP only a score is needed, but there are steps in GFCI that require a test, so for this method, both a test and a + * score need to be given. + *

+ * Note that SP considers all permutations of the algorithm, which is exponential in the number of variables. So SP is + * limited to about 10 variables. + *

+ * This class is configured to respect knowledge of forbidden and required edges, including knowledge of temporal + * tiers. * * @author josephramsey * @author bryan andrews @@ -74,14 +73,14 @@ public final class SpFci implements IGraphSearch { private final TetradLogger logger = TetradLogger.getInstance(); // The score. private final Score score; + // The conditional independence test. + private final IndependenceTest independenceTest; // The sample size. int sampleSize; // The PAG being constructed. private Graph graph; // The background knowledge. private Knowledge knowledge = new Knowledge(); - // The conditional independence test. - private final IndependenceTest independenceTest; // Flag for complete rule set, true if you should use complete rule set, false otherwise. private boolean completeRuleSetUsed = true; // The maximum length for any discriminating path. -1 if unlimited; otherwise, a positive integer. @@ -329,7 +328,9 @@ private void modifiedR0(Graph fgesGraph, SepsetProducer sepsets) { * Orients according to background knowledge */ private void fciOrientbk(Knowledge knowledge, Graph graph, List variables) { - this.logger.log("info", "Starting BK Orientation."); + if (verbose) { + this.logger.log("info", "Starting BK Orientation."); + } for (Iterator it = knowledge.forbiddenEdgesIterator(); it.hasNext(); ) { KnowledgeEdge edge = it.next(); @@ -371,7 +372,9 @@ private void fciOrientbk(Knowledge knowledge, Graph graph, List variables) this.logger.log("knowledgeOrientation", LogUtilsSearch.edgeOrientedMsg("Knowledge", graph.getEdge(from, to))); } - this.logger.log("info", "Finishing BK Orientation."); + if (verbose) { + this.logger.log("info", "Finishing BK Orientation."); + } } } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/SuborderSearch.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/SuborderSearch.java index ca60755df1..4dcef3ddfb 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/SuborderSearch.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/SuborderSearch.java @@ -15,9 +15,9 @@ * x1a,...,x1n as a prefix. This is used by PermutationSearch to form a complete permutation search algorithm, where * PermutationSearch handles an optimization for tiered knowledge where each tier can be searched separately in order. * (See the documentation for that class.) - * - *

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

+ *

+ * This class is configured to respect knowledge of forbidden and required edges, including knowledge of temporal + * tiers. * * @author bryanandrews * @see PermutationSearch diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/SvarFas.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/SvarFas.java index dd862c6469..c3cb31c0c8 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/SvarFas.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/SvarFas.java @@ -36,22 +36,21 @@ import java.util.*; /** - *

Adapts FAS for the time series setting, assuming the data is generated by a - * SVAR (structural vector autoregression). The main difference is that time order is imposed, and if an edge is - * removed, it will also remove all homologous edges to preserve the time-repeating structure assumed by SvarFCI. Based - * on (but not identical to) code by Entner and Hoyer for their 2010 paper. Modified by dmalinsky 4/21/2016.

- * - *

The references are as follows:

- * - *

Malinsky, D., & Spirtes, P. (2018, August). Causal structure learning from multivariate - * time series in settings with unmeasured confounding. In Proceedings of 2018 ACM SIGKDD workshop on causal discovery - * (pp. 23-47). PMLR.

- * - *

Entner, D., & Hoyer, P. O. (2010). On causal discovery from time series data using FCI. Probabilistic - * graphical models, 121-128.

- * - *

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

+ * Adapts FAS for the time series setting, assuming the data is generated by a SVAR (structural vector autoregression). + * The main difference is that time order is imposed, and if an edge is removed, it will also remove all homologous + * edges to preserve the time-repeating structure assumed by SvarFCI. Based on (but not identical to) code by Entner and + * Hoyer for their 2010 paper. Modified by dmalinsky 4/21/2016. + *

+ * The references are as follows: + *

+ * Malinsky, D., & Spirtes, P. (2018, August). Causal structure learning from multivariate time series in settings + * with unmeasured confounding. In Proceedings of 2018 ACM SIGKDD workshop on causal discovery (pp. 23-47). PMLR. + *

+ * Entner, D., & Hoyer, P. O. (2010). On causal discovery from time series data using FCI. Probabilistic graphical + * models, 121-128. + *

+ * This class is configured to respect knowledge of forbidden and required edges, including knowledge of temporal + * tiers. * * @author dmalinsky * @see Fas @@ -60,51 +59,35 @@ */ public class SvarFas implements IFas { - /** - * The search graph. It is assumed going in that all 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. - */ + // The search graph. It is assumed going in that all 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 - */ + //The independence test. This should be appropriate to the types private final IndependenceTest test; - /** - * The logger, by default the empty logger. - */ + // The logger, by default the empty logger. private final TetradLogger logger = TetradLogger.getInstance(); + // The number formatter. private final NumberFormat nf = new DecimalFormat("0.00E0"); - /** - * Specification of which edges are forbidden or required. - */ + // 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. - */ + // 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. - */ + // The number of independence tests. private int numIndependenceTests; - /** - * The sepsets found during the search. - */ + // The sepsets found during the search. private SepsetMap sepset = new SepsetMap(); - /** - * The depth 0 graph, specified initially. - */ + // The depth 0 graph, specified initially. private Graph externalGraph; - /** - * True iff verbose output should be printed. - */ + // True iff verbose output should be printed. private boolean verbose; - + // The output stream for printing. private PrintStream out = System.out; /** * Constructs a new FastAdjacencySearch. + * + * @param test The independence test. */ public SvarFas(IndependenceTest test) { this.graph = new EdgeListGraph(test.getVariables()); @@ -113,10 +96,10 @@ public SvarFas(IndependenceTest test) { /** * 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 + * 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 @@ -283,7 +266,7 @@ private boolean searchAtDepth0(List nodes, IndependenceTest test, Map itx1 = simListX.iterator(); Iterator ity1 = simListY.iterator(); @@ -294,13 +277,13 @@ private boolean searchAtDepth0(List nodes, IndependenceTest test, Map nodes, IndependenceTest test, Map condSetAB = new HashSet<>(); for (Node tempNode : condSet) { - int ind_temptier = this.knowledge.isInWhichTier(tempNode); - List temptier = this.knowledge.getTier(ind_temptier); - int ind_temp = -1; - for (int j = 0; j < temptier.size(); ++j) { - if (getNameNoLag(tempNode.getName()).equals(getNameNoLag(temptier.get(j)))) { - ind_temp = j; + int indTempTier = this.knowledge.isInWhichTier(tempNode); + List tempTier = this.knowledge.getTier(indTempTier); + int indTemp = -1; + for (int j = 0; j < tempTier.size(); ++j) { + if (getNameNoLag(tempNode.getName()).equals(getNameNoLag(tempTier.get(j)))) { + indTemp = j; break; } } - int cond_diff = indx_tier - ind_temptier; + int cond_diff = indx_tier - indTempTier; int condAB_tier = this.knowledge.isInWhichTier(x1) - cond_diff; if (condAB_tier < 0 || condAB_tier > (ntiers - 1) || this.knowledge.getTier(condAB_tier).size() == 1) { // added condition for time tier 05.29.2016 @@ -576,7 +558,7 @@ private void removeSimilarPairs(Map> adjacencies, IndependenceTe continue; } List new_tier = this.knowledge.getTier(condAB_tier); - String tempNode1 = new_tier.get(ind_temp); + String tempNode1 = new_tier.get(indTemp); System.out.println("adding variable " + tempNode1 + " to SepSet"); condSetAB.add(test.getVariable(tempNode1)); } @@ -597,17 +579,17 @@ private void removeSimilarPairs(Map> adjacencies, IndependenceTe System.out.println("removed edge between " + x1 + " and " + y1 + " because of structure knowledge"); Set condSetAB = new HashSet<>(); for (Node tempNode : condSet) { - int ind_temptier = this.knowledge.isInWhichTier(tempNode); - List temptier = this.knowledge.getTier(ind_temptier); + int indTempTier = this.knowledge.isInWhichTier(tempNode); + List tempTier = this.knowledge.getTier(indTempTier); int ind_temp = -1; - for (int j = 0; j < temptier.size(); ++j) { - if (getNameNoLag(tempNode.getName()).equals(getNameNoLag(temptier.get(j)))) { + for (int j = 0; j < tempTier.size(); ++j) { + if (getNameNoLag(tempNode.getName()).equals(getNameNoLag(tempTier.get(j)))) { ind_temp = j; break; } } - int cond_diff = indx_tier - ind_temptier; + int cond_diff = indx_tier - indTempTier; int condAB_tier = this.knowledge.isInWhichTier(x1) - cond_diff; if (condAB_tier < 0 || condAB_tier > (ntiers - 1) || this.knowledge.getTier(condAB_tier).size() == 1) { // added condition for time tier 05.29.2016 diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/SvarFci.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/SvarFci.java index 7e46fa7170..d8543867e6 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/SvarFci.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/SvarFci.java @@ -37,68 +37,50 @@ import java.util.Set; /** - *

Adapts FCI for the time series setting, assuming the data is generated by a - * SVAR (structural vector autoregression). The main difference is that time order is imposed, and if an edge is - * removed, it will also remove all homologous edges to preserve the time-repeating structure assumed by SvarFCI. Based - * on (but not identical to) code by Entner and Hoyer for their 2010 paper. Modified by dmalinsky 4/21/2016.

- * - *

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.)

- * - *

The references are as follows:

- * - *

Malinsky, D., & Spirtes, P. (2018, August). Causal structure learning from multivariate - * time series in settings with unmeasured confounding. In Proceedings of 2018 ACM SIGKDD workshop on causal discovery - * (pp. 23-47). PMLR.

- * - *

Entner, D., & Hoyer, P. O. (2010). On causal discovery from time series data using FCI. Probabilistic - * graphical models, 121-128.

- * - *

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

+ * Adapts FCI for the time series setting, assuming the data is generated by a SVAR (structural vector autoregression). + * The main difference is that time order is imposed, and if an edge is removed, it will also remove all homologous + * edges to preserve the time-repeating structure assumed by SvarFCI. Based on (but not identical to) code by Entner and + * Hoyer for their 2010 paper. Modified by dmalinsky 4/21/2016. + *

+ * 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.) + *

+ * The references are as follows: + *

+ * Malinsky, D., & Spirtes, P. (2018, August). Causal structure learning from multivariate time series in settings + * with unmeasured confounding. In Proceedings of 2018 ACM SIGKDD workshop on causal discovery (pp. 23-47). PMLR. + *

+ * Entner, D., & Hoyer, P. O. (2010). On causal discovery from time series data using FCI. Probabilistic graphical + * models, 121-128. + *

+ * This class is configured to respect knowledge of forbidden and required edges, including knowledge of temporal + * tiers. * * @author danielmalinsky * @see Fci * @see Knowledge */ public final class SvarFci implements IGraphSearch { - + // The independence test to use. private final IndependenceTest independenceTest; - /** - * The logger to use. - */ + // The logger to use. private final TetradLogger logger = TetradLogger.getInstance(); - /** - * The PAG being constructed. - */ + // The PAG being constructed. private Graph graph; - /** - * The SepsetMap being constructed. - */ + // The SepsetMap being constructed. private SepsetMap sepsets; - /** - * The background knowledge. - */ + // The background knowledge. private Knowledge knowledge = new Knowledge(); - /** - * flag for the complete rule set, true if it should use the complete rule set, false otherwise. - */ + // flag for the complete rule set, true if it should use the complete rule set, false otherwise. private boolean completeRuleSetUsed; - /** - * The maximum length for any discriminating path. -1 if unlimited; otherwise, a positive integer. - */ + // 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. - */ + // The depth for the fast adjacency search. private int depth = -1; - /** - * True iff verbose output should be printed. - */ + // True iff verbose output should be printed. private boolean verbose; - /** * Constructs a new FCI search for the given independence test and background knowledge. */ @@ -385,22 +367,22 @@ private void removeSimilarPairs(IndependenceTest test, Node x, Node y, Set break; } - int ind_temptier = this.knowledge.isInWhichTier(tempNode); - List temptier = this.knowledge.getTier(ind_temptier); + int indTempTier = this.knowledge.isInWhichTier(tempNode); + List tempTier = this.knowledge.getTier(indTempTier); int ind_temp = -1; - for (int j = 0; j < temptier.size(); ++j) { + for (int j = 0; j < tempTier.size(); ++j) { if (Thread.currentThread().isInterrupted()) { break; } - if (getNameNoLag(tempNode.getName()).equals(getNameNoLag(temptier.get(j)))) { + if (getNameNoLag(tempNode.getName()).equals(getNameNoLag(tempTier.get(j)))) { ind_temp = j; break; } } - int cond_diff = indx_tier - ind_temptier; + int cond_diff = indx_tier - indTempTier; int condAB_tier = this.knowledge.isInWhichTier(x1) - cond_diff; if (condAB_tier < 0 || condAB_tier > (ntiers - 1) @@ -434,18 +416,18 @@ private void removeSimilarPairs(IndependenceTest test, Node x, Node y, Set break; } - int ind_temptier = this.knowledge.isInWhichTier(tempNode); - List temptier = this.knowledge.getTier(ind_temptier); + int indTempTier = this.knowledge.isInWhichTier(tempNode); + List tempTier = this.knowledge.getTier(indTempTier); int ind_temp = -1; - for (int j = 0; j < temptier.size(); ++j) { - if (getNameNoLag(tempNode.getName()).equals(getNameNoLag(temptier.get(j)))) { + for (int j = 0; j < tempTier.size(); ++j) { + if (getNameNoLag(tempNode.getName()).equals(getNameNoLag(tempTier.get(j)))) { ind_temp = j; break; } } - int cond_diff = indx_tier - ind_temptier; + int cond_diff = indx_tier - indTempTier; int condAB_tier = this.knowledge.isInWhichTier(x1) - cond_diff; if (condAB_tier < 0 || condAB_tier > (ntiers - 1) diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/SvarFges.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/SvarFges.java index 092342ba34..a214b5105d 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/SvarFges.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/SvarFges.java @@ -39,22 +39,21 @@ import java.util.concurrent.*; /** - *

Adapts FGES for the time series setting, assuming the data is generated by a - * SVAR (structural vector autoregression). The main difference is that time order is imposed, and if an edge is - * removed, it will also remove all homologous edges to preserve the time-repeating structure assumed by SvarFCI. Based - * on (but not identical to) code by Entner and Hoyer for their 2010 paper. Modified by dmalinsky 4/21/2016.

- * - *

The references are as follows:

- * - *

Malinsky, D., & Spirtes, P. (2018, August). Causal structure learning from multivariate - * time series in settings with unmeasured confounding. In Proceedings of 2018 ACM SIGKDD workshop on causal discovery - * (pp. 23-47). PMLR.

- * - *

Entner, D., & Hoyer, P. O. (2010). On causal discovery from time series data using FCI. Probabilistic - * graphical models, 121-128.

- * - *

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

+ * Adapts FGES for the time series setting, assuming the data is generated by a SVAR (structural vector autoregression). + * The main difference is that time order is imposed, and if an edge is removed, it will also remove all homologous + * edges to preserve the time-repeating structure assumed by SvarFCI. Based on (but not identical to) code by Entner and + * Hoyer for their 2010 paper. Modified by dmalinsky 4/21/2016. + *

+ * The references are as follows: + *

+ * Malinsky, D., & Spirtes, P. (2018, August). Causal structure learning from multivariate time series in settings + * with unmeasured confounding. In Proceedings of 2018 ACM SIGKDD workshop on causal discovery (pp. 23-47). PMLR. + *

+ * Entner, D., & Hoyer, P. O. (2010). On causal discovery from time series data using FCI. Probabilistic graphical + * models, 121-128. + *

+ * This class is configured to respect knowledge of forbidden and required edges, including knowledge of temporal + * tiers. * * @author danielmalinsky * @see Fges @@ -63,54 +62,37 @@ */ public final class SvarFges implements IGraphSearch, DagScorer { + // The number of threads to use. final int maxThreads = ForkJoinPoolInstance.getInstance().getPool().getParallelism(); - /** - * The logger for this class. The config needs to be set. - */ + // The logger for this class. The config needs to be set. private final TetradLogger logger = TetradLogger.getInstance(); - /** - * The top n graphs found by the algorithm, where n is numCPDAGsToStore. - */ + // The top n graphs found by the algorithm, where n is numCPDAGsToStore. private final LinkedList topGraphs = new LinkedList<>(); // The static ForkJoinPool instance. private final ForkJoinPool pool = ForkJoinPoolInstance.getInstance().getPool(); + // The number of graphs searched. private final int[] count = new int[1]; // Arrows with the same totalScore are stored in this list to distinguish their order in sortedArrows. // The ordering doesn't matter; it just has to be transitive. - int arrowIndex; - Set removedEdges = new HashSet<>(); - /** - * Specification of forbidden and required edges. - */ + private int arrowIndex; + // The set of removed edges. + private Set removedEdges = new HashSet<>(); + // Specification of forbidden and required edges. private Knowledge knowledge = new Knowledge(); - /** - * List of variables in the data set, in order. - */ + // List of variables in the data set, in order. private List variables; - /** - * The true graph, if known. If this is provided, asterisks will be printed out next to false positive added edges - * (that is, edges added that aren't adjacencies in the true graph). - */ + // The true graph, if known. If this is provided, asterisks will be printed out next to false positive added edges + // (that is, edges added that aren't adjacencies in the true graph). private Graph trueGraph; - /** - * An initial graph to start from. - */ + // An initial graph to start from. private Graph externalGraph; - /** - * Elapsed time of the most recent search. - */ + // Elapsed time of the most recent search. private long elapsedTime; - /** - * The totalScore for discrete searches. - */ + // The totalScore for discrete searches. private Score score; - /** - * The number of top CPDAGs to store. - */ + // The number of top CPDAGs to store. private int numCPDAGsToStore; - /** - * True if verbose output should be printed. - */ + // True if verbose output should be printed. private boolean verbose; // Potential arrows sorted by bump high to low. The first one is a candidate for adding to the graph. private SortedSet sortedArrows; @@ -132,14 +114,11 @@ public final class SvarFges implements IGraphSearch, DagScorer { private Graph graph; // Internal. private Mode mode = Mode.heuristicSpeedup; - /** - * True if one-edge faithfulness is assumed. Speeds the algorithm up. - */ + // True if one-edge faithfulness is assumed. Speeds the algorithm up. private boolean faithfulnessAssumed = false; // Bounds the indegree of the graph. private int maxIndegree = -1; - /** * Construct a Score and pass it in here. The totalScore should return a positive value in case of conditional * dependence and a negative values in case of conditional independence. See Chickering (2002), locally consistent @@ -151,7 +130,6 @@ public SvarFges(Score score) { this.graph = new EdgeListGraph(getVariables()); } - // Used to find semidirected paths for cycle checking. private static Node traverseSemiDirected(Node node, Edge edge) { if (node == edge.getNode1()) { @@ -167,8 +145,8 @@ private static Node traverseSemiDirected(Node node, Edge edge) { } /** - * Greedy equivalence search: Start from the empty graph, add edges till the model is significant. Then start deleting - * edges till a minimum is achieved. + * Greedy equivalence search: Start from the empty graph, add edges till the model is significant. Then start + * deleting edges till a minimum is achieved. * * @return the resulting CPDAG. */ @@ -261,13 +239,18 @@ public long getElapsedTime() { } /** - * If the true graph is set, asterisks will be printed in log output for the true edges. + * Sets the true graph, which will result in some edges in output graphs being marked with asterisks. + * + * @param trueGraph the true graph. */ public void setTrueGraph(Graph trueGraph) { this.trueGraph = trueGraph; } /** + * Returns the score of the given DAG. + * + * @param dag the dag to score. * @return the totalScore of the given DAG, up to a constant. */ public double getScore(Graph dag) { @@ -301,6 +284,8 @@ public Graph getExternalGraph() { /** * Sets the initial graph. + * + * @param externalGraph the initial graph. */ public void setExternalGraph(Graph externalGraph) { if (externalGraph != null) { @@ -321,6 +306,7 @@ public void setExternalGraph(Graph externalGraph) { /** * Sets whether verbose output should be produced. + * @param verbose true if verbose output should be produced. */ public void setVerbose(boolean verbose) { this.verbose = verbose; @@ -335,6 +321,7 @@ public PrintStream getOut() { /** * Sets the output stream that output (except for log output) should be sent to. By detault System.out. + * @param out the output stream. */ public void setOut(PrintStream out) { this.out = out; @@ -349,53 +336,12 @@ public Graph getAdjacencies() { /** * Sets the set of preset adjacencies for the algorithm; edges not in this adjacencies graph will not be added. + * @param adjacencies the adjacencies graph. */ public void setAdjacencies(Graph adjacencies) { this.adjacencies = adjacencies; } - /** - * For BIC totalScore, a multiplier on the penalty term. For continuous searches. - * - * @deprecated Use the getters on the individual scores instead. - */ - public double getPenaltyDiscount() { - if (this.score instanceof HasPenaltyDiscount) { - return ((HasPenaltyDiscount) this.score).getPenaltyDiscount(); - } else { - return 2.0; - } - } - - /** - * For BIC totalScore, a multiplier on the penalty term. For continuous searches. - * - * @deprecated Use the setters on the individual scores instead. - */ - public void setPenaltyDiscount(double penaltyDiscount) { - if (this.score instanceof HasPenaltyDiscount) { - ((HasPenaltyDiscount) this.score).setPenaltyDiscount(penaltyDiscount); - } - } - - /** - * @deprecated Use the setters on the individual scores instead. - */ - public void setSamplePrior(double samplePrior) { - if (this.score instanceof DiscreteScore) { - ((DiscreteScore) this.score).setSamplePrior(samplePrior); - } - } - - /** - * @deprecated Use the setters on the individual scores instead. - */ - public void setStructurePrior(double expectedNumParents) { - if (this.score instanceof DiscreteScore) { - ((DiscreteScore) this.score).setStructurePrior(expectedNumParents); - } - } - /** * The maximum of parents any nodes can have in the output pattern. * @@ -415,13 +361,42 @@ public void setMaxIndegree(int maxIndegree) { this.maxIndegree = maxIndegree; } - + /** + * @return the graph being constructed. + */ public int getMinChunk(int n) { // The minimum number of operations to do before parallelizing. int minChunk = 100; return FastMath.max(n / this.maxThreads, minChunk); } + /** + * Scores the given DAG, up to a constant. + */ + public double scoreDag(Graph dag) { + buildIndexing(dag.getNodes()); + + double _score = 0.0; + + for (Node y : dag.getNodes()) { + Set parents = new HashSet<>(dag.getParents(y)); + int[] parentIndices = new int[parents.size()]; + Iterator pi = parents.iterator(); + int count = 0; + + while (pi.hasNext()) { + Node nextParent = pi.next(); + parentIndices[count++] = this.hashIndices.get(nextParent); + } + + int yIndex = this.hashIndices.get(y); + _score += this.score.localScore(yIndex, parentIndices); + } + + return _score; + } + + //Sets the discrete scoring function to use. private void setScore(Score totalScore) { this.score = totalScore; @@ -461,8 +436,7 @@ protected Boolean compute() { int numNodesPerTask = FastMath.max(100, nodes.size() / SvarFges.this.maxThreads); for (int i = 0; i < nodes.size(); i += numNodesPerTask) { - NodeTaskEmptyGraph task = new NodeTaskEmptyGraph(i, FastMath.min(nodes.size(), i + numNodesPerTask), - nodes, emptySet); + NodeTaskEmptyGraph task = new NodeTaskEmptyGraph(i, FastMath.min(nodes.size(), i + numNodesPerTask), nodes, emptySet); tasks.add(task); task.fork(); @@ -1041,8 +1015,7 @@ class BackwardTask extends RecursiveTask { private final int from; private final int to; - public BackwardTask(Node r, List adj, int chunk, int from, int to, - Map hashIndices) { + public BackwardTask(Node r, List adj, int chunk, int from, int to, Map hashIndices) { this.adj = adj; this.hashIndices = hashIndices; this.chunk = chunk; @@ -1092,8 +1065,7 @@ protected Boolean compute() { for (Node r : toProcess) { this.neighbors.put(r, getNeighbors(r)); List adjacentNodes = new ArrayList<>(this.graph.getAdjacentNodes(r)); - this.pool.invoke(new BackwardTask(r, adjacentNodes, getMinChunk(adjacentNodes.size()), 0, - adjacentNodes.size(), this.hashIndices)); + this.pool.invoke(new BackwardTask(r, adjacentNodes, getMinChunk(adjacentNodes.size()), 0, adjacentNodes.size(), this.hashIndices)); } } @@ -1181,8 +1153,7 @@ private Set getNeighbors(Node y) { } // Evaluate the Insert(X, Y, T) operator (Definition 12 from Chickering, 2002). - private double insertEval(Node x, Node y, Set t, Set naYX, - Map hashIndices) { + private double insertEval(Node x, Node y, Set t, Set naYX, Map hashIndices) { Set set = new HashSet<>(naYX); set.addAll(t); set.addAll(this.graph.getParents(y)); @@ -1190,8 +1161,7 @@ private double insertEval(Node x, Node y, Set t, Set naYX, } // Evaluate the Delete(X, Y, T) operator (Definition 12 from Chickering, 2002). - private double deleteEval(Node x, Node y, Set diff, - Map hashIndices) { + private double deleteEval(Node x, Node y, Set diff, Map hashIndices) { Set set = new HashSet<>(diff); set.addAll(this.graph.getParents(y)); set.remove(x); @@ -1219,8 +1189,7 @@ private boolean insert(Node x, Node y, Set T, double bump) { if (this.verbose) { String label = this.trueGraph != null && trueEdge != null ? "*" : ""; - TetradLogger.getInstance().log("insertedEdges", this.graph.getNumEdges() + ". INSERT " + this.graph.getEdge(x, y) + - " " + T + " " + bump + " " + label); + TetradLogger.getInstance().log("insertedEdges", this.graph.getNumEdges() + ". INSERT " + this.graph.getEdge(x, y) + " " + T + " " + bump + " " + label); } int numEdges = this.graph.getNumEdges(); @@ -1229,10 +1198,7 @@ private boolean insert(Node x, Node y, Set T, double bump) { if (this.verbose) { String label = this.trueGraph != null && trueEdge != null ? "*" : ""; - this.out.println(this.graph.getNumEdges() + ". INSERT " + this.graph.getEdge(x, y) + - " " + T + " " + bump + " " + label - + " degree = " + GraphUtils.getDegree(this.graph) - + " indegree = " + GraphUtils.getIndegree(this.graph)); + this.out.println(this.graph.getNumEdges() + ". INSERT " + this.graph.getEdge(x, y) + " " + T + " " + bump + " " + label + " degree = " + GraphUtils.getDegree(this.graph) + " indegree = " + GraphUtils.getIndegree(this.graph)); } for (Node _t : T) { @@ -1284,8 +1250,7 @@ private boolean delete(Node x, Node y, Set H, double bump, Set naYX) if (this.verbose) { String label = this.trueGraph != null && trueEdge != null ? "*" : ""; - String message = (this.graph.getNumEdges()) + ". DELETE " + x + "-->" + y + - " H = " + H + " NaYX = " + naYX + " diff = " + diff + " (" + bump + ") " + label; + String message = (this.graph.getNumEdges()) + ". DELETE " + x + "-->" + y + " H = " + H + " NaYX = " + naYX + " diff = " + diff + " (" + bump + ") " + label; TetradLogger.getInstance().log("deletedEdges", message); this.out.println(message); } @@ -1304,8 +1269,7 @@ private boolean delete(Node x, Node y, Set H, double bump, Set naYX) // **/ if (this.verbose) { - TetradLogger.getInstance().log("directedEdges", "--- Directing " + oldyh + " to " + - this.graph.getEdge(y, h)); + TetradLogger.getInstance().log("directedEdges", "--- Directing " + oldyh + " to " + this.graph.getEdge(y, h)); this.out.println("--- Directing " + oldyh + " to " + this.graph.getEdge(y, h)); } @@ -1322,8 +1286,7 @@ private boolean delete(Node x, Node y, Set H, double bump, Set naYX) // **/ if (this.verbose) { - TetradLogger.getInstance().log("directedEdges", "--- Directing " + oldxh + " to " + - this.graph.getEdge(x, h)); + TetradLogger.getInstance().log("directedEdges", "--- Directing " + oldxh + " to " + this.graph.getEdge(x, h)); this.out.println("--- Directing " + oldxh + " to " + this.graph.getEdge(x, h)); } } @@ -1569,34 +1532,8 @@ private void addLookupArrow(Node i, Node j, Arrow arrow) { arrows.add(arrow); } - /** - * Scores the given DAG, up to a constant. - */ - public double scoreDag(Graph dag) { - buildIndexing(dag.getNodes()); - - double _score = 0.0; - - for (Node y : dag.getNodes()) { - Set parents = new HashSet<>(dag.getParents(y)); - int[] parentIndices = new int[parents.size()]; - Iterator pi = parents.iterator(); - int count = 0; - - while (pi.hasNext()) { - Node nextParent = pi.next(); - parentIndices[count++] = this.hashIndices.get(nextParent); - } - - int yIndex = this.hashIndices.get(y); - _score += this.score.localScore(yIndex, parentIndices); - } - - return _score; - } - private double scoreGraphChange(Node y, Set parents, - Node x, Map hashIndices) { + private double scoreGraphChange(Node y, Set parents, Node x, Map hashIndices) { int yIndex = hashIndices.get(y); if (parents.contains(x)) return Double.NaN;//throw new IllegalArgumentException(); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/SvarGfci.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/SvarGfci.java index 50cccb97f3..895758de19 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/SvarGfci.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/SvarGfci.java @@ -40,22 +40,21 @@ /** - *

Adapts GFCI for the time series setting, assuming the data is generated by a - * SVAR (structural vector autoregression). The main difference is that time order is imposed, and if an edge is - * removed, it will also remove all homologous edges to preserve the time-repeating structure assumed by SvarFCI. Based - * on (but not identical to) code by Entner and Hoyer for their 2010 paper. Modified by dmalinsky 4/21/2016.

- * - *

The references are as follows:

- * - *

Malinsky, D., & Spirtes, P. (2018, August). Causal structure learning from multivariate - * time series in settings with unmeasured confounding. In Proceedings of 2018 ACM SIGKDD workshop on causal discovery - * (pp. 23-47). PMLR.

- * - *

Entner, D., & Hoyer, P. O. (2010). On causal discovery from time series data using FCI. Probabilistic - * graphical models, 121-128.

- * - *

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

+ * Adapts GFCI for the time series setting, assuming the data is generated by a SVAR (structural vector autoregression). + * The main difference is that time order is imposed, and if an edge is removed, it will also remove all homologous + * edges to preserve the time-repeating structure assumed by SvarFCI. Based on (but not identical to) code by Entner and + * Hoyer for their 2010 paper. Modified by dmalinsky 4/21/2016. + *

+ * The references are as follows: + *

+ * Malinsky, D., & Spirtes, P. (2018, August). Causal structure learning from multivariate time series in settings + * with unmeasured confounding. In Proceedings of 2018 ACM SIGKDD workshop on causal discovery (pp. 23-47). PMLR. + *

+ * Entner, D., & Hoyer, P. O. (2010). On causal discovery from time series data using FCI. Probabilistic graphical + * models, 121-128. + *

+ * This class is configured to respect knowledge of forbidden and required edges, including knowledge of temporal + * tiers. * * @author danielmalinsky * @see GFci @@ -63,32 +62,33 @@ * @see SvarFci */ public final class SvarGfci implements IGraphSearch { - // The logger to use. private final TetradLogger logger = TetradLogger.getInstance(); + // The conditional independence test. + private final IndependenceTest independenceTest; // The covariance matrix being searched over. Assumes continuous data. ICovarianceMatrix covarianceMatrix; // The PAG being constructed. private Graph graph; // The background knowledge. private Knowledge knowledge = new Knowledge(); - // The conditional independence test. - private final IndependenceTest independenceTest; // Flag for the complete rule set, true if one should use the complete rule set, false otherwise. private boolean completeRuleSetUsed; // The maximum length for any discriminating path. -1 if unlimited; otherwise, a positive integer. private int maxPathLength = -1; // True iff verbose output should be printed. private boolean verbose; - // The score. private Score score; - + // The sepsets. private SepsetProducer sepsets; /** * Constructs a new GFCI search for the given independence test and background knowledge. + * + * @param test The independence test. + * @param score The score. */ public SvarGfci(IndependenceTest test, Score score) { if (score == null) { @@ -300,7 +300,9 @@ private void modifiedR0(Graph fgesGraph) { * Orients according to background knowledge */ private void fciOrientbk(Knowledge knowledge, Graph graph, List variables) { - this.logger.log("info", "Starting BK Orientation."); + if (verbose) { + this.logger.log("info", "Starting BK Orientation."); + } for (Iterator it = knowledge.forbiddenEdgesIterator(); it.hasNext(); ) { KnowledgeEdge edge = it.next(); @@ -344,7 +346,9 @@ private void fciOrientbk(Knowledge knowledge, Graph graph, List variables) this.logger.log("knowledgeOrientation", LogUtilsSearch.edgeOrientedMsg("Knowledge", graph.getEdge(from, to))); } - this.logger.log("info", "Finishing BK Orientation."); + if (verbose) { + this.logger.log("info", "Finishing BK Orientation."); + } } private String getNameNoLag(Object obj) { diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/BdeScore.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/BdeScore.java index b847fa57b8..88f534c88b 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/BdeScore.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/BdeScore.java @@ -30,19 +30,20 @@ import java.util.List; /** - *

Calculates the BDe score (Bayes Dirichlet Equivalent) score for analyzing - * discrete multinomial data. A good discussion of BD* scores can be found here:

- * - *

Heckerman, D., Geiger, D. & Chickering, D.M. Learning Bayesian networks: - * The combination of knowledge and statistical data. Mach Learn 20, 197–243 (1995).

- * - *

As for all scores in Tetrad, higher scores mean more dependence, and negative - * scores indicate independence.

+ * Calculates the BDe score (Bayes Dirichlet Equivalent) score for analyzing discrete multinomial data. A good + * discussion of BD* scores can be found here: + *

+ * Heckerman, D., Geiger, D. & Chickering, D.M. Learning Bayesian networks: The combination of knowledge and + * statistical data. Mach Learn 20, 197–243 (1995). + *

+ * As for all scores in Tetrad, higher scores mean more dependence, and negative scores indicate independence. * * @author josephramsey * @see BdeuScore */ public class BdeScore implements DiscreteScore { + + // The discrete dataset. private final DataSet dataSet; /** @@ -72,7 +73,7 @@ public BdeScore(DataSet dataSet) { */ public double localScore(int i, int[] parents) { - // Number of categories for i. + // Number of categories for index i. int r = numCategories(i); // Numbers of categories of parents. @@ -115,10 +116,7 @@ public double localScore(int i, int[] parents) { } int rowIndex = getRowIndex(dims, values); - -// for (int m = 0; m < dataSet().getMultiplier(n); m++) { n_ijk[rowIndex][childValue]++; -// } } // Row sums. @@ -152,12 +150,12 @@ public double localScore(int i, int[] parents) { } /** - * Returns the different between localScore(y | z, x) and localScore(y | z) + * Returns the difference between localScore(y | z, x) and localScore(y | z) * * @param x The index of the x variable * @param y The index of the y variable. * @param z The indices of the z variables - * @return The differnece in scores. + * @return The difference in scores. */ @Override public double localScoreDiff(int x, int y, int[] z) { @@ -185,9 +183,6 @@ private int getRowIndex(int[] dim, int[] values) { } /** - * BDe does not use a structure prior. - * - * @param structurePrior The structure prior (not used). * @throws UnsupportedOperationException Since this method is not implemented for this score. */ public void setStructurePrior(double structurePrior) { @@ -195,9 +190,6 @@ public void setStructurePrior(double structurePrior) { } /** - * BDe does not use a sample prior. - * - * @param samplePrior The structure prior (not used). * @throws UnsupportedOperationException Since this method is not implemented for this score. */ public void setSamplePrior(double samplePrior) { diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/BdeuScore.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/BdeuScore.java index bc89865464..08dde7dfeb 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/BdeuScore.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/BdeuScore.java @@ -32,26 +32,33 @@ import java.util.List; /** - *

Calculates the BDeu score, which the BDe (Bayes Dirichlet Equivalent) score - * with uniform priors. A good discussion of BD* scores can be found here:

- * - *

Heckerman, D., Geiger, D. & Chickering, D.M. Learning Bayesian networks: - * The combination of knowledge and statistical data. Mach Learn 20, 197–243 (1995).

- * - *

As for all scores in Tetrad, higher scores mean more dependence, and negative - * scores indicate independence.

+ * Calculates the BDeu score, which the BDe (Bayes Dirichlet Equivalent) score with uniform priors. A good discussion of + * BD* scores can be found here: + *

+ * Heckerman, D., Geiger, D. & Chickering, D.M. Learning Bayesian networks: The combination of knowledge and + * statistical data. Mach Learn 20, 197–243 (1995). + *

+ * As for all scores in Tetrad, higher scores mean more dependence, and negative scores indicate independence. * * @author josephramsey * @see BdeScore */ public class BdeuScore implements DiscreteScore { + + // The discrete dataset. private final int[][] data; + // The sample size of the data. private final int sampleSize; + // The number of categories for each variable. private final int[] numCategories; + // The discrete dataset. private final DataSet dataSet; - private List variables; - private double samplePrior = 1; - private double structurePrior = 1; + // The variables of the dataset. + private final List variables; + // The sample prior. + private double samplePrior = 1d; + // The structure prior. + private double structurePrior = 0d; /** * Constructs a BDe score for the given dataset. @@ -196,7 +203,7 @@ public double localScore(int node, int[] parents) { * * @param x The index of x. * @param y The index of y. - * @param z The indeces of the z variables. + * @param z The indices of the z variables. * @return The score difference. */ @Override @@ -214,23 +221,6 @@ public List getVariables() { return this.variables; } - /** - * Sets the variables to another of the same names, in the same order. - * - * @param variables The new varialbe list. - * @see edu.cmu.tetrad.algcomparison.algorithm.multi.Images - */ - void setVariables(List variables) { - for (int i = 0; i < variables.size(); i++) { - if (!variables.get(i).getName().equals(this.variables.get(i).getName())) { - throw new IllegalArgumentException("Variable in index " + (i + 1) + " does not have the same name " + - "as the variable being substituted for it."); - } - } - - this.variables = variables; - } - /** * Returns the sample size of the data. * @@ -280,7 +270,7 @@ public void setStructurePrior(double structurePrior) { } /** - * Returns the smaple prior. + * Returns the sample prior. * * @return This prior. */ @@ -306,7 +296,7 @@ public void setSamplePrior(double samplePrior) { @Override public String toString() { NumberFormat nf = new DecimalFormat("0.00"); - return "BDeu Score SampP " + nf.format(this.samplePrior) + " StuctP " + nf.format(this.structurePrior); + return "BDeu Score Sample prior = " + nf.format(this.samplePrior) + " Structure prior = " + nf.format(this.structurePrior); } /** @@ -320,7 +310,7 @@ public int getMaxDegree() { } /** - * This score does not implement a method to decide whehter a node is determined by its parents. + * This score does not implement a method to decide whether a node is determined by its parents. * * @param z The parents. * @param y The node. diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/ConditionalGaussianLikelihood.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/ConditionalGaussianLikelihood.java index e62624bc15..e2fe86516a 100755 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/ConditionalGaussianLikelihood.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/ConditionalGaussianLikelihood.java @@ -27,6 +27,7 @@ import edu.cmu.tetrad.util.Matrix; import org.apache.commons.math3.stat.correlation.Covariance; import org.apache.commons.math3.util.FastMath; +import org.jetbrains.annotations.Contract; import java.util.ArrayList; import java.util.HashMap; @@ -39,15 +40,14 @@ import static org.apache.commons.math3.util.FastMath.log; /** - *

Implements a conditional Gaussian likelihood. Please note that this likelihood will be - * maximal only if the continuous variables are jointly Gaussian conditional on the discrete variables; in all other - * cases, it will be less than maximal. The reference is here:

- * - *

Andrews, B., Ramsey, J., & Cooper, G. F. (2018). Scoring Bayesian networks of mixed variables. - * International journal of data science and analytics, 6, 3-18.

- * - *

As for all scores in Tetrad, higher scores mean more dependence, and negative - * scores indicate independence.

+ * Implements a conditional Gaussian likelihood. Please note that this likelihood will be maximal only if the continuous + * variables are jointly Gaussian conditional on the discrete variables; in all other cases, it will be less than + * maximal. The reference is here: + *

+ * Andrews, B., Ramsey, J., & Cooper, G. F. (2018). Scoring Bayesian networks of mixed variables. International + * journal of data science and analytics, 6, 3-18. + *

+ * As for all scores in Tetrad, higher scores mean more dependence, and negative scores indicate independence. * * @author bryanandrews * @author josephramsey @@ -62,16 +62,12 @@ public class ConditionalGaussianLikelihood { private final DataSet dataSet; // The mixedVariables of the mixed data set. private final List mixedVariables; - // Indices of mixedVariables. private final Map nodesHash; - // Continuous data only. private final double[][] continuousData; // Number of categories to use to discretize continuous mixedVariables. private int numCategoriesToDiscretize = 3; - // Multiplier on degrees of freedom for the continuous portion of those degrees. - private double penaltyDiscount = 1; // "Cell" consisting of all rows. private List rows; // Discretize the parents @@ -79,6 +75,8 @@ public class ConditionalGaussianLikelihood { /** * Constructs the score using a covariance matrix. + * + * @param dataSet The continuous dataset to analyze. */ public ConditionalGaussianLikelihood(DataSet dataSet) { if (dataSet == null) { @@ -117,6 +115,10 @@ public ConditionalGaussianLikelihood(DataSet dataSet) { for (int i = 0; i < dataSet.getNumRows(); i++) this.rows.add(i); } + /** + * Sets the rows to use for the likelihood calculation. If not set, all rows will be used. + * @param rows The rows to use. + */ public void setRows(List rows) { this.rows = rows; } @@ -160,15 +162,6 @@ public Ret getLikelihood(int i, int[] parents) { return new Ret(ret1.getLik() - ret2.getLik(), ret1.getDof() - ret2.getDof()); } - /** - * Sets the penalty discount for this score, which is a multiplier on the panalty term of BIC. - * - * @param penaltyDiscount The penalty discount. - */ - public void setPenaltyDiscount(double penaltyDiscount) { - this.penaltyDiscount = penaltyDiscount; - } - /** * Sets whether to discretize child variables to avoid integration. An optimization. * @@ -180,7 +173,7 @@ public void setDiscretize(boolean discretize) { } /** - * Sets the number of categories to use to discretize child variables to avoid integrationl + * Sets the number of categories to use to discretize child variables to avoid integration * * @param numCategoriesToDiscretize This number. * @see #setDiscretize(boolean) @@ -264,11 +257,11 @@ private Ret likelihoodJoint(List X, List A if (a == 0) continue; - if (A.size() > 0) { + if (!A.isEmpty()) { c1 += a * multinomialLikelihood(a, rows.size()); } - if (X.size() > 0) { + if (!X.isEmpty()) { try { // Determinant will be zero if data are linearly dependent. @@ -358,13 +351,14 @@ private List> partition(List discrete_parents, L } /** - * Gives return value for a conditional Gaussain likelihood, returning a likelihood value and the degrees of freedom + * Gives return value for a conditional Gaussian likelihood, returning a likelihood value and the degrees of freedom * for it. */ - public static class Ret { + public static final class Ret { private final double lik; private final int dof; + @Contract(pure = true) private Ret(double lik, int dof) { this.lik = lik; this.dof = dof; diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/ConditionalGaussianScore.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/ConditionalGaussianScore.java index 18c5cd6ac6..b85c0a1d4f 100755 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/ConditionalGaussianScore.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/ConditionalGaussianScore.java @@ -35,33 +35,30 @@ import java.util.List; /** - *

Implements a conditional Gaussian BIC score for FGS, which calculates a BIC - * score for mixed discrete/Gaussian data using the conditional Gaussian likelihood function (see). The reference is - * here:

- * - *

Andrews, B., Ramsey, J., & Cooper, G. F. (2018). Scoring Bayesian networks of mixed variables. - * International journal of data science and analytics, 6, 3-18.

- * - *

As for all scores in Tetrad, higher scores mean more dependence, and negative - * scores indicate independence.

+ * Implements a conditional Gaussian BIC score for FGS, which calculates a BIC score for mixed discrete/Gaussian data + * using the conditional Gaussian likelihood function (see). The reference is here: + *

+ * Andrews, B., Ramsey, J., & Cooper, G. F. (2018). Scoring Bayesian networks of mixed variables. International + * journal of data science and analytics, 6, 3-18. *

- * * @author josephramsey + * As for all scores in Tetrad, higher scores mean more dependence, and negative scores indicate independence. * + * @author josephramsey * @see ConditionalGaussianLikelihood * @see DegenerateGaussianScore */ public class ConditionalGaussianScore implements Score { - + // The dataset. private final DataSet dataSet; - // The variables of the dataset. private final List variables; - // Likelihood function private final ConditionalGaussianLikelihood likelihood; - + // The penalty discount. private double penaltyDiscount; + // The number of categories to discretize. private int numCategoriesToDiscretize = 3; + // The structure prior. private double structurePrior = 0; /** @@ -72,7 +69,7 @@ public class ConditionalGaussianScore implements Score { * @param penaltyDiscount A multiplier on the penalty term in the BIC score. * @param discretize When a discrete variable is a child of a continuous variable, one (expensive) way to solve * the problem is to do a numerical integration. A less expensive (and often more accurate) - * way to solve the problem is to discretize the child with a certian number of discrete + * way to solve the problem is to discretize the child with a certain number of discrete * categories. if this parameter is set to True, a separate copy of all variables is * maintained that is discretized in this way, and these are substituted for the discrete * children when this sort of problem needs to be solved. This information needs to be known @@ -92,12 +89,11 @@ public ConditionalGaussianScore(DataSet dataSet, double penaltyDiscount, boolean this.likelihood = new ConditionalGaussianLikelihood(dataSet); this.likelihood.setNumCategoriesToDiscretize(this.numCategoriesToDiscretize); - this.likelihood.setPenaltyDiscount(penaltyDiscount); this.likelihood.setDiscretize(discretize); } /** - * Calculates the sample likelihood and BIC score for i given its parents in a simple SEM model. + * Calculates the sample likelihood and BIC score for index i given its parents in a simple SEM model. * * @param i The index of the child. * @param parents The indices of the parents. @@ -133,7 +129,7 @@ public double localScoreDiff(int x, int y, int[] z) { } /** - * Reurns the sample size of the data. + * Returns the sample size of the data. * * @return This size. */ @@ -176,7 +172,7 @@ public int getMaxDegree() { } /** - * Returns the penalty discount for this score, which is a multiplier on the penatly term of the BIC score. + * Returns the penalty discount for this score, which is a multiplier on the penalty term of the BIC score. * * @return This penalty discount. */ @@ -247,8 +243,6 @@ private double getStructurePrior(int[] parents) { return k * FastMath.log(p) + (n - k) * FastMath.log(1.0 - p); } } - - } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/DegenerateGaussianScore.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/DegenerateGaussianScore.java index b29e125155..5d0f853ac9 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/DegenerateGaussianScore.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/DegenerateGaussianScore.java @@ -35,30 +35,32 @@ /** - *

This implements the degenerate Gaussian BIC score for FGES. The degenerate Gaussian score - * replaces each discrete variable in the data with a list of 0/1 continuous indicator columns for each of the - * categories but one (the last one implied). This data, now all continuous, is given to the SEM BIC score and methods - * used to help determine conditional independence for the mixed continuous/discrete case from this information. The - * references is as follows:

- * - *

Andrews, B., Ramsey, J., & Cooper, G. F. (2019, July). Learning high-dimensional - * directed acyclic graphs with mixed data-types. In The 2019 ACM SIGKDD Workshop on Causal Discovery (pp. 4-21). - * PMLR.

- * - *

As for all scores in Tetrad, higher scores mean more dependence, and negative - * scores indicate independence.

+ * =This implements the degenerate Gaussian BIC score for FGES. The degenerate Gaussian score replaces each discrete + * variable in the data with a list of 0/1 continuous indicator columns for each of the categories but one (the last one + * implied). This data, now all continuous, is given to the SEM BIC score and methods used to help determine conditional + * independence for the mixed continuous/discrete case from this information. The references is as follows: + *

+ * Andrews, B., Ramsey, J., & Cooper, G. F. (2019, July). Learning high-dimensional directed acyclic graphs with + * mixed data-types. In The 2019 ACM SIGKDD Workshop on Causal Discovery (pp. 4-21). PMLR. + *

+ * As for all scores in Tetrad, higher scores mean more dependence, and negative scores indicate independence. * * @author Bryan Andrews */ public class DegenerateGaussianScore implements Score { // The mixed variables of the original dataset. private final List variables; - // The embedding map. private final Map> embedding; - + // The SEM BIC score. private final SemBicScore bic; + /** + * Constructs the score using a dataset. + * + * @param dataSet The dataset. + * @param precomputeCovariances True if covariances should be precomputed. + */ public DegenerateGaussianScore(DataSet dataSet, boolean precomputeCovariances) { if (dataSet == null) { throw new NullPointerException(); @@ -162,40 +164,84 @@ public double localScore(int i, int... parents) { return score; } + /** + * Calculates localScore(y | z, x) - localScore(z). + * + * @param x A node. + * @param y TAhe node. + * @param z A set of nodes. + * @return The score difference. + */ public double localScoreDiff(int x, int y, int[] z) { return localScore(y, append(z, x)) - localScore(y, z); } + /** + * Returns the list of variables. + * + * @return The list of variables. + */ @Override public List getVariables() { return this.variables; } + /** + * True if an edge with the given bump is an effect edge. + * + * @param bump The bump. + * @return True if so. + */ @Override public boolean isEffectEdge(double bump) { return this.bic.isEffectEdge(bump); } + /** + * Returns the sample sizE. + * + * @return The sample size. + */ @Override public int getSampleSize() { return this.bic.getSampleSize(); } + /** + * Returns the max degree. + * + * @return The max degree. + */ @Override public int getMaxDegree() { return this.bic.getMaxDegree(); } + /** + * Returns a string for this object. + * + * @return The string. + */ @Override public String toString() { NumberFormat nf = new DecimalFormat("0.00"); return "Degenerate Gaussian Score Penalty " + nf.format(this.bic.getPenaltyDiscount()); } + /** + * Returns the penalty discount. + * + * @return The penalty discount. + */ public double getPenaltyDiscount() { return this.bic.getPenaltyDiscount(); } + /** + * Sets the penalty discount. + * + * @param penaltyDiscount The penalty discount. + */ public void setPenaltyDiscount(double penaltyDiscount) { this.bic.setPenaltyDiscount(penaltyDiscount); } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/DiscreteBicScore.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/DiscreteBicScore.java index 773a34073e..9fcdc82f0c 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/DiscreteBicScore.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/DiscreteBicScore.java @@ -33,27 +33,34 @@ import static org.apache.commons.math3.util.FastMath.log; /** - * Calculates the discrete BIC score. The likelihood for this score is calculated as SUM(ln(P(X | Z) P(Z)) across all + * Calculates the discrete BIC score. The likelihood for this score is calculated as SUM(ln(P(X | Z) P(Z))) across all * cells in all conditional probability tables for the discrete model. The parameters are counted as SUM(rows * (cols - - * 1)) for all conditional probability tables in the model. Then the BIC score is calculated as 2L - ck ln N, where c is - * a multiplier on the penalty ("penalty discount"). - * - *

As for all scores in Tetrad, higher scores mean more dependence, and negative - * scores indicate independence.

+ * 1)) for all conditional probability tables in the model, where rows summing to zero are discounted, as their marginal + * probabilities cannot be calcualted. Then the BIC score is calculated as 2L - ck ln N, where c is a multiplier on the + * penalty ("penalty discount"). + *

+ * As for all scores in Tetrad, higher scores mean more dependence, and negative scores indicate independence. * * @author josephramsey */ public class DiscreteBicScore implements DiscreteScore { + // The discrete dataset. private final DataSet dataSet; + // The variables of the dataset. private final int[][] data; + // The sample size. private final int sampleSize; + // The number of categories for each variable. private final int[] numCategories; + // The variables of the dataset. private List variables; + // The penalty discount. private double penaltyDiscount = 1; - private double structurePrior = 1; + // The structure prior. + private double structurePrior = 0; /** - * Constructor. + * Constructs the score using a dataset. * * @param dataSet The discrete dataset to analyze. */ @@ -152,8 +159,6 @@ public double localScore(int node, int[] parents) { int[] myChild = this.data[node]; - int N = 0; - ROW: for (int i = 0; i < this.sampleSize; i++) { for (int p = 0; p < parents.length; p++) { @@ -171,7 +176,6 @@ public double localScore(int node, int[] parents) { n_jk[rowIndex][childValue]++; n_j[rowIndex]++; - N++; } //Finally, compute the score @@ -182,14 +186,22 @@ public double localScore(int node, int[] parents) { int cellCount = n_jk[rowIndex][childValue]; int rowCount = n_j[rowIndex]; - if (cellCount == 0) continue; + if (cellCount == 0 || rowCount == 0) continue; lik += cellCount * FastMath.log(cellCount / (double) rowCount); } } - int params = r * (c - 1); + int attestedRows = 0; - double score = 2 * lik - this.penaltyDiscount * params * FastMath.log(N) + 2 * getPriorForStructure(parents.length); + for (int rowIndex = 0; rowIndex < r; rowIndex++) { + if (n_j[rowIndex] > 0) { + attestedRows++; + } + } + + int params = attestedRows * (c - 1); + + double score = 2 * lik - this.penaltyDiscount * params * FastMath.log(sampleSize) + 2 * getPriorForStructure(parents.length); if (Double.isNaN(score) || Double.isInfinite(score)) { return Double.NaN; @@ -198,6 +210,77 @@ public double localScore(int node, int[] parents) { } } + /** + * Returns the number of parameters for a node given its parents. + * + * @param node The index of the node. + * @param parents The indices of the node's parents. + */ + public int numParameters(int node, int[] parents) { + if (!(this.variables.get(node) instanceof DiscreteVariable)) { + throw new IllegalArgumentException("Not discrete: " + this.variables.get(node)); + } + + for (int t : parents) { + if (!(this.variables.get(t) instanceof DiscreteVariable)) { + throw new IllegalArgumentException("Not discrete: " + this.variables.get(t)); + } + } + + // Numbers of categories of parents. + int[] dims = new int[parents.length]; + + for (int p = 0; p < parents.length; p++) { + dims[p] = this.numCategories[parents[p]]; + } + + // Number of parent states. + int r = 1; + + for (int p = 0; p < parents.length; p++) { + r *= dims[p]; + } + + // Conditional cell coefs of data for node given parents(node). + int[] n_j = new int[r]; + + int[] parentValues = new int[parents.length]; + + int[][] myParents = new int[parents.length][]; + for (int i = 0; i < parents.length; i++) { + myParents[i] = this.data[parents[i]]; + } + + int[] myChild = this.data[node]; + + ROW: + for (int i = 0; i < this.sampleSize; i++) { + for (int p = 0; p < parents.length; p++) { + if (myParents[p][i] == -99) continue ROW; + parentValues[p] = myParents[p][i]; + } + + int childValue = myChild[i]; + + if (childValue == -99) { + continue; + } + + int rowIndex = DiscreteBicScore.getRowIndex(dims, parentValues); + n_j[rowIndex]++; + } + + int attestedRows = 0; + + for (int rowIndex = 0; rowIndex < r; rowIndex++) { + if (n_j[rowIndex] > 0) { + attestedRows++; + } + } + + return attestedRows * (this.numCategories[node] - 1); + } + /** * Returns localScore(y | z, x) - localScore(y | z). * diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/DiscreteScore.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/DiscreteScore.java index 9199dce89e..b90544fc64 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/DiscreteScore.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/DiscreteScore.java @@ -32,19 +32,21 @@ public interface DiscreteScore extends Score { /** * Sets the structure prior. - * @param structurePrior Ibid. * + * @param structurePrior Ibid. */ void setStructurePrior(double structurePrior); /** * Sets the sample prior. + * * @param samplePrior Ibid. */ void setSamplePrior(double samplePrior); /** * Returns the dataset. + * * @return Ibid. */ DataSet getDataSet(); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/EbicScore.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/EbicScore.java index 6d618b12e1..0b97c62805 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/EbicScore.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/EbicScore.java @@ -21,7 +21,10 @@ package edu.cmu.tetrad.search.score; -import edu.cmu.tetrad.data.*; +import edu.cmu.tetrad.data.DataSet; +import edu.cmu.tetrad.data.DataTransforms; +import edu.cmu.tetrad.data.ICovarianceMatrix; +import edu.cmu.tetrad.data.SimpleDataLoader; import edu.cmu.tetrad.graph.Node; import edu.cmu.tetrad.search.Fges; import edu.cmu.tetrad.search.utils.LogUtilsSearch; @@ -36,27 +39,37 @@ import static org.apache.commons.math3.util.FastMath.log; /** - *

Implements the extended BIC (EBIC) score. The reference is here:

- * - *

Chen, J., & Chen, Z. (2008). Extended Bayesian information criteria for - * model selection with large model spaces. Biometrika, 95(3), 759-771.

- * - *

As for all scores in Tetrad, higher scores mean more dependence, and negative - * scores indicate independence.

+ * Implements the extended BIC (EBIC) score. The reference is here: + *

+ * Chen, J., & Chen, Z. (2008). Extended Bayesian information criteria for model selection with large model spaces. + * Biometrika, 95(3), 759-771. + *

+ * As for all scores in Tetrad, higher scores mean more dependence, and negative scores indicate independence. * * @author josephramsey */ public class EbicScore implements Score { + // The variables of the covariance matrix. private final List variables; + // The sample size of the covariance matrix. private final int sampleSize; + // The covariance matrix. private ICovarianceMatrix covariances; + // The number of variables. private double N; + // The dataset. private Matrix data; + // True if verbose output should be sent to out. private boolean calculateRowSubsets; + // The gamma parameter. private double gamma = 1; + // True if the pseudo-inverse should be used. + private boolean usePseudoInverse = false; /** * Constructs the score using a covariance matrix. + * + * @param covariances The covariance matrix. */ public EbicScore(ICovarianceMatrix covariances) { if (covariances == null) { @@ -97,6 +110,8 @@ public EbicScore(DataSet dataSet, boolean precomputeCovariances) { } /** + * Returns the score of the node at index y, given its parents. + * * @return localScore(y | z, x) - localScore(y | z). */ @Override @@ -105,7 +120,7 @@ public double localScoreDiff(int x, int y, int[] z) { } /** - * Returns the score of the node i given its parents. + * Returns the score of the node at index i, given its parents. * * @param i The index of the node. * @param parents The indices of the node's parents. @@ -116,7 +131,8 @@ public double localScore(int i, int... parents) throws RuntimeException { double varRy; try { - varRy = SemBicScore.getVarRy(i, parents, this.data, this.covariances, this.calculateRowSubsets); + varRy = SemBicScore.getVarRy(i, parents, this.data, this.covariances, this.calculateRowSubsets, + this.usePseudoInverse); } catch (SingularMatrixException e) { throw new RuntimeException("Singularity encountered when scoring " + LogUtilsSearch.getScoreFact(i, parents, variables)); @@ -158,7 +174,7 @@ public boolean isEffectEdge(double bump) { /** * Returns the variables for this score. * - * @return Thsi list. + * @return This list. */ @Override public List getVariables() { @@ -202,6 +218,15 @@ public void setGamma(double gamma) { this.gamma = gamma; } + /** + * Returns the gamma parameter for EBIC. + * + * @param usePseudoInverse True if the pseudo-inverse should be used. + */ + public void setUsePseudoInverse(boolean usePseudoInverse) { + this.usePseudoInverse = usePseudoInverse; + } + private void setCovariances(ICovarianceMatrix covariances) { this.covariances = covariances; this.N = covariances.getSampleSize(); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/GicScores.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/GicScores.java index 7e47feae92..e81c7c61d7 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/GicScores.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/GicScores.java @@ -35,14 +35,12 @@ import static org.apache.commons.math3.util.FastMath.*; /** - *

Implements scores motivated by the Generalized Information Criterion (GIC) - * approach as given in Kim et al. (2012).

- * - *

Kim, Y., Kwon, S., & Choi, H. (2012). Consistent model selection criteria on - * high dimensions. The Journal of Machine Learning Research, 13(1), 1037-1057.

- * - *

As for all scores in Tetrad, higher scores mean more dependence, and negative - * scores indicate independence.

+ * Implements scores motivated by the Generalized Information Criterion (GIC) approach as given in Kim et al. (2012). + *

+ * Kim, Y., Kwon, S., & Choi, H. (2012). Consistent model selection criteria on high dimensions. The Journal of + * Machine Learning Research, 13(1), 1037-1057. + *

+ * As for all scores in Tetrad, higher scores mean more dependence, and negative scores indicate independence. * * @author josephramsey */ @@ -68,11 +66,15 @@ public class GicScores implements Score { private boolean calculateRowSubsets = false; // private boolean calculateSquareEuclideanNorms = false; private double penaltyDiscount = 1; + // True if the pseudo-inverse should be used. + private boolean usePseudoInverse = false; /** * Constructs the score using a covariance matrix. + * + * @param covariances The covariance matrix. */ - public GicScores(ICovarianceMatrix covariances/*, double correlationThreshold*/) { + public GicScores(ICovarianceMatrix covariances) { if (covariances == null) { throw new NullPointerException(); } @@ -85,6 +87,9 @@ public GicScores(ICovarianceMatrix covariances/*, double correlationThreshold*/) /** * Constructs the score using a covariance matrix. + * + * @param dataSet The continuous dataset to analyze. + * @param precomputeCovariances Whether the covariances should be precomputed or computed on the fly. True if */ public GicScores(DataSet dataSet, boolean precomputeCovariances) { if (dataSet == null) { @@ -109,12 +114,26 @@ public GicScores(DataSet dataSet, boolean precomputeCovariances) { calculateRowSubsets = true; } + /** + * Calculates the sample likelihood and BIC score for index i given its parents in a simple SEM model. + * + * @param x A node. + * @param y TAhe node. + * @param z A set of nodes. + * @return The score difference. + */ @Override public double localScoreDiff(int x, int y, int[] z) { return localScore(y, append(z, x)) - localScore(y, z); } - + /** + * Calculates the sample likelihood and BIC score for index i given its parents in a simple SEM model. + * + * @param i The node. + * @param parents The parents. + * @return The score. + */ public double localScore(int i, int... parents) { double sn = 12; @@ -128,7 +147,7 @@ public double localScore(int i, int... parents) { double varry; try { - varry = SemBicScore.getVarRy(i, parents, data, covariances, calculateRowSubsets); + varry = SemBicScore.getVarRy(i, parents, data, covariances, calculateRowSubsets, this.usePseudoInverse); } catch (SingularMatrixException e) { throw new RuntimeException("Singularity encountered when scoring " + LogUtilsSearch.getScoreFact(i, parents, variables)); @@ -164,96 +183,96 @@ public double localScore(int i, int... parents) { } else if (ruleType == RuleType.GIC6) { // Following Kim, Y., Kwon, S., & Choi, H. (2012). Consistent model selection criteria on high dimensions. - // The Journal of Machine Learning Resjearch, 13(1), 1037-1057. + // The Journal of Machine Learning Research, 13(1), 1037-1057. lambda = log(n) * log(pn); } else { throw new IllegalStateException("That lambda rule is not configured: " + ruleType); } -// double c = penaltyDiscount; - - // private double penaltyDiscount; - // private double correlationThreshold = 1.0; - boolean takeLog = true; - if (takeLog) { - return -(n / 2.0) * log(varry) - lambda * getPenaltyDiscount() * k; - } else { - // The true error variance - double trueErrorVariance = 1.0; - return -(n / 2.0) * (varry) - lambda * getPenaltyDiscount() * k * trueErrorVariance; - } - + return -(n / 2.0) * log(varry) - lambda * getPenaltyDiscount() * k; } /** - * Specialized scoring method for a single parent. Used to speed up the effect edges search. + * Returns the sample size. + * + * @return This size. */ - - -// public double getTrueErrorVariance() { -// return trueErrorVariance; -// } public ICovarianceMatrix getCovariances() { return covariances; } + /** + * Sets the covariance matrix. + * + * @param covariances The covariance matrix. + */ private void setCovariances(ICovarianceMatrix covariances) { -// CorrelationMatrix correlations = new CorrelationMatrix(covariances); this.covariances = covariances; -// this.covariances = covariances; - -// boolean exists = false; - -// for (int i = 0; i < correlations.getSize(); i++) { -// for (int j = 0; j < correlations.getSize(); j++) { -// if (i == j) continue; -// double r = correlations.getValue(i, j); -// if (abs(r) > correlationThreshold) { -// System.out.println("Absolute correlation too high: " + r); -// exists = true; -// } -// } -// } - -// if (exists) { -// throw new IllegalArgumentException("Some correlations are too high (> " + correlationThreshold -// + ") in absolute value."); -// } - - this.N = covariances.getSampleSize(); } + /** + * Returns the sample size. + * + * @return This size. + */ public int getSampleSize() { return sampleSize; } + /** + * Returns true if an edge with this bump is an effect edge. + * + * @param bump The bump. + * @return True if so. + */ @Override public boolean isEffectEdge(double bump) { return bump > 0; } -// public void setTrueErrorVariance(double trueErrorVariance) { -// this.trueErrorVariance = trueErrorVariance; -// } - + /** + * Returns the dataset. + * + * @return The dataset. + */ public DataSet getDataSet() { return dataSet; } + /** + * Returns true if verbose output should be sent to out. + * + * @return True if verbose output should be sent to out. + */ public boolean isVerbose() { return verbose; } + /** + * Sets whether verbose output should be sent to out. + * + * @param verbose True if verbose output should be sent to out. + */ public void setVerbose(boolean verbose) { this.verbose = verbose; } + /** + * Returns the variables of the dataset. + * + * @return These variables as list. + */ @Override public List getVariables() { return variables; } + /** + * Sets the variables of the dataset. + * + * @param variables The variables of the dataset. + */ public void setVariables(List variables) { if (covariances != null) { covariances.setVariables(variables); @@ -262,11 +281,23 @@ public void setVariables(List variables) { this.variables = variables; } + /** + * Returns the max degree of the graph for some algorithms. + * + * @return This max degree. + */ @Override public int getMaxDegree() { return (int) FastMath.ceil(log(sampleSize)); } + /** + * Returns a judgment of whether the variable in z determine y exactly. + * + * @param z The set of nodes. + * @param y The node. + * @return This judgment + */ @Override public boolean determines(List z, Node y) { int i = variables.indexOf(y); @@ -282,50 +313,64 @@ public boolean determines(List z, Node y) { return Double.isNaN(v); } -// public RuleType getRuleType() { -// return ruleType; -// } - + /** + * Sets the rule type. + * + * @param ruleType The rule type. + * @see RuleType + */ public void setRuleType(RuleType ruleType) { this.ruleType = ruleType; } -// public void setPenaltyDiscount(double penaltyDiscount) { -// this.penaltyDiscount = penaltyDiscount; -// } - -// public void setCorrelationThreshold(double correlationThreshold) { -// this.correlationThreshold = correlationThreshold; -// } - -// public void setTakeLog(boolean takeLog) { -// this.takeLog = takeLog; -// } - -// public void setCalculateSquareEuclideanNorms(boolean calculateSquareEuclideanNorms) { -// this.calculateSquareEuclideanNorms = calculateSquareEuclideanNorms; -// } - + /** + * Sets the lambda parameter. + * + * @param lambda The lambda parameter. + */ public void setLambda(double lambda) { this.lambda = lambda; } + /** + * Returns the penalty discount. + * + * @return The penalty discount. + */ public double getPenaltyDiscount() { return penaltyDiscount; } + /** + * Sets the penalty discount. + * + * @param penaltyDiscount The penalty discount. + */ public void setPenaltyDiscount(double penaltyDiscount) { this.penaltyDiscount = penaltyDiscount; } + /** + * Returns a string for this object. + * + * @return A string for this object. + */ public String toString() { return "Generalized Information Criterion Score"; } + /** + * Sets whether to use the pseudo-inverse when calculating the score. + * + * @param usePseudoInverse True if so. + */ + public void setUsePseudoInverse(boolean usePseudoInverse) { + this.usePseudoInverse = usePseudoInverse; + } /** * Gives the options for the rules to use for calculating the scores. The "GIC" rules, and RICc, are the rules - * proposed in the Kim et al. paper for generalized information criteria.' + * proposed in the Kim et al. paper for generalized information criteria. * * @see GicScores */ diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/GraphScore.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/GraphScore.java index 486cc3dffd..31b802f0af 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/GraphScore.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/GraphScore.java @@ -21,8 +21,6 @@ package edu.cmu.tetrad.search.score; -import edu.cmu.tetrad.data.DataModel; -import edu.cmu.tetrad.data.DataSet; import edu.cmu.tetrad.data.IndependenceFacts; import edu.cmu.tetrad.graph.EdgeListGraph; import edu.cmu.tetrad.graph.Graph; @@ -37,24 +35,22 @@ import java.util.Set; /** - *

Implements a pscudo-"score" that implmenets implements Chickering and Meek's - * (2002) locally consistent score criterion. This is not a true score; rather, a -1 is returned in case mseparation - * holds and a 1 in case mseparation does not hold. This is only meant to be used in the context of FGES, and allows the - * search to follow its path prescribed by the locally consistent scoring criterion. For a reference to the latter, - * pleasee this article:

- * - *

Chickering (2002) "Optimal structure identification with greedy search" - * Journal of Machine Learning Research.

- * - *

For further discussion of using m-separation in the GES search, see:

- * - *

Nandy, P., Hauser, A., & Maathuis, M. H. (2018). High-dimensional consistency - * in score-based and hybrid structure learning. The Annals of Statistics, 46(6A), 3151-3183.

- * - *

For more discussion please see:

- * - *

Shen, X., Zhu, S., Zhang, J., Hu, S., & Chen, Z. (2022, August). Reframed GES - * with a neural conditional dependence measure. In Uncertainty in Artificial Intelligence (pp. 1782-1791). PMLR.

+ * Implements a pscudo-"score" that implmenets implements Chickering and Meek's (2002) locally consistent score + * criterion. This is not a true score; rather, a -1 is returned in case mseparation holds and a 1 in case mseparation + * does not hold. This is only meant to be used in the context of FGES, and allows the search to follow its path + * prescribed by the locally consistent scoring criterion. For a reference to the latter, pleasee this article: + *

+ * Chickering (2002) "Optimal structure identification with greedy search" Journal of Machine Learning Research. + *

+ * For further discussion of using m-separation in the GES search, see: + *

+ * Nandy, P., Hauser, A., & Maathuis, M. H. (2018). High-dimensional consistency in score-based and hybrid structure + * learning. The Annals of Statistics, 46(6A), 3151-3183. + *

+ * For more discussion please see: + *

+ * Shen, X., Zhu, S., Zhang, J., Hu, S., & Chen, Z. (2022, August). Reframed GES with a neural conditional + * dependence measure. In Uncertainty in Artificial Intelligence (pp. 1782-1791). PMLR. * * @author josephramsey * @see Fges @@ -63,15 +59,13 @@ public class GraphScore implements Score { // The variables of the covariance matrix. private final List variables; + // The DAG, if supplied. private Graph dag; + // The independence facts, if supplied. private IndependenceFacts facts; - // True if verbose output should be sent to out. - private boolean verbose = false; - private Node n = null; - private List prefix = null; /** - * Constructor + * Constructs a GraphScore from a DAG. * * @param dag A directed acyclic graph. */ @@ -82,7 +76,7 @@ public GraphScore(Graph dag) { } /** - * Constructor. + * Constructs a GraphScore from a list of independence facts. * * @param facts A list known independence facts; a lookup will be donw from these facts. * @see IndependenceFacts @@ -99,27 +93,12 @@ public GraphScore(IndependenceFacts facts) { * @return this score. */ public double localScore(int y, int[] z) { - return getPearlParentsTest().size(); - } - - private Set getPearlParentsTest() { - Set mb = new HashSet<>(); - - for (Node z0 : prefix) { - Set cond = new HashSet<>(prefix); - cond.remove(z0); - - if (dag.paths().isMConnectedTo(n, z0, cond)) { - mb.add(z0); - } - } - - return mb; + throw new UnsupportedOperationException(); } - /** - * Returns a "score difference", which amounts to a conditional local scoring criterion results + * Returns a "score difference", which amounts to a conditional local scoring criterion results. Only difference + * methods is implemented, since the other methods don't make sense here. * * @return The "difference". */ @@ -129,9 +108,9 @@ public double localScoreDiff(int x, int y, int[] z) { } /** - * The "unconditional difference." + * The "unconditional difference." Only difference methods is implemented, since the other methods don't make sense here. * - * @return This. + * @return The "difference". */ @Override public double localScoreDiff(int x, int y) { @@ -153,7 +132,7 @@ public double localScore(int i) { } /** - * Returns a judgment for FGES as to whether a score with the bump is for an effect edge. + * Returns a judgment for FGES whether a score with the bump is for an effect edge. * * @param bump The bump * @return True, if so. @@ -164,13 +143,6 @@ public boolean isEffectEdge(double bump) { return bump > 0; } - /** - * @throws UnsupportedOperationException Since the method doesn't make sense here. - */ - public DataSet getDataSet() { - throw new UnsupportedOperationException(); - } - /** * Returns the list of variables. * @@ -192,14 +164,7 @@ public int getMaxDegree() { } /** - * @throws UnsupportedOperationException Since this "score" does not use data. - */ - public DataModel getData() { - throw new UnsupportedOperationException("This score does not use data."); - } - - /** - * @throws UnsupportedOperationException Since this score does not use data. + * @throws UnsupportedOperationException Since the method doesn't make sense here. */ public int getSampleSize() { throw new UnsupportedOperationException("This score does not use data, so no sample size is available."); @@ -242,18 +207,6 @@ private boolean isMSeparatedFrom(Node x, Node y, Set z) { throw new IllegalArgumentException("Expecting either a DAG or an IndependenceFacts object."); } - private boolean isMConnectedTo(Node x, Node y, Set z) { - return !isMSeparatedFrom(x, y, z); - } - - private List getVariableList(int[] indices) { - List variables = new ArrayList<>(); - for (int i : indices) { - variables.add(this.variables.get(i)); - } - return variables; - } - private Set getVariableSet(int[] indices) { Set variables = new HashSet<>(); for (int i : indices) { diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/ImagesScore.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/ImagesScore.java index 5d3a73a2fd..fc15b50c13 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/ImagesScore.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/ImagesScore.java @@ -29,18 +29,16 @@ import java.util.List; /** - *

Implements a score to average results over multiple scores. This is - * used for the IMaGES algorithm. The idea is that one pick and algorithm that takes (only) a score as input, such as - * FGES or GRaSP or BOSS, and then constructs an ImagesScore (which class) with a list of datasets as input, using same - * object-identical variables, and feeds this Images score to this algorithm through the contructor. One then runs the - * algorithm to get an estimate of the structure.

- * - *

Importantly, only the variables from the first score will be returned - * from the getVariables method, so it is up to the user to ensure that all of the scores share the same - * (object-identical) variables.

- * - *

As for all scores in Tetrad, higher scores mean more dependence, and - * negative scores indicate independence.

+ * Implements a score to average results over multiple scores. This is used for the IMaGES algorithm. The idea is that + * one pick and algorithm that takes (only) a score as input, such as FGES or GRaSP or BOSS, and then constructs an + * ImagesScore (which class) with a list of datasets as input, using same object-identical variables, and feeds this + * Images score to this algorithm through the constructor. One then runs the algorithm to get an estimate of the + * structure. + *

+ * Importantly, only the variables from the first score will be returned from the getVariables method, so it is up to + * the user to ensure that all the scores share the same (object-identical) variables. + *

+ * As for all scores in Tetrad, higher scores mean more dependence, and negative scores indicate independence. * * @author josephramsey * @see Fges @@ -51,7 +49,6 @@ public class ImagesScore implements Score { // The covariance matrix. private final List scores; - // The variables of the covariance matrix. private final List variables; @@ -124,6 +121,16 @@ public double localScore(int i, int[] parents) { } } + /** + * Returns the (aggregate) local score for a variable given its parents, which is obtained by averaging the local + * such scores obtained from each individual score provided in the constructor, excluding scores that are returned + * as undefined (which are left out of the average). + * + * @param i The variable whose score is needed. + * @param parents The indices of the parents. + * @param index The index of the score to use. + * @return This score. + */ public double localScore(int i, int[] parents, int index) { return localScoreOneDataSet(i, parents, index); } @@ -176,6 +183,12 @@ public double localScore(int i) { return sum / count; } + /** + * Returns a judgment for FGES whether a score with the bump is for an effect edge. + * + * @param bump The bump. + * @return True if so. + */ @Override public boolean isEffectEdge(double bump) { return scores.get(0).isEffectEdge(bump); @@ -214,6 +227,8 @@ public int getMaxDegree() { /** * Returns the 'determines' judgment from the first score. * + * @param z The set of variables. + * @param y The variable. * @return This judgment, true if the 'determine' relations holds. */ @Override diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/IndTestScore.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/IndTestScore.java index b5a300cfc6..4024a4d0f2 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/IndTestScore.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/IndTestScore.java @@ -35,25 +35,24 @@ * Gives a method of interpreting a test as a score. Various independence tests will calculate p-values; they simply * report alpha - p as a score, which will be higher for greater dependence. This class wraps such an independence test * and returns the score reported by that test. - * - *

As for all scores in Tetrad, higher scores mean more dependence, and negative - * scores indicate independence.

+ *

+ * As for all scores in Tetrad, higher scores mean more dependence, and negative scores indicate independence. * * @author josephramsey * @see IndependenceTest */ public class IndTestScore implements Score { - + // The independence test. private final IndependenceTest test; - // The variables of the covariance matrix. private final List variables; - // True if verbose output should be sent to out. private boolean verbose; /** * Constructs the score using a covariance matrix. + * + * @param test The independence test. */ public IndTestScore(IndependenceTest test) { this.variables = new ArrayList<>(); @@ -69,20 +68,24 @@ public IndTestScore(IndependenceTest test) { /** * Calculates the sample likelihood and BIC score for i, given its parents in a simple SEM model + * + * @param i The index of the variable. + * @param parents The indices of the parents of i. */ public double localScore(int i, int[] parents) { throw new UnsupportedOperationException(); } - private List getVariableList(int[] indices) { - List variables = new ArrayList<>(); - for (int i : indices) { - variables.add(this.variables.get(i)); - } - return variables; - } - + /** + * Returns a "score difference", which amounts to a conditional local scoring criterion results. Only difference + * methods is implemented, since the other methods don't make sense here. + * + * @param x A node. + * @param y TAhe node. + * @param z A set of nodes. + * @return The "difference". + */ @Override public double localScoreDiff(int x, int y, int[] z) { IndependenceResult result = this.test.checkIndependence(this.variables.get(x), this.variables.get(y), new HashSet<>(getVariableList(z))); @@ -90,53 +93,99 @@ public double localScoreDiff(int x, int y, int[] z) { } /** - * Specialized scoring method for a single parent. Used to speed up the effect edges search. + * @throws UnsupportedOperationException if called. */ public double localScore(int i, int parent) { throw new UnsupportedOperationException(); } + /** + * @throws UnsupportedOperationException if called. + */ public double localScore(int i) { throw new UnsupportedOperationException(); } + /** + * Returns true if the edge with the given bump is an effect edge. + * + * @param bump The bump. + * @return True if so. + */ @Override public boolean isEffectEdge(double bump) { return true; } + /** + * Returns the data set. + * @return The data set. + */ public DataSet getDataSet() { throw new UnsupportedOperationException(); } + /** + * Returns true if verbose output should be sent to out. + * @return True if verbose output should be sent to out. + */ public boolean isVerbose() { return this.verbose; } + /** + * Sets whether verbose output should be sent to out. + * @param verbose True if verbose output should be sent to out. + */ public void setVerbose(boolean verbose) { this.verbose = verbose; } + /** + * Returns the list of variables. + * @return The list of variables. + */ @Override public List getVariables() { return this.variables; } + /** + * Returns the sample size. + * @return The sample size. + */ public int getSampleSize() { return 0; } + /** + * Returns the maximum degree, which is set to 1000. + * @return 1000. + */ @Override public int getMaxDegree() { return 1000; } + /** + * Returns the 'determines' judgment from the first score. + * @param z The set of nodes. + * @param y The node. + * @return This judgment, true if the 'determine' relations holds. + */ @Override public boolean determines(List z, Node y) { return false; } + private List getVariableList(int[] indices) { + List variables = new ArrayList<>(); + for (int i : indices) { + variables.add(this.variables.get(i)); + } + return variables; + } } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/MvpLikelihood.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/MvpLikelihood.java index c03360e8fb..731681d709 100755 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/MvpLikelihood.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/MvpLikelihood.java @@ -38,17 +38,17 @@ /** - *

Calculates Mixed Variables Polynomial likelihood. The reference is here:

- * - *

Andrews, B., Ramsey, J., & Cooper, G. F. (2018). Scoring Bayesian networks of - * mixed variables. International journal of data science and analytics, 6, 3-18.

+ * Calculates Mixed Variables Polynomial likelihood. The reference is here: + *

+ * Andrews, B., Ramsey, J., & Cooper, G. F. (2018). Scoring Bayesian networks of mixed variables. International + * journal of data science and analytics, 6, 3-18. * * @author Bryan Andrews */ public class MvpLikelihood { + // The dataset. private final DataSet dataSet; - // The variables of the dataset. private final List variables; // Indices of variables. @@ -68,6 +68,21 @@ public class MvpLikelihood { // The variables of the discrete dataset. private List discreteVariables; + /** + * Constructs the score using a data set. + * + * @param dataSet A dataset with a mixture of continuous and discrete variables. It may be all continuous or + * @param structurePrior The structure prior. + * @param fDegree F-degree + * @param discretize When a discrete variable is a child of a continuous variable, one (expensive) way to solve + * the problem is to do a numerical integration. A less expensive (and often more accurate) + * way to solve the problem is to discretize the child with a certain number of discrete + * categories. if this parameter is set to True, a separate copy of all variables is + * maintained that is discretized in this way, and these are substituted for the discrete + * children when this sort of problem needs to be solved. This information needs to be known + * in the constructor since one needs to know right away whether ot create this separate + * discretized version of the continuous columns. + */ public MvpLikelihood(DataSet dataSet, double structurePrior, int fDegree, boolean discretize) { if (dataSet == null) { @@ -123,8 +138,14 @@ public MvpLikelihood(DataSet dataSet, double structurePrior, int fDegree, boolea } + /** + * Returns the score of the node at index i, given its parents. + * + * @param child_index The index of the child. + * @param parents The indices of the parents. + * @return The score. + */ public double getLik(int child_index, int[] parents) { - double lik = 0; Node c = this.variables.get(child_index); List continuous_parents = new ArrayList<>(); @@ -154,11 +175,9 @@ public double getLik(int child_index, int[] parents) { for (int j = 0; j < p; j++) continuousCols[j] = this.nodesHash.get(continuous_parents.get(j)); for (List cell : cells) { -// for (int[] cell : cells) { int r = cell.size(); -// int r = cell.length; - if (r > 1) { + if (r > 1) { double[] mean = new double[p]; double[] var = new double[p]; for (int i = 0; i < p; i++) { @@ -194,7 +213,6 @@ public double getLik(int child_index, int[] parents) { Vector target = new Vector(r); for (int i = 0; i < r; i++) { target.set(i, this.continuousData[child_index][cell.get(i)]); -// target.set(i, continuousData[child_index][cell[i]]); } lik += multipleRegression(target, subset); } else { @@ -211,101 +229,13 @@ public double getLik(int child_index, int[] parents) { return lik; } - - private double multipleRegression(Vector Y, Matrix X) { - - int n = X.getNumRows(); - Vector r; - if (X.getNumColumns() >= n) { - Vector ones = new Vector(n); - for (int i = 0; i < n; i++) ones.set(i, 1); - r = ones.scalarMult(ones.dotProduct(Y) / (double) n).minus(Y); - } else { - try { - Matrix Xt = X.transpose(); - Matrix XtX = Xt.times(X); - r = X.times(XtX.inverse().times(Xt.times(Y))).minus(Y); - } catch (Exception e) { - Vector ones = new Vector(n); - for (int i = 0; i < n; i++) ones.set(i, 1); - r = ones.scalarMult(ones.dotProduct(Y) / (double) n).minus(Y); - } - } - - double sigma2 = r.dotProduct(r) / n; - double lik; - - if (sigma2 < 0) { - Vector ones = new Vector(n); - for (int i = 0; i < n; i++) ones.set(i, 1); - r = ones.scalarMult(ones.dotProduct(Y) / (double) FastMath.max(n, 2)).minus(Y); - sigma2 = r.dotProduct(r) / n; - lik = -(n / 2.) * (FastMath.log(2 * FastMath.PI) + FastMath.log(sigma2) + 1); - } else if (sigma2 == 0) { - lik = 0; - } else { - lik = -(n / 2.) * (FastMath.log(2 * FastMath.PI) + FastMath.log(sigma2) + 1); - } - - - if (Double.isInfinite(lik) || Double.isNaN(lik)) { - System.out.println(lik); - } - - return lik; - } - - private double approxMultinomialRegression(Matrix Y, Matrix X) { - - int n = X.getNumRows(); - int d = Y.getNumColumns(); - double lik = 0.0; - Matrix P; - - - if (d >= n || X.getNumColumns() >= n) { - Matrix ones = new Matrix(n, 1); - for (int i = 0; i < n; i++) ones.set(i, 0, 1); - P = ones.times(ones.transpose().times(Y).scalarMult(1 / (double) n)); - } else { - try { - Matrix Xt = X.transpose(); - Matrix XtX = Xt.times(X); - P = X.times(XtX.inverse().times(Xt.times(Y))); - } catch (Exception e) { - Matrix ones = new Matrix(n, 1); - for (int i = 0; i < n; i++) ones.set(i, 0, 1); - P = ones.times(ones.transpose().times(Y).scalarMult(1 / (double) n)); - } - - for (int i = 0; i < n; i++) { - double min = 1; - double center = 1 / (double) d; - double bound = 1 / (double) n; - for (int j = 0; j < d; j++) { - min = FastMath.min(min, P.get(i, j)); - } - if (X.getNumColumns() > 1 && min < bound) { - min = (bound - center) / (min - center); - for (int j = 0; j < d; j++) { - P.set(i, j, min * P.get(i, j) + center * (1 - min)); - } - } - } - } - - for (int i = 0; i < n; i++) { - lik += FastMath.log(P.getRow(i).dotProduct(Y.getRow(i))); - } - - if (Double.isInfinite(lik) || Double.isNaN(lik)) { - System.out.println(lik); - } - - return lik; - } - - + /** + * Returns the score of the node at index i, given its parents. + * + * @param child_index The index of the child. + * @param parents The indices of the parents. + * @return The score. + */ public double getDoF(int child_index, int[] parents) { double dof = 0; @@ -351,8 +281,13 @@ public double getDoF(int child_index, int[] parents) { return dof; } + /** + * Returns the structure prior. + * + * @param k The number of edges. + * @return The structure prior. + */ public double getStructurePrior(int k) { - if (this.structurePrior < 0) { return getEBICprior(); } @@ -375,6 +310,50 @@ public double getEBICprior() { } + private double multipleRegression(Vector Y, Matrix X) { + + int n = X.getNumRows(); + Vector r; + if (X.getNumColumns() >= n) { + Vector ones = new Vector(n); + for (int i = 0; i < n; i++) ones.set(i, 1); + r = ones.scalarMult(ones.dotProduct(Y) / (double) n).minus(Y); + } else { + try { + Matrix Xt = X.transpose(); + Matrix XtX = Xt.times(X); + r = X.times(XtX.inverse().times(Xt.times(Y))).minus(Y); + } catch (Exception e) { + Vector ones = new Vector(n); + for (int i = 0; i < n; i++) ones.set(i, 1); + r = ones.scalarMult(ones.dotProduct(Y) / (double) n).minus(Y); + } + } + + double sigma2 = r.dotProduct(r) / n; + double lik; + + if (sigma2 < 0) { + Vector ones = new Vector(n); + for (int i = 0; i < n; i++) ones.set(i, 1); + r = ones.scalarMult(ones.dotProduct(Y) / (double) FastMath.max(n, 2)).minus(Y); + sigma2 = r.dotProduct(r) / n; + lik = -(n / 2.) * (FastMath.log(2 * FastMath.PI) + FastMath.log(sigma2) + 1); + } else if (sigma2 == 0) { + lik = 0; + } else { + lik = -(n / 2.) * (FastMath.log(2 * FastMath.PI) + FastMath.log(sigma2) + 1); + } + + + if (Double.isInfinite(lik) || Double.isNaN(lik)) { + System.out.println(lik); + } + + return lik; + } + + private DataSet useErsatzVariables() { List nodes = new ArrayList<>(); // Number of categories to use to discretize continuous mixedVariables. @@ -417,4 +396,53 @@ private DataSet useErsatzVariables() { return replaced; } + private double approxMultinomialRegression(Matrix Y, Matrix X) { + + int n = X.getNumRows(); + int d = Y.getNumColumns(); + double lik = 0.0; + Matrix P; + + + if (d >= n || X.getNumColumns() >= n) { + Matrix ones = new Matrix(n, 1); + for (int i = 0; i < n; i++) ones.set(i, 0, 1); + P = ones.times(ones.transpose().times(Y).scalarMult(1 / (double) n)); + } else { + try { + Matrix Xt = X.transpose(); + Matrix XtX = Xt.times(X); + P = X.times(XtX.inverse().times(Xt.times(Y))); + } catch (Exception e) { + Matrix ones = new Matrix(n, 1); + for (int i = 0; i < n; i++) ones.set(i, 0, 1); + P = ones.times(ones.transpose().times(Y).scalarMult(1 / (double) n)); + } + + for (int i = 0; i < n; i++) { + double min = 1; + double center = 1 / (double) d; + double bound = 1 / (double) n; + for (int j = 0; j < d; j++) { + min = FastMath.min(min, P.get(i, j)); + } + if (X.getNumColumns() > 1 && min < bound) { + min = (bound - center) / (min - center); + for (int j = 0; j < d; j++) { + P.set(i, j, min * P.get(i, j) + center * (1 - min)); + } + } + } + } + + for (int i = 0; i < n; i++) { + lik += FastMath.log(P.getRow(i).dotProduct(Y.getRow(i))); + } + + if (Double.isInfinite(lik) || Double.isNaN(lik)) { + System.out.println(lik); + } + + return lik; + } } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/MvpScore.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/MvpScore.java index 49c406a812..cbbb83f5d2 100755 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/MvpScore.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/MvpScore.java @@ -28,23 +28,20 @@ import java.util.List; /** - *

Implements a mixed variable polynomial BIC score. The reference is here:

- * - *

Andrews, B., Ramsey, J., & Cooper, G. F. (2018). Scoring Bayesian networks of - * mixed variables. International journal of data science and analytics, 6, 3-18.

+ * Implements a mixed variable polynomial BIC score. The reference is here: + *

+ * Andrews, B., Ramsey, J., & Cooper, G. F. (2018). Scoring Bayesian networks of mixed variables. International + * journal of data science and analytics, 6, 3-18. * * @author Bryan Andrews */ public class MvpScore implements Score { - + // The mixed variables of the original dataset. private final DataSet dataSet; - // The variables of the continuousData set. private final List variables; - // Likelihood function private final MvpLikelihood likelihood; - // Log number of instances private final double logn; @@ -69,6 +66,10 @@ public MvpScore(DataSet dataSet, double structurePrior, int fDegree, boolean dis /** * The local score of the child given its parents. + * + * @param i The child. + * @param parents The parents. + * @return The local score. */ public double localScore(int i, int... parents) { @@ -90,7 +91,12 @@ public double localScore(int i, int... parents) { } /** - * localScore(y | z, x) - localScore(y | z). + * Returns localScore(y | z, x) - localScore(y | z). + * + * @param x A node. + * @param y The node. + * @param z A set of nodes. + * @return The score difference. */ public double localScoreDiff(int x, int y, int[] z) { return localScore(y, append(z, x)) - localScore(y, z); @@ -117,21 +123,36 @@ public boolean isEffectEdge(double bump) { return bump > 0; } + /** + * Returns the list of variables. + * + * @return This list. + */ @Override public List getVariables() { return this.variables; } + /** + * Returns an estimate of the maximum degree of the graph for some algorithms. + * + * @return This maximum. + */ @Override public int getMaxDegree() { return (int) FastMath.ceil(FastMath.log(this.dataSet.getNumRows())); } + /** + * Returns a judgment of whether the variable in z determine y exactly. + * @param z The set of nodes. + * @param y The node. + * @return This judgment. + */ @Override public boolean determines(List z, Node y) { return false; } - } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/PoissonPriorScore.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/PoissonPriorScore.java index 99617ec475..5055ea0366 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/PoissonPriorScore.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/PoissonPriorScore.java @@ -33,16 +33,15 @@ import static org.apache.commons.math3.util.FastMath.*; /** - *

Implements Poisson prior score, a novel (unpubished) score that replaces the - * penalty term in BIC by the log of the Poisson distribution. The Poisson distribution has a lambda parameter, which is - * made a parameter of this score and acts like a structure prior for the score.

- * - *

Here is the Wikipedia page for the Poisson distribution, for reference:

- * - *

https://en.wikipedia.org/wiki/Poisson_distribution

- * - *

As for all scores in Tetrad, higher scores mean more dependence, and negative - * scores indicate independence.

+ * Implements Poisson prior score, a novel (unpubished) score that replaces the penalty term in BIC by the log of the + * Poisson distribution. The Poisson distribution has a lambda parameter, which is made a parameter of this score and + * acts like a structure prior for the score. + *

+ * Here is the Wikipedia page for the Poisson distribution, for reference: + *

+ * https://en.wikipedia.org/wiki/Poisson_distribution + *

+ * As for all scores in Tetrad, higher scores mean more dependence, and negative scores indicate independence. * * @author bryanandrews * @author josephramsey @@ -56,22 +55,21 @@ public class PoissonPriorScore implements Score { private DataSet dataSet; // The covariance matrix. private ICovarianceMatrix covariances; - // True if verbose output should be sent to out. - private boolean verbose; - // Sample size or equivalent sample size. private double N; - // The data, if it is set. private Matrix data; - // True if row subsets should be calculated. private boolean calculateRowSubsets; - + // The lambda parameter. private double lambda = 3.; + // True if the pseudo-inverse should be used. + private boolean usePseudoInverse = false; /** * Constructs the score using a covariance matrix. + * + * @param covariances The covariance matrix. */ public PoissonPriorScore(ICovarianceMatrix covariances) { if (covariances == null) { @@ -85,6 +83,9 @@ public PoissonPriorScore(ICovarianceMatrix covariances) { /** * Constructs the score using a covariance matrix. + * + * @param dataSet The dataset. + * @param precomputeCovariances Whether the covariances should be precomputed or computed on the fly. True if */ public PoissonPriorScore(DataSet dataSet, boolean precomputeCovariances) { @@ -109,16 +110,22 @@ public PoissonPriorScore(DataSet dataSet, boolean precomputeCovariances) { } - private static double getP(int pn, int m0, double lambda) { - return 2 - pow(1 + (exp(-(lambda - 1) / 2.)) * sqrt(lambda), (double) pn - m0); - } - + /** + * Returns the score difference localScore(y | z, x) - localScore(y | z). + * + * @param x A node. + * @param y TAhe node. + * @param z A set of nodes. + * @return The score difference. + */ @Override public double localScoreDiff(int x, int y, int[] z) { return localScore(y, append(z, x)) - localScore(y, z); } /** + * Returns the score of the node at index i, given its parents. + * * @param i The index of the node. * @param parents The indices of the node's parents. * @return The score, or NaN if the score cannot be calculated. @@ -129,7 +136,8 @@ public double localScore(int i, int... parents) throws RuntimeException { double varRy; try { - varRy = SemBicScore.getVarRy(i, parents, this.data, this.covariances, this.calculateRowSubsets); + varRy = SemBicScore.getVarRy(i, parents, this.data, this.covariances, this.calculateRowSubsets, + this.usePseudoInverse); } catch (SingularMatrixException e) { throw new RuntimeException("Singularity encountered when scoring " + LogUtilsSearch.getScoreFact(i, parents, variables)); @@ -147,6 +155,11 @@ public double localScore(int i, int... parents) throws RuntimeException { } } + /** + * Returns the covariance matrix. + * + * @return The covariance matrix. + */ public ICovarianceMatrix getCovariances() { return this.covariances; } @@ -178,29 +191,53 @@ private void setCovariances(ICovarianceMatrix covariances) { this.N = covariances.getSampleSize(); } + /** + * Returns the sample size. + * + * @return This size. + */ public int getSampleSize() { return this.sampleSize; } + /** + * Returns true if the edge with the given bump is an effect edge. + * + * @param bump The bump. + * @return True if so. + */ @Override public boolean isEffectEdge(double bump) { return bump > 0; } - public void setVerbose(boolean verbose) { - this.verbose = verbose; - } - + /** + * Returns the variables. + * + * @return This list. + */ @Override public List getVariables() { return this.variables; } + /** + * Returns the max degree. + * + * @return This maximum. + */ @Override public int getMaxDegree() { return (int) ceil(log(this.sampleSize)); } + /** + * Returns true if z determines y. + * + * @param z The set of nodes. + * @param y The node. + * @return True if z determines y. + */ @Override public boolean determines(List z, Node y) { int i = this.variables.indexOf(y); @@ -209,15 +246,34 @@ public boolean determines(List z, Node y) { return Double.isNaN(v); } + /** + * Returns the data set. + * + * @return The data set. + */ public DataModel getData() { return this.dataSet; } + /** + * Sets the lambda parameter. + * + * @param lambda The lambda parameter. + */ public void setLambda(double lambda) { if (lambda < 1.0) throw new IllegalArgumentException("Poisso lambda can't be < 1: " + lambda); this.lambda = lambda; } + /** + * Sets whether the pseudo-inverse should be used. + * + * @param usePseudoInverse True if the pseudo-inverse should be used. + */ + public void setUsePseudoInverse(boolean usePseudoInverse) { + this.usePseudoInverse = usePseudoInverse; + } + private int[] indices(List __adj) { int[] indices = new int[__adj.size()]; for (int t = 0; t < __adj.size(); t++) indices[t] = this.variables.indexOf(__adj.get(t)); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/ScoredGraph.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/ScoredGraph.java index e8e9f2260f..3af7d35c4c 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/ScoredGraph.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/ScoredGraph.java @@ -26,6 +26,8 @@ import edu.cmu.tetrad.util.TetradSerializable; import org.jetbrains.annotations.NotNull; +import java.io.Serial; + /** * Stores a graph with a score for the graph. The equals, hashcode, and compare methods are overridden so that it will * be easy to put these stored graphs into sets and lists. @@ -33,31 +35,67 @@ * @author josephramsey */ public class ScoredGraph implements Comparable, TetradSerializable { + @Serial private static final long serialVersionUID = 23L; + + // The graph. private final Graph graph; + // The score. private final Double score; + /** + * Constructs a scored graph. + * + * @param graph The graph. + * @param score The score. + */ public ScoredGraph(Graph graph, Double score) { this.graph = graph; this.score = score; } + /** + * Returns a serializable instance of this class. + * + * @return A serializable instance of this class. + */ public static ScoredGraph serializableInstance() { return new ScoredGraph(new EdgeListGraph(), 0.0); } + /** + * Returns the graph. + * + * @return The graph. + */ public Graph getGraph() { return this.graph; } + /** + * Returns the score. + * + * @return The score. + */ public double getScore() { return this.score; } + /** + * Return s the hashcode of the score. + * + * @return The hashcode of the score. + */ public int hashCode() { return this.score.hashCode(); } + /** + * Returns true if the scoreed graph and this scored graph are equal. + * + * @param o The other scored graph. + * @return True if the score and graph are equal. + */ public boolean equals(ScoredGraph o) { if (!this.score.equals(o.getScore())) { return false; @@ -66,6 +104,13 @@ public boolean equals(ScoredGraph o) { return this.graph.equals(o.getGraph()); } + /** + * Returns a compare value for this scored graph compared ot the given scored graph. + * + * @param o the object to be compared. + * @return a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than + * the specified object. + */ public int compareTo(@NotNull ScoredGraph o) { Double thisScore = getScore(); Double otherScore = o.getScore(); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/SemBicScore.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/SemBicScore.java index 7b069f6634..5fc7e9ae7a 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/SemBicScore.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/SemBicScore.java @@ -28,6 +28,7 @@ import edu.cmu.tetrad.graph.Node; import edu.cmu.tetrad.search.utils.LogUtilsSearch; import edu.cmu.tetrad.util.Matrix; +import edu.cmu.tetrad.util.MatrixUtils; import edu.cmu.tetrad.util.StatUtils; import edu.cmu.tetrad.util.TetradLogger; import org.apache.commons.math3.linear.SingularMatrixException; @@ -42,29 +43,26 @@ import static org.apache.commons.math3.util.FastMath.log; /** - *

Implements the linear, Gaussian BIC score, with a 'penalty discount' multiplier - * on the BIC penalty. The formula used for the score is BIC = 2L - ck ln n, where c is the penalty discount and L is - * the linear, Gaussian log likelihood--that is, the sum of the log likelihoods of the individual records, which are - * assumed to be i.i.d.

- * - *

For FGES, Chickering uses the standard linear, Gaussian BIC score, so we will - * for lack of a better reference give his paper:

- * - *

Chickering (2002) "Optimal structure identification with greedy search" - * Journal of Machine Learning Research.

- * - *

The version of the score due to Nandy et al. is given in this reference:

- * - *

Nandy, P., Hauser, A., & Maathuis, M. H. (2018). High-dimensional consistency - * in score-based and hybrid structure learning. The Annals of Statistics, 46(6A), 3151-3183.

- * - *

This score may be used anywhere though where a linear, Gaussian score is needed. - * Anectodally, the score is fairly robust to non-Gaussianity, though with some additional unfaithfulness over and above - * waht the score would give for Guassian data, a detriment that can be overcome to an extent by use a permutation - * algorithm such as SP, GRaSP, or BOSS

- * - *

As for all scores in Tetrad, higher scores mean more dependence, and negative - * scores indicate independence.

+ * Implements the linear, Gaussian BIC score, with a 'penalty discount' multiplier on the BIC penalty. The formula used + * for the score is BIC = 2L - ck ln n, where c is the penalty discount and L is the linear, Gaussian log + * likelihood--that is, the sum of the log likelihoods of the individual records, which are assumed to be i.i.d. + *

+ * For FGES, Chickering uses the standard linear, Gaussian BIC score, so we will for lack of a better reference give his + * paper: + *

+ * Chickering (2002) "Optimal structure identification with greedy search" Journal of Machine Learning Research. + *

+ * The version of the score due to Nandy et al. is given in this reference: + *

+ * Nandy, P., Hauser, A., & Maathuis, M. H. (2018). High-dimensional consistency in score-based and hybrid structure + * learning. The Annals of Statistics, 46(6A), 3151-3183. + *

+ * This score may be used anywhere though where a linear, Gaussian score is needed. Anecdotally, the score is fairly + * robust to non-Gaussianity, though with some additional unfaithfulness over and above what the score would give for + * Gaussian data, a detriment that can be overcome to an extent by use a permutation algorithm such as SP, GRaSP, or + * BOSS. + *

+ * As for all scores in Tetrad, higher scores mean more dependence, and negative scores indicate independence. * * @author josephramsey * @see edu.cmu.tetrad.search.Fges @@ -78,7 +76,9 @@ public class SemBicScore implements Score { private final int sampleSize; // A map from variable names to their indices. private final Map indexMap; + // The log of the sample size. private final double logN; + // True if row subsets should be calculated. private boolean calculateRowSubsets; // The dataset. private DataModel dataModel; @@ -92,18 +92,19 @@ public class SemBicScore implements Score { private boolean verbose; // The penalty penaltyDiscount, 1 for standard BIC. private double penaltyDiscount = 1.0; - // The structure prior, 0 for standard BIC. private double structurePrior; - - // Equivalent sample size + // The covariance matrix. private Matrix matrix; - // The rule type to use. private RuleType ruleType = RuleType.CHICKERING; + // True iff the pseudo-inverse should be used instead of the inverse to avoid exceptions. + private boolean usePseudoInverse = false; /** * Constructs the score using a covariance matrix. + * + * @param covariances The covariance matrix. */ public SemBicScore(ICovarianceMatrix covariances) { if (covariances == null) { @@ -119,6 +120,9 @@ public SemBicScore(ICovarianceMatrix covariances) { /** * Constructs the score using a covariance matrix. + * + * @param dataSet The dataset. + * @param precomputeCovariances Whether the covariances should be precomputed or computed on the fly. True if */ public SemBicScore(DataSet dataSet, boolean precomputeCovariances) { @@ -147,20 +151,74 @@ public SemBicScore(DataSet dataSet, boolean precomputeCovariances) { this.logN = log(sampleSize); } - public static double getVarRy(int i, int[] parents, Matrix data, ICovarianceMatrix covariances, boolean calculateRowSubsets) + /** + * Returns the variance of the residual of the regression of the ith variable on its parents. + * + * @param i The index of the variable. + * @param parents The indices of the parents. + * @param covariances The covariance matrix. + * @param calculateRowSubsets True if row subsets should be calculated. + * @return The variance of the residual of the regression of the ith variable on its parents. + */ + public static double getVarRy(int i, int[] parents, Matrix data, ICovarianceMatrix covariances, + boolean calculateRowSubsets, boolean usePseudoInverse) throws SingularMatrixException { + CovAndCoefs covAndcoefs = getCovAndCoefs(i, parents, data, covariances, calculateRowSubsets, usePseudoInverse); + return (bStar(covAndcoefs.b()).transpose().times(covAndcoefs.cov()).times(bStar(covAndcoefs.b())).get(0, 0)); + } + + /** + * Returns the covariance matrix of the regression of the ith variable on its parents and the regression + * coefficients. + * + * @param i The index of the variable. + * @param parents The indices of the parents. + * @param data The data matrix. + * @param covariances The covariance matrix. + * @param calculateRowSubsets True if row subsets should be calculated. + * @param usePseudoInverse True if the pseudo-inverse should be used instead of the inverse to avoid exceptions. + * @return The covariance matrix of the regression of the ith variable on its parents and the regression + * coefficients. + */ + @NotNull + public static SemBicScore.CovAndCoefs getCovAndCoefs(int i, int[] parents, Matrix data, ICovarianceMatrix covariances, boolean calculateRowSubsets, boolean usePseudoInverse) { + List rows = SemBicScore.getRows(i, parents, data, calculateRowSubsets); + return getCovAndCoefs(i, parents, data, covariances, usePseudoInverse, rows); + } + + /** + * Returns the covariance matrix of the regression of the ith variable on its parents and the regression + * + * @param i The index of the variable. + * @param parents The indices of the parents. + * @param data The data matrix. + * @param covariances The covariance matrix. + * @param usePseudoInverse True if the pseudo-inverse should be used instead of the inverse to avoid exceptions. + * @param rows The rows to use. + * @return The covariance matrix of the regression of the ith variable on its parents and the regression + */ + @NotNull + public static CovAndCoefs getCovAndCoefs(int i, int[] parents, Matrix data, ICovarianceMatrix covariances, boolean usePseudoInverse, List rows) { int[] all = SemBicScore.concat(i, parents); - Matrix cov = SemBicScore.getCov(SemBicScore.getRows(i, parents, data, calculateRowSubsets), all, all, data, covariances); + Matrix cov = SemBicScore.getCov(rows, all, all, data, covariances); int[] pp = SemBicScore.indexedParents(parents); Matrix covxx = cov.getSelection(pp, pp); Matrix covxy = cov.getSelection(pp, new int[]{0}); - Matrix b = (covxx.inverse().times(covxy)); - Matrix bStar = bStar(b); - return (bStar.transpose().times(cov).times(bStar).get(0, 0)); + + // The regression coefficient vector. + Matrix b; + + if (usePseudoInverse) { + b = new Matrix(MatrixUtils.pseudoInverse(covxx.toArray())).times(covxy); + } else { + b = covxx.inverse().times(covxy); + } + + return new CovAndCoefs(cov, b); } @NotNull - public static Matrix bStar(Matrix b) { + private static Matrix bStar(Matrix b) { Matrix byx = new Matrix(b.getNumRows() + 1, 1); byx.set(0, 0, 1); for (int j = 0; j < b.getNumRows(); j++) byx.set(j + 1, 0, -b.get(j, 0)); @@ -235,9 +293,14 @@ private static List getRows(int i, int[] parents, Matrix data, boolean return rows; } - @NotNull - private ICovarianceMatrix getCovarianceMatrix(DataSet dataSet, boolean precomputeCovariances) { - return SimpleDataLoader.getCovarianceMatrix(dataSet, precomputeCovariances); + /** + * Returns the covariance matrix of the regression of the ith variable on its parents and the regression + * coefficients. + * + * @param usePseudoInverse True if the pseudo-inverse should be used instead of the inverse to avoid exceptions. + */ + public void setUsePseudoInverse(boolean usePseudoInverse) { + this.usePseudoInverse = usePseudoInverse; } @Override @@ -272,6 +335,8 @@ public double nandyBic(int x, int y, int[] z) { } /** + * Returns the score for the given node and its parents. + * * @param i The index of the node. * @param parents The indices of the node's parents. * @return The score, or NaN if the score cannot be calculated. @@ -283,7 +348,8 @@ public double localScore(int i, int... parents) { Arrays.sort(parents); try { - double varey = SemBicScore.getVarRy(i, parents, this.data, this.covariances, this.calculateRowSubsets); + double varey = SemBicScore.getVarRy(i, parents, this.data, this.covariances, this.calculateRowSubsets, + usePseudoInverse); lik = -(double) (this.sampleSize / 2.0) * log(varey); } catch (SingularMatrixException e) { System.out.println("Singularity encountered when scoring " + @@ -309,30 +375,47 @@ public double localScore(int i, int... parents) { } } - -// private final Map, Double> cache = new ConcurrentHashMap<>(); - /** - * Specialized scoring method for a single parent. Used to speed up the effect edges search. + * Returns the multiplier on the penalty term for this score. + * + * @return The multiplier on the penalty term for this score. */ - - public double getPenaltyDiscount() { return this.penaltyDiscount; } + /** + * Sets the multiplier on the penalty term for this score. + * + * @param penaltyDiscount The multiplier on the penalty term for this score. + */ public void setPenaltyDiscount(double penaltyDiscount) { this.penaltyDiscount = penaltyDiscount; } + /** + * Returns the structure prior for this score. + * + * @return The structure prior for this score. + */ public double getStructurePrior() { return this.structurePrior; } + /** + * Sets the structure prior for this score. + * + * @param structurePrior The structure prior for this score. + */ public void setStructurePrior(double structurePrior) { this.structurePrior = structurePrior; } + /** + * Returns the covariance matrix. + * + * @return The covariance matrix. + */ public ICovarianceMatrix getCovariances() { return this.covariances; } @@ -345,32 +428,68 @@ private void setCovariances(ICovarianceMatrix covariances) { } + /** + * Returns the sample size. + * + * @return The sample size. + */ public int getSampleSize() { return this.sampleSize; } + /** + * Returns true if the given bump is an effect edge. + * + * @param bump The bump. + * @return True if the given bump is an effect edge. + */ @Override public boolean isEffectEdge(double bump) { return bump > 0; } + /** + * Returns the data model. + * + * @return The data model. + */ public DataModel getDataModel() { return this.dataModel; } + /** + * Returns true if verbose output should be sent to out. + * + * @return True if verbose output should be sent to out. + */ public boolean isVerbose() { return this.verbose; } + /** + * Sets whether verbose output should be sent to out. + * + * @param verbose True if verbose output should be sent to out. + */ public void setVerbose(boolean verbose) { this.verbose = verbose; } + /** + * Returns the variables of the covariance matrix. + * + * @return The variables of the covariance matrix. + */ @Override public List getVariables() { return new ArrayList<>(this.variables); } + /** + * Sets the variables of the covariance matrix. + * + * @param variables The variables of the covariance matrix. + */ public void setVariables(List variables) { if (this.covariances != null) { this.covariances.setVariables(variables); @@ -379,11 +498,23 @@ public void setVariables(List variables) { this.variables = variables; } + /** + * Returns the maximum degree of the score. + * + * @return The maximum degree of the score. + */ @Override public int getMaxDegree() { return (int) FastMath.ceil(log(this.sampleSize)); } + /** + * Returns true is the variables in z determine the variable y. + * + * @param z The set of nodes. + * @param y The node. + * @return True is the variables in z determine the variable y. + */ @Override public boolean determines(List z, Node y) { int i = this.variables.indexOf(y); @@ -404,11 +535,49 @@ public boolean determines(List z, Node y) { return false; } - // @Override + /** + * Returns the data model. + * + * @return The data model. + */ public DataModel getData() { return this.dataModel; } + /** + * Sets the rule type to use. + * + * @param ruleType The rule type to use. + * @see RuleType + */ + public void setRuleType(RuleType ruleType) { + this.ruleType = ruleType; + } + + /** + * Returns a SEM BIC score for the given subset of variables. + * + * @param subset The subset of variables. + * @return A SEM BIC score for the given subset of variables. + */ + public SemBicScore subset(List subset) { + int[] cols = new int[subset.size()]; + for (int i = 0; i < cols.length; i++) { + cols[i] = variables.indexOf(subset.get(i)); + } + ICovarianceMatrix cov = getCovariances().getSubmatrix(cols); + return new SemBicScore(cov); + } + + /** + * Returns a string representation of this score. + * + * @return A string representation of this score. + */ + public String toString() { + return "SEM BIC Score"; + } + private double getStructurePrior(int parents) { if (abs(getStructurePrior()) <= 0) { return 0; @@ -531,27 +700,17 @@ private Matrix getCov(List rows, int[] cols) { return cov; } - public void setRuleType(RuleType ruleType) { - this.ruleType = ruleType; - } - - public SemBicScore subset(List pi2) { - int[] cols = new int[pi2.size()]; - for (int i = 0; i < cols.length; i++) { - cols[i] = variables.indexOf(pi2.get(i)); - } - ICovarianceMatrix cov = getCovariances().getSubmatrix(cols); - return new SemBicScore(cov); - } - - public String toString() { - return "SEM BIC Score"; + private ICovarianceMatrix getCovarianceMatrix(DataSet dataSet, boolean precomputeCovariances) { + return SimpleDataLoader.getCovarianceMatrix(dataSet, precomputeCovariances); } /** * Gives two options for calculating the BIC score, one describe by Chickering and the other due to Nandy et al. */ public enum RuleType {CHICKERING, NANDY} + + public record CovAndCoefs(Matrix cov, Matrix b) { + } } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/SemBicScorer.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/SemBicScorer.java index 57c5979b6a..cd3deb47d6 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/SemBicScorer.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/SemBicScorer.java @@ -48,7 +48,7 @@ public static double scoreDag(Graph dag, DataModel data, double penaltyDiscount, } else if (data instanceof DataSet) { score = new SemBicScore((DataSet) data, precomputeCovariances); } else { - throw new IllegalArgumentException("Expecting a covariance matrix of a dataset."); + throw new IllegalArgumentException("Expecting a covariance matrix or a dataset."); } score.setPenaltyDiscount(penaltyDiscount); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/ZsbScore.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/ZsbScore.java index 29a7548982..f7d52e4dad 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/ZsbScore.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/ZsbScore.java @@ -37,26 +37,24 @@ import static org.apache.commons.math3.util.FastMath.*; /** - *

Implements an unpublished score based on a risk bound due to - * Zhang and Shen. It adapts Theorem 1 in the following reference:

- * - *

Zhang, Y., & Shen, X. (2010). Model selection procedure for - * high‐dimensional data. Statistical Analysis and Data Mining: The ASA Data Science Journal, 3(5), 350-358

- * - *

The score uses Theorem 1 in the above to numerically search - * for a lambda value that is bounded by a given probability risk, between 0 and 1, if outputting a local false positive - * parent for a variable. There is a parameter m0, which is a maximum number of parents for a particular variable, which - * is free. The solution of this score is to increase m0 from 0 upward, re-evaluating with each scoring that is done - * using that variable as a target node. Thus, over time, a lower bound on m0 is estimated with more and more precision. - * So as the score is used in the context of FGES or GRaSP, for instance, so long as the score for a given node is - * visited more than once, the scores output by the procedure can be expected to improve, though setting m0 to 0 for all - * variables does not give bad results even by itself.

- * - *

This score is conservative for large, dense models and faster - * than other available scores in this package. The risk bound is easily interpreted.

- * - *

As for all scores in Tetrad, higher scores mean more dependence, - * and negative scores indicate independence.

+ * Implements an unpublished score based on a risk bound due to Zhang and Shen. It adapts Theorem 1 in the following + * reference: + *

+ * Zhang, Y., & Shen, X. (2010). Model selection procedure for high‐dimensional data. Statistical Analysis and Data + * Mining: The ASA Data Science Journal, 3(5), 350-358 + *

+ * The score uses Theorem 1 in the above to numerically search for a lambda value that is bounded by a given probability + * risk, between 0 and 1, if outputting a local false positive parent for a variable. There is a parameter m0, which is + * a maximum number of parents for a particular variable, which is free. The solution of this score is to increase m0 + * from 0 upward, re-evaluating with each scoring that is done using that variable as a target node. Thus, over time, a + * lower bound on m0 is estimated with more and more precision. So as the score is used in the context of FGES or GRaSP, + * for instance, so long as the score for a given node is visited more than once, the scores output by the procedure can + * be expected to improve, though setting m0 to 0 for all variables does not give bad results even by itself. + *

+ * This score is conservative for large, dense models and faster than other available scores in this package. The risk + * bound is easily interpreted. + *

+ * As for all scores in Tetrad, higher scores mean more dependence, and negative scores indicate independence. * * @author josephramsey */ @@ -80,8 +78,8 @@ public class ZsbScore implements Score { private List lambdas; // The data, if it is set. private Matrix data; - - private boolean changed = false; + // True if the pseudo-inverse should be used. + private boolean usePseudoInverse; /** * Constructs the score using a covariance matrix. @@ -162,7 +160,7 @@ public double localScore(int i, int... parents) { double varRy; try { - varRy = SemBicScore.getVarRy(i, parents, data, covariances, calculateRowSubsets); + varRy = SemBicScore.getVarRy(i, parents, data, covariances, calculateRowSubsets, usePseudoInverse); } catch (SingularMatrixException e) { throw new RuntimeException("Singularity encountered when scoring " + LogUtilsSearch.getScoreFact(i, parents, variables)); @@ -194,6 +192,11 @@ public double localScoreDiff(int x, int y, int[] z) { return localScore(y, append(z, x)) - localScore(y, z); } + /** + * Returns the covariance matrix. + * + * @return The covariance matrix. + */ public ICovarianceMatrix getCovariances() { return covariances; } @@ -291,6 +294,15 @@ public void setRiskBound(double riskBound) { this.riskBound = riskBound; } + /** + * Sets whether to use the pseudo-inverse in place of the inverse in the score. + * + * @param usePseudoInverse True if the pseudo-inverse should be used. + */ + public void setUsePseudoInverse(boolean usePseudoInverse) { + this.usePseudoInverse = usePseudoInverse; + } + private double getLambda(int m0, int pn) { if (lambdas == null) { lambdas = new ArrayList<>(); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/package-info.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/package-info.java index df4cb0efd7..4e731ff2d1 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/package-info.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/score/package-info.java @@ -1,4 +1,4 @@ /** - * Contains classes for various various sorts of scores for running score-based algorithms. + * Contains classes for various sorts of scores for running score-based algorithms. */ package edu.cmu.tetrad.search.score; diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/ChiSquareTest.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/ChiSquareTest.java index 1adc8bd541..539e067f19 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/ChiSquareTest.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/ChiSquareTest.java @@ -26,59 +26,62 @@ import edu.cmu.tetrad.data.DiscreteVariable; import edu.cmu.tetrad.util.CombinationIterator; import org.apache.commons.math3.distribution.ChiSquaredDistribution; -import org.apache.commons.math3.util.FastMath; -import java.util.Arrays; +import java.util.List; + +import static org.apache.commons.math3.util.FastMath.log; /** - * Calculates marginal chi square test results for a discrete dataset. + * Calculates chi-square or g-square for a conditional cross-tabulation table for independence question 0 _||_ 1 | 2, 3, + * ...max by summing up chi-square and degrees of freedom for each conditional table in turn, where rows or columns that + * sum to less than a given threshold have been removed. The adjusted conditional tables are required to have more than + * 0 total counts and at least 2 rows and 2 columns; otherwise, the test is judged to be invalid. Otherwise, a p-value + * is returned based on the Chi-Square distribution with the total degrees of freedom and total chi-square. * * @author frankwimberly * @author josephramsey + * @see TestType */ public class ChiSquareTest { - /** - * The data set this test uses. - */ + // The data set this test uses. private final DataSet dataSet; - - /** - * The number of values for each variable in the data. - */ + // The number of values for each variable in the data. private final int[] dims; - - /** - * Stores the data in the form of a cell table. - */ + // Stores the data in the form of a cell table. private final CellTable cellTable; + // The type of test to perform. + private final TestType testType; + // The significance level of the test. + private double alpha; /** - * The significance level of the test. + * The minimum sum of a row or column for a conditional table to be included in the overall chi-square and degrees + * of freedom. Note that this should not be too small, or the chi-square distribution will not be a good + * approximation to the distribution of the test statistic. */ - private double alpha; - + private double minCountPerCell = 1.0; /** * Constructs a test using the given data set and significance level. * - * @param dataSet A data set consisting entirely of discrete variables. - * @param alpha The significance level, usually 0.05. + * @param dataSet A data set consisting entirely of discrete variables. + * @param alpha The significance level, usually 0.05. + * @param testType The type of test to perform, either CHI_SQUARE or G_SQUARE. */ - public ChiSquareTest(DataSet dataSet, double alpha) { + public ChiSquareTest(DataSet dataSet, double alpha, TestType testType) { if (alpha < 0.0 || alpha > 1.0) { - throw new IllegalArgumentException("Significance level must be in " + - "[0, 1]: " + alpha); + throw new IllegalArgumentException("Significance level must be in " + "[0, 1]: " + alpha); } this.dims = new int[dataSet.getNumColumns()]; for (int i = 0; i < getDims().length; i++) { - DiscreteVariable variable = - (DiscreteVariable) dataSet.getVariable(i); + DiscreteVariable variable = (DiscreteVariable) dataSet.getVariable(i); this.getDims()[i] = variable.getNumCategories(); } + this.testType = testType; this.dataSet = dataSet; this.alpha = alpha; this.cellTable = new CellTable(null); @@ -88,7 +91,10 @@ public ChiSquareTest(DataSet dataSet, double alpha) { /** * Calculates chi square for a conditional cross-tabulation table for independence question 0 _||_ 1 | 2, 3, ...max * by summing up chi square and degrees of freedom for each conditional table in turn, where rows or columns that - * consist entirely of zeros have been removed. + * with fewer than minSumRowOrCol counts have been removed. The adjusted conditional tables are required to have + * more than 0 total counts and at least 2 rows and 2 columns; otherwise, the test is judged to be invalid. + * Otherwise, a p-value is returned based on the Chi-Square distribution with the total degrees of freedom and total + * chi-square. * * @param testIndices These indices, in order. * @return a Chi square test result. @@ -112,8 +118,7 @@ public Result calcChiSquare(int[] testIndices) { int df = 0; int[] condDims = new int[testIndices.length - 2]; - System.arraycopy(selectFromArray(getDims(), testIndices), 2, condDims, 0, - condDims.length); + System.arraycopy(selectFromArray(getDims(), testIndices), 2, condDims, 0, condDims.length); int[] coords = new int[testIndices.length]; int numRows = this.getCellTable().getNumValues(0); @@ -124,76 +129,99 @@ public Result calcChiSquare(int[] testIndices) { // Make a chi square table for each condition combination, strike zero rows and columns and calculate // chi square and degrees of freedom for the remaining rows and columns in the table. See Friedman. while (combinationIterator.hasNext()) { - boolean[] attestedRows = new boolean[numRows]; - boolean[] attestedCols = new boolean[numCols]; - - Arrays.fill(attestedRows, true); - Arrays.fill(attestedCols, true); - int[] combination = combinationIterator.next(); - System.arraycopy(combination, 0, coords, 2, combination.length); - long total = getCellTable().calcMargin(coords, bothVars); - - if (total == 0) continue; - - double _xSquare = 0.0; + double[] sumRows = new double[numRows]; + double[] sumCols = new double[numCols]; + boolean[] zeroRows = new boolean[numRows]; + boolean[] zeroCols = new boolean[numCols]; + int numNonZeroRows = 0; + int numNonZeroCols = 0; for (int i = 0; i < numRows; i++) { - for (int j = 0; j < numCols; j++) { - coords[0] = i; - coords[1] = j; - - long sumRow = getCellTable().calcMargin(coords, firstVar); - long sumCol = getCellTable().calcMargin(coords, secondVar); - long observed = getCellTable().getValue(coords); + coords[0] = i; + sumRows[i] = getCellTable().calcMargin(coords, secondVar); - if (sumRow == 0L) { - attestedRows[i] = false; - continue; - } + if (sumRows[i] == 0 || sumRows[i] < minCountPerCell * numCols) { + zeroRows[i] = true; + } else { + numNonZeroRows++; + } + } - if (sumCol == 0L) { - attestedCols[j] = false; - continue; - } + for (int j = 0; j < numCols; j++) { + coords[1] = j; + sumCols[j] = getCellTable().calcMargin(coords, firstVar); - double expected = (sumRow * sumCol) / (double) total; - _xSquare += FastMath.pow(observed - expected, 2.0) / expected; + if (sumCols[j] == 0 || sumCols[j] < minCountPerCell * numRows) { + zeroCols[j] = true; + } else { + numNonZeroCols++; } } - int numAttestedRows = 0; - int numAttestedCols = 0; + double total = getCellTable().calcMargin(coords, bothVars); - for (boolean attestedRow : attestedRows) { - if (attestedRow) { - numAttestedRows++; - } + if (total < minCountPerCell * numRows * numCols) { + continue; } - for (boolean attestedCol : attestedCols) { - if (attestedCol) { - numAttestedCols++; + if (total > 0 && numNonZeroRows > 1 && numNonZeroCols > 1) { + double _xSquare = 0.0; + + for (int i = 0; i < numRows; i++) { + for (int j = 0; j < numCols; j++) { + coords[0] = i; + coords[1] = j; + + if (zeroRows[i] || zeroCols[j]) { + continue; + } + + double observed = getCellTable().getValue(coords); + + // Under the above conditions, expected > 0. + double expected = (sumRows[i] * sumCols[j]) / total; + + if (testType == TestType.CHI_SQUARE) { + + // Note here expected > 0, so we can divide by it. + double d = observed - expected; + _xSquare += (d * d) / expected; + } else if (testType == TestType.G_SQUARE) { + + // The G-square test is a likelihood ratio test, so we need to take the log of the + // observed/expected ratio. When observed is zero, we add 0 to the total. This is the + // correct thing to do, since the limit of x * log(x) as x approaches zero is zero. + if (observed > 0) { + _xSquare += 2.0 * observed * log(observed / expected); + } else { + _xSquare += 0; + } + } else { + throw new IllegalArgumentException("Unknown test type: " + testType); + } + } } - } - if (numAttestedRows > 0 && numAttestedCols > 0) { - df += (numAttestedRows - 1) * (numAttestedCols - 1); + int _df = (numNonZeroRows - 1) * (numNonZeroCols - 1); + if (_df == 0) _df = 1; xSquare += _xSquare; + df += _df; } } - // If df == 0, this is definitely an independent table. if (df == 0) { - final double pValue = 1.0; - return new Result(xSquare, pValue, 0, true); - } - double pValue = 1.0 - new ChiSquaredDistribution(df).cumulativeProbability(xSquare); - boolean indep = (pValue > getAlpha()); - return new Result(xSquare, pValue, df, indep); + // If no conditional table had positive degrees of freedom, the test is invalid. + return new Result(Double.NaN, Double.NaN, 0, true, false); + } else { + + // Otherwise, we can calculate a p-value for the test. + double pValue = 1.0 - new ChiSquaredDistribution(df).cumulativeProbability(xSquare); + return new Result(xSquare, pValue, df, (pValue > getAlpha()), true); + } } /** @@ -216,14 +244,12 @@ public boolean isDetermined(int[] testIndices, double p) { int[] firstVar = {0}; int[] condDims = new int[testIndices.length - 1]; - System.arraycopy(selectFromArray(getDims(), testIndices), 1, condDims, 0, - condDims.length); + System.arraycopy(selectFromArray(getDims(), testIndices), 1, condDims, 0, condDims.length); int[] coords = new int[testIndices.length]; int numValues = this.getCellTable().getNumValues(0); - CombinationIterator combinationIterator = - new CombinationIterator(condDims); + CombinationIterator combinationIterator = new CombinationIterator(condDims); while (combinationIterator.hasNext()) { int[] combination = combinationIterator.next(); @@ -240,9 +266,9 @@ public boolean isDetermined(int[] testIndices, double p) { for (int i = 0; i < numValues; i++) { coords[0] = i; - long numi = this.getCellTable().getValue(coords); + long value = this.getCellTable().getValue(coords); - if ((double) numi / total >= p) { + if ((double) value / total >= p) { dominates = true; } } @@ -271,13 +297,20 @@ public double getAlpha() { */ public void setAlpha(double alpha) { if (alpha < 0.0 || alpha > 1.0) { - throw new IllegalArgumentException("Significance level must be in " + - "[0, 1]: " + alpha); + throw new IllegalArgumentException("Significance level must be in " + "[0, 1]: " + alpha); } this.alpha = alpha; } + /** + * Sets the rows to use in the data. + * + * @param rows The rows to use. + */ + public void setRows(List rows) { + this.cellTable.setRows(rows); + } private int[] selectFromArray(int[] arr, int[] indices) { int[] retArr = new int[indices.length]; @@ -301,6 +334,23 @@ private CellTable getCellTable() { return this.cellTable; } + /** + * The minimum number of counts per conditional table for chi-square for that table and its degrees of freedom to be + * included in the overall chi-square and degrees of freedom. Note that this should not be too small, or the + * chi-square distribution will not be a good approximation to the distribution of the test statistic. + * + * @param minCountPerCell The minimum number of counts per conditional table. The default is 1; this must be >= 0. + */ + public void setMinCountPerCell(double minCountPerCell) { + this.minCountPerCell = minCountPerCell; + } + + /** + * The type of test to perform. + */ + public enum TestType { + CHI_SQUARE, G_SQUARE + } /** * Simple class to store the parameters of the result returned by the G Square test. @@ -308,52 +358,87 @@ private CellTable getCellTable() { * @author Frank Wimberly */ public static class Result { - - /** - * The chi square value. - */ private final double chiSquare; - - /** - * The pValue of the result. - */ private final double pValue; - - /** - * The adjusted degrees of freedom. - */ private final int df; + private final boolean isIndep; + private final boolean isValid; /** - * Whether the conditional independence holds or not. (True if it does, false if it doesn't. + * Constructs a new g square result using the given parameters. + * + * @param chiSquare The chi square value. + * @param pValue The pValue of the result. + * @param df The adjusted degrees of freedom. + * @param isIndep Whether the conditional independence holds or not. (True if it does, false if it doesn't.) */ - private final boolean isIndep; + public Result(double chiSquare, double pValue, int df, boolean isIndep) { + this(chiSquare, pValue, df, isIndep, true); + } /** * Constructs a new g square result using the given parameters. + * + * @param chiSquare The chi square value. + * @param pValue The pValue of the result. + * @param df The adjusted degrees of freedom. + * @param isIndep Whether the conditional independence holds or not. (True if it does, false if it doesn't.) + * @param isValid Whether the result is isValid or not. */ - public Result(double chiSquare, double pValue, int df, boolean isIndep) { + public Result(double chiSquare, double pValue, int df, boolean isIndep, boolean isValid) { this.chiSquare = chiSquare; this.pValue = pValue; this.df = df; this.isIndep = isIndep; + this.isValid = isValid; } + /** + * Returns the chi square value, or NaN if the chi square value cannot be determined. + * + * @return the chi square value. + */ public double getXSquare() { return this.chiSquare; } + /** + * Returns the pValue of the result, or NaN if the p-value cannot be determined. + * + * @return the pValue of the result. + */ public double getPValue() { return this.pValue; } + /** + * Returns the adjusted degrees of freedom, or -1 if the degrees of freedom cannot be determined. + * + * @return the adjusted degrees of freedom. + */ public int getDf() { return this.df; } + /** + * Returns whether the conditional independence holds or not. (True if it does, false if it doesn't.) For + * invalid results, this method returns a value set by the test. + * + * @return whether the conditional independence holds or not. + */ public boolean isIndep() { return this.isIndep; } + + /** + * Returns whether the result is valid or not. A result is valid if its judgment of independence is not + * indeterminate. + * + * @return whether the result is valid or not. + */ + public boolean isValid() { + return isValid; + } } } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/ConditionalCorrelationIndependence.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/ConditionalCorrelationIndependence.java index ef6325de03..7ccdda0c1e 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/ConditionalCorrelationIndependence.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/ConditionalCorrelationIndependence.java @@ -44,8 +44,7 @@ *

* This all follows the original Daudin paper, which is this: *

- * Daudin, J. J. (1980). Partial association measures and ann application to qualitative regression. - * Biometrika, 67(3), + * Daudin, J. J. (1980). Partial association measures and ann application to qualitative regression. Biometrika, 67(3), * 581-590. *

* We use Nadaraya-Watson kernel regression, though we further restrict the sample size to nearby points. diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/GSquareTest.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/GSquareTest.java deleted file mode 100644 index 7b230e59f5..0000000000 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/GSquareTest.java +++ /dev/null @@ -1,402 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// 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.test; - -import edu.cmu.tetrad.data.CellTable; -import edu.cmu.tetrad.data.DataSet; -import edu.cmu.tetrad.data.DiscreteVariable; -import edu.cmu.tetrad.util.CombinationIterator; -import edu.cmu.tetrad.util.ProbUtils; -import org.apache.commons.math3.util.FastMath; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - *

Performs conditional independence tests of discrete data using the G Square method. - * Degrees of freedom are calculated as in Fienberg (2007), this reference:

- * - *

Fienberg, S. E. (2007). The analysis of cross-classified categorical data. - * Springer Science & Business Media.

- * - * @author Frank Wimberly original version - * @author josephramsey revision 10/01 - */ -public final class GSquareTest { - - /** - * The data set this test uses. - */ - private final DataSet dataSet; - - /** - * The number of values for each variable in the data. - */ - private final int[] dims; - - /** - * Stores the data in the form of a cell table. - */ - private final CellTable cellTable; - - /** - * The significance level of the test. - */ - private double alpha; - - /** - * Constructor - * - * @param dataSet The discrete dataset for which test results are requested. - * @param alpha The alpha sigificance level cutoff. - */ - public GSquareTest(DataSet dataSet, double alpha) { - if (alpha < 0.0 || alpha > 1.0) { - throw new IllegalArgumentException("Significance level must be in " + - "[0, 1]: " + alpha); - } - - this.dims = new int[dataSet.getNumColumns()]; - - for (int i = 0; i < getDims().length; i++) { - DiscreteVariable variable = - (DiscreteVariable) dataSet.getVariable(i); - this.getDims()[i] = variable.getNumCategories(); - } - - this.dataSet = dataSet; - this.alpha = alpha; - this.cellTable = new CellTable(null); - this.getCellTable().setMissingValue(DiscreteVariable.MISSING_VALUE); - } - - /** - * Calculates g square for a conditional crosstabulation table for independence question 0 _||_ 1 | 2, 3, ...max by - * summing up g square and degrees of freedom for each conditional table in turn, where rows or columns that consist - * entirely of zeros have been removed. - * - * @param testIndices The indices of the test result needed, in order. So for the above, [0 1 2 3...max]. - * @return the test result. - * @see Result - */ - public Result calcGSquare(int[] testIndices) { - - if (testIndices.length < 2) - throw new IllegalArgumentException("Need at least two variables for G Square test."); - - // Reset the cell table for the columns referred to in - // 'testIndices.' Do cell coefs for those columns. - getCellTable().addToTable(getDataSet(), testIndices); - - // Indicator arrays to tell the cell table which margins - // to calculate. For x _||_ y | z1, z2, ..., we want to - // calculate the margin for x, the margin for y, and the - // margin for x and y. (These will be used later.) - int[] firstVar = {0}; - int[] secondVar = {1}; - int[] bothVars = {0, 1}; - - double g2 = 0.0; - int df = 0; - - int[] condDims = new int[testIndices.length - 2]; - System.arraycopy(selectFromArray(getDims(), testIndices), 2, condDims, 0, - condDims.length); - - int[] coords = new int[testIndices.length]; - int numRows = this.getCellTable().getNumValues(0); - int numCols = this.getCellTable().getNumValues(1); - - boolean[] attestedRows = new boolean[numRows]; - boolean[] attestedCols = new boolean[numCols]; - - CombinationIterator combinationIterator = - new CombinationIterator(condDims); - - while (combinationIterator.hasNext()) { - int[] combination = combinationIterator.next(); - - System.arraycopy(combination, 0, coords, 2, combination.length); - Arrays.fill(attestedRows, true); - Arrays.fill(attestedCols, true); - - long total = this.getCellTable().calcMargin(coords, bothVars); - - double _gSquare = 0.0; - - List e = new ArrayList<>(); - List o = new ArrayList<>(); - - for (int i = 0; i < numRows; i++) { - for (int j = 0; j < numCols; j++) { - coords[0] = i; - coords[1] = j; - - long sumRow = this.getCellTable().calcMargin(coords, secondVar); - long sumCol = this.getCellTable().calcMargin(coords, firstVar); - long observed = (int) this.getCellTable().getValue(coords); - - boolean skip = false; - - if (sumRow == 0) { - attestedRows[i] = false; - skip = true; - } - - if (sumCol == 0) { - attestedCols[j] = false; - skip = true; - } - - if (skip) { - continue; - } - - e.add((double) sumCol * sumRow); - o.add(observed); - } - } - - for (int i = 0; i < o.size(); i++) { - double expected = e.get(i) / (double) total; - - if (o.get(i) != 0) { - _gSquare += 2.0 * o.get(i) * FastMath.log(o.get(i) / expected); - } - } - - if (total == 0) { - continue; - } - - int numAttestedRows = 0; - int numAttestedCols = 0; - - for (boolean attestedRow : attestedRows) { - if (attestedRow) { - numAttestedRows++; - } - } - - for (boolean attestedCol : attestedCols) { - if (attestedCol) { - numAttestedCols++; - } - } - - int _df = (numAttestedRows - 1) * (numAttestedCols - 1); - - if (_df > 0) { - df += _df; - g2 += _gSquare; - } - } - - // If df == 0, return indep. - if (df == 0) { - df = 1; - } - - double pValue = 1.0 - ProbUtils.chisqCdf(g2, df); - boolean indep = (pValue > getAlpha()); - return new Result(g2, pValue, df, indep); - } - - /** - * Returns the dimensions of the variables, in order. - * - * @return These dimensions, as an int[] array. For instance, if the array is [2 3], then the first variable has 2 - * categories and second variable has 3 categories. - */ - public int[] getDims() { - return this.dims; - } - - /** - * Returns the cell table for this test. - * - * @return This table. - * @see CellTable - */ - public CellTable getCellTable() { - return this.cellTable; - } - - /** - * @return the getModel significance level being used for tests. - */ - public double getAlpha() { - return this.alpha; - } - - /** - * Sets the significance level to be used for tests. - * - * @param alpha The alpha significance level of the test. - */ - public void setAlpha(double alpha) { - if (alpha < 0.0 || alpha > 1.0) { - throw new IllegalArgumentException("Significance level must be in " + - "[0, 1]: " + alpha); - } - - this.alpha = alpha; - } - - /** - * Returns the dataset used for this test. - * - * @return This dataset. - */ - public DataSet getDataSet() { - return this.dataSet; - } - - /** - * Returns a judgement of whether the variables index by 'testIndices' determine the variable index by 'p'. - * - * @param testIndices The indices of the conditioning variables. - * @param p The index of the child variable. - * @return True if the conditioning variables determine the child variable. - */ - public boolean isDetermined(int[] testIndices, double p) { - - // Reset the cell table for the columns referred to in - // 'testIndices.' Do cell coefs for those columns. - this.getCellTable().addToTable(getDataSet(), testIndices); - - // Indicator arrays to tell the cell table which margins - // to calculate. For x _||_ y | z1, z2, ..., we want to - // calculate the margin for x, the margin for y, and the - // margin for x and y. (These will be used later.) - int[] firstVar = {0}; - - int[] condDims = new int[testIndices.length - 1]; - System.arraycopy(selectFromArray(getDims(), testIndices), 1, condDims, 0, - condDims.length); - - int[] coords = new int[testIndices.length]; - int numValues = this.getCellTable().getNumValues(0); - - CombinationIterator combinationIterator = - new CombinationIterator(condDims); - - while (combinationIterator.hasNext()) { - int[] combination = combinationIterator.next(); - System.arraycopy(combination, 0, coords, 1, combination.length); - - long total = this.getCellTable().calcMargin(coords, firstVar); - - if (total == 0) { - continue; - } - - boolean dominates = false; - - for (int i = 0; i < numValues; i++) { - coords[0] = i; - - long numi = this.getCellTable().getValue(coords); - - if ((double) numi / total >= p) { - dominates = true; - } - } - - if (!dominates) { - return false; - } - } - - return true; - } - - private int[] selectFromArray(int[] arr, int[] indices) { - int[] retArr = new int[indices.length]; - - for (int i = 0; i < indices.length; i++) { - retArr[i] = arr[indices[i]]; - } - - return retArr; - } - - /** - * Stores the parameters of the result returned by the G Square test and its p-value. - * - * @author Frank Wimberly - */ - public static final class Result { - - /** - * The g square value itself. - */ - private final double gSquare; - - /** - * The pValue of the result. - */ - private final double pValue; - - /** - * The adjusted degrees of freedom. - */ - private final int df; - - /** - * Whether the conditional independence holds or not. (True if it does, false if it doesn't. - */ - private final boolean isIndep; - - /** - * Constructs a new g square result using the given parameters. - */ - public Result(double gSquare, double pValue, int df, boolean isIndep) { - this.gSquare = gSquare; - this.pValue = pValue; - this.df = df; - this.isIndep = isIndep; - } - - public double getGSquare() { - return this.gSquare; - } - - public double getPValue() { - return this.pValue; - } - - public int getDf() { - return this.df; - } - - public boolean isIndep() { - return this.isIndep; - } - } -} - - - - - diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestChiSquare.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestChiSquare.java index 655b9e983b..1614e69423 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestChiSquare.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestChiSquare.java @@ -30,21 +30,19 @@ import edu.cmu.tetrad.util.TetradLogger; import java.text.NumberFormat; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Set; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; /** * Checks the conditional independence X _||_ Y | S, where S is a set of discrete variable, and X and Y are discrete * variable not in S, by applying a conditional Chi Square test. A description of such a test is given in Fienberg, "The - * Analysis of Cross-Classified Categorical Data," 2nd edition. - * The formulas for the degrees of freedom used in this test are equivalent to the formulation on page 142 of Fienberg. + * Analysis of Cross-Classified Categorical Data," 2nd edition. The formulas for the degrees of freedom used in this + * test are equivalent to the formulation on page 142 of Fienberg. * * @author josephramsey * @see ChiSquareTest */ -public final class IndTestChiSquare implements IndependenceTest { +public final class IndTestChiSquare implements IndependenceTest, RowsSettable { /** * The Chi Square tester. @@ -60,20 +58,22 @@ public final class IndTestChiSquare implements IndependenceTest { * The dataset of discrete variables. */ private final DataSet dataSet; - + // A cache of results for independence facts. + private final Map facts = new ConcurrentHashMap<>(); /** * The G Square value associated with a particular call of isIndependent. Set in that method and not in the * constructor. */ private double xSquare; - /** * The degrees of freedom associated with a particular call of isIndependent. Set in the method and not in the * constructor. */ private int df; - + private double minCountPerCell = 1.0; private boolean verbose; + private List rows = null; + /** * Constructs a new independence checker to check conditional independence facts for discrete data using a g square @@ -98,7 +98,8 @@ public IndTestChiSquare(DataSet dataSet, double alpha) { this.dataSet = dataSet; this.variables = new ArrayList<>(dataSet.getVariables()); - this.chiSquareTest = new ChiSquareTest(dataSet, alpha); + this.chiSquareTest = new ChiSquareTest(dataSet, alpha, ChiSquareTest.TestType.CHI_SQUARE); + this.chiSquareTest.setMinCountPerCell(minCountPerCell); } /** @@ -171,6 +172,12 @@ public IndependenceResult checkIndependence(Node x, Node y, Set _z) { List z = new ArrayList<>(_z); Collections.sort(z); + if (this.facts.containsKey(new IndependenceFact(x, y, _z))) { + ChiSquareTest.Result result = this.facts.get(new IndependenceFact(x, y, _z)); + return new IndependenceResult(new IndependenceFact(x, y, _z), result.isIndep(), result.getPValue(), + getAlpha() - result.getPValue()); + } + // For testing x, y given z1,...,zn, set up an array of length // n + 2 containing the indices of these variables in order. int[] testIndices = new int[2 + z.size()]; @@ -191,6 +198,8 @@ public IndependenceResult checkIndependence(Node x, Node y, Set _z) { } ChiSquareTest.Result result = this.chiSquareTest.calcChiSquare(testIndices); + this.facts.put(new IndependenceFact(x, y, _z), result); + this.xSquare = result.getXSquare(); this.df = result.getDf(); double pValue = result.getPValue(); @@ -342,6 +351,50 @@ private double getDeterminationP() { */ return 0.99; } + + /** + * The minimum number of counts per conditional table for chi-square for that table and its degrees of freedom to be + * included in the overall chi-square and degrees of freedom. Note that this should not be too small, or the + * chi-square distribution will not be a good approximation to the distribution of the test statistic. + * + * @param minCountPerCell The minimum number of counts per conditional table. The default is 1; this must be >= 0. + */ + public void setMinCountPerCell(double minCountPerCell) { + this.minCountPerCell = minCountPerCell; + this.chiSquareTest.setMinCountPerCell(minCountPerCell); + } + + /** + * Returns the rows used for the test. If null, all rows are used. + * + * @return The rows used for the test. Can be null. + */ + @Override + public List getRows() { + return new ArrayList<>(rows); + } + + /** + * Sets the rows to use for the test. If null, all rows are used. + * + * @param rows The rows to use for the test. Can be null. + */ + @Override + public void setRows(List rows) { + if (rows == null) { + this.rows = null; + chiSquareTest.setRows(null); + } else { + for (int i : rows) { + if (i < 0 || i >= dataSet.getNumRows()) { + throw new IllegalArgumentException("Row " + i + " is out of bounds."); + } + } + + this.rows = new ArrayList<>(rows); + chiSquareTest.setRows(this.rows); + } + } } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestConditionalCorrelation.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestConditionalCorrelation.java index 0b5cb3c307..1af1e06add 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestConditionalCorrelation.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestConditionalCorrelation.java @@ -32,7 +32,9 @@ import java.text.NumberFormat; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; /** * Checks conditional independence of variable in a continuous data set using a conditional correlation test for the @@ -42,30 +44,21 @@ */ public final class IndTestConditionalCorrelation implements IndependenceTest { - /** - * Formats as 0.0000. - */ + // Formats as 0.0000. private static final NumberFormat nf = NumberFormatUtil.getInstance().getNumberFormat(); - /** - * The instance of CCI that is wrapped. - */ + // The instance of CCI that is wrapped. private final ConditionalCorrelationIndependence cci; - /** - * The variables of the covariance data, in order. (Unmodifiable list.) - */ + //The variables of the covariance data, in order. (Unmodifiable list.) private final List variables; - /** - * Stores a reference to the data set passed in through the constructor. - */ + // Stores a reference to the data set passed in through the constructor. private final DataSet dataSet; - /** - * The significance level of the independence tests. - */ + // A cache of results for independence facts. + private final Map facts = new ConcurrentHashMap<>(); + // The significance level of the independence tests. private double alpha; - /** - * True if verbose output should be printed. - */ + // True if verbose output should be printed. private boolean verbose; + // The score of the last test. private double score = Double.NaN; @@ -96,6 +89,9 @@ public IndTestConditionalCorrelation(DataSet dataSet, double alpha) { /** + * Constructs a new Independence test which checks independence facts based on the correlation data implied by the + * given data set (must be continuous). The given significance level is used. + * * @throws UnsupportedOperationException This method is not implemented. */ public IndependenceTest indTestSubset(List vars) { @@ -109,6 +105,9 @@ public IndependenceTest indTestSubset(List vars) { * @see IndependenceResult */ public IndependenceResult checkIndependence(Node x, Node y, Set z) { + if (this.facts.containsKey(new IndependenceFact(x, y, z))) { + return facts.get(new IndependenceFact(x, y, z)); + } double score = this.cci.isIndependent(x, y, z); this.score = score; @@ -128,7 +127,9 @@ public IndependenceResult checkIndependence(Node x, Node y, Set z) { } } - return new IndependenceResult(new IndependenceFact(x, y, z), independent, p, alpha - p); + IndependenceResult result = new IndependenceResult(new IndependenceFact(x, y, z), independent, p, score); + facts.put(new IndependenceFact(x, y, z), result); + return result; } /** diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestConditionalGaussianLrt.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestConditionalGaussianLrt.java index 363ba09130..da891d5cf1 100755 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestConditionalGaussianLrt.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestConditionalGaussianLrt.java @@ -35,6 +35,7 @@ import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; /** * Performs a test of conditional independence X _||_ Y | Z1...Zn where all searchVariables are either continuous or @@ -45,12 +46,19 @@ * @author josephramsey */ public class IndTestConditionalGaussianLrt implements IndependenceTest { + // The data set. private final DataSet data; + // A hash of nodes to indices. private final Map nodesHash; // Likelihood function private final ConditionalGaussianLikelihood likelihood; + // A cache of results for independence facts. + private final Map facts = new ConcurrentHashMap<>(); + // The significance level of the independence tests. private double alpha; + // True if verbose output should be printed. private boolean verbose; + // The number of categories to discretize continuous variables into. private int numCategoriesToDiscretize = 3; /** @@ -89,11 +97,16 @@ public IndependenceTest indTestSubset(List vars) { * @see IndependenceResult */ public IndependenceResult checkIndependence(Node x, Node y, Set _z) { + if (this.facts.containsKey(new IndependenceFact(x, y, _z))) { + return facts.get(new IndependenceFact(x, y, _z)); + } + this.likelihood.setNumCategoriesToDiscretize(this.numCategoriesToDiscretize); List z = new ArrayList<>(_z); Collections.sort(z); + List allVars = new ArrayList<>(z); allVars.add(x); allVars.add(y); @@ -145,7 +158,10 @@ public IndependenceResult checkIndependence(Node x, Node y, Set _z) { } } - return new IndependenceResult(new IndependenceFact(x, y, _z), independent, pValue, getAlpha() - pValue); + IndependenceResult result = new IndependenceResult(new IndependenceFact(x, y, _z), independent, + pValue, getAlpha() - pValue); + facts.put(new IndependenceFact(x, y, _z), result); + return result; } /** diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestDegenerateGaussianLrt.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestDegenerateGaussianLrt.java index b8eace3243..1a96ccd7fa 100755 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestDegenerateGaussianLrt.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestDegenerateGaussianLrt.java @@ -42,11 +42,10 @@ import static org.apache.commons.math3.util.FastMath.*; /** - *

Implements a degenerate Gaussian score as a LRT. The reference is here:

- * - *

Andrews, B., Ramsey, J., & Cooper, G. F. (2019, July). Learning high-dimensional - * directed acyclic graphs with mixed data-types. In The 2019 ACM SIGKDD Workshop on Causal Discovery (pp. 4-21). - * PMLR.

+ * Implements a degenerate Gaussian score as a LRT. The reference is here: + *

+ * Andrews, B., Ramsey, J., & Cooper, G. F. (2019, July). Learning high-dimensional directed acyclic graphs with + * mixed data-types. In The 2019 ACM SIGKDD Workshop on Causal Discovery (pp. 4-21). PMLR. * * @author Bryan Andrews */ @@ -54,18 +53,25 @@ public class IndTestDegenerateGaussianLrt implements IndependenceTest { // A constant. private static final double L2PE = log(2.0 * PI * E); + // The data set. private final BoxDataSet ddata; + // The data set. private final double[][] _ddata; + // A hash of nodes to indices. private final Map nodeHash; + // The data set. private final DataSet dataSet; // The mixed variables of the original dataset. private final List variables; // The embedding map. private final Map> embedding; + // A cache of results for independence facts. + private final Map facts = new ConcurrentHashMap<>(); // The alpha level. private double alpha = 0.001; // The p value. private double pValue = NaN; + // True if verbose output should be printed. private boolean verbose; /** @@ -176,6 +182,9 @@ public IndependenceTest indTestSubset(List vars) { * @see IndependenceResult */ public IndependenceResult checkIndependence(Node x, Node y, Set _z) { + if (facts.containsKey(new IndependenceFact(x, y, _z))) { + return facts.get(new IndependenceFact(x, y, _z)); + } List allNodes = new ArrayList<>(); allNodes.add(x); @@ -238,8 +247,10 @@ public IndependenceResult checkIndependence(Node x, Node y, Set _z) { } } - return new IndependenceResult(new IndependenceFact(x, y, _z), + IndependenceResult result = new IndependenceResult(new IndependenceFact(x, y, _z), independent, pValue, alpha - pValue); + facts.put(new IndependenceFact(x, y, _z), result); + return result; } /** diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestFisherZ.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestFisherZ.java index 729eda85e7..04bbe5379b 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestFisherZ.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestFisherZ.java @@ -25,12 +25,10 @@ import edu.cmu.tetrad.graph.IndependenceFact; import edu.cmu.tetrad.graph.Node; import edu.cmu.tetrad.search.IndependenceTest; -import edu.cmu.tetrad.search.utils.GraphSearchUtils; +import edu.cmu.tetrad.search.score.SemBicScore; import edu.cmu.tetrad.search.utils.LogUtilsSearch; -import edu.cmu.tetrad.util.Matrix; -import edu.cmu.tetrad.util.MatrixUtils; -import edu.cmu.tetrad.util.StatUtils; -import edu.cmu.tetrad.util.TetradLogger; +import edu.cmu.tetrad.util.Vector; +import edu.cmu.tetrad.util.*; import org.apache.commons.math3.distribution.NormalDistribution; import org.apache.commons.math3.linear.SingularMatrixException; import org.apache.commons.math3.util.FastMath; @@ -50,18 +48,35 @@ * @author josephramsey * @author Frank Wimberly */ -public final class IndTestFisherZ implements IndependenceTest { +public final class IndTestFisherZ implements IndependenceTest, RowsSettable { + // A hash from variable names to indices. private final Map indexMap; + // A hash from variable names to variables. private final Map nameMap; - private final NormalDistribution normal = new NormalDistribution(0, 1, 1e-15); + // The standard normal distribution. + private final NormalDistribution normal = new NormalDistribution(0, 1); + // The variables of the covariance data, in order. (Unmodifiable list.) private final Map nodesHash; + // A cache of results for independence facts. + private final Map facts = new ConcurrentHashMap<>(); + // The correlation matrix. private ICovarianceMatrix cor = null; + // The variables of the covariance data, in order. (Unmodifiable list.) private List variables; + // The significance level of the independence tests. private double alpha; + // Stores a reference to the data set passed in through the constructor. private DataSet dataSet; + // Matrix from of the data. + private Matrix data; + // True if verbose output should be printed. private boolean verbose = true; - // private double p = Double.NaN; + // The correlation coefficient for the last test. private double r = Double.NaN; + // The rows used in the test. + private List rows = null; + // Use pseudoinverse instead of correlation matrix. + private boolean usePseudoinverse = false; /** @@ -93,8 +108,6 @@ public IndTestFisherZ(DataSet dataSet, double alpha) { this.nodesHash = nodesHash; } else { -// this.cor = new CorrelationMatrix(dataSet); - if (!(alpha >= 0 && alpha <= 1)) { throw new IllegalArgumentException("Alpha mut be in [0, 1]"); } @@ -163,7 +176,6 @@ public IndTestFisherZ(ICovarianceMatrix covMatrix, double alpha) { this.nodesHash = nodesHash; } - /** * Creates a new independence test instance for a subset of the variables. * @@ -202,29 +214,132 @@ public IndependenceTest indTestSubset(List vars) { * @see IndependenceResult */ public IndependenceResult checkIndependence(Node x, Node y, Set z) { - double p = Double.NaN; + if (facts.containsKey(new IndependenceFact(x, y, z))) { + return facts.get(new IndependenceFact(x, y, z)); + } + + if (usePseudoinverse) { + IndependenceResult result = checkIndependencePseudoinverse(x, y, z); + facts.put(new IndependenceFact(x, y, z), result); + return result; + } else { // Use inverse. - try { - p = getPValue(x, y, z); - } catch (SingularMatrixException e) { - throw new RuntimeException("Singular matrix encountered for test: " + LogUtilsSearch.independenceFact(x, y, z)); + double p; + + try { + p = getPValue(x, y, z); + } catch (SingularMatrixException e) { + throw new RuntimeException("Singular matrix encountered for test: " + LogUtilsSearch.independenceFact(x, y, z)); + } + + boolean independent = p > this.alpha; + + if (this.verbose) { + if (independent) { + TetradLogger.getInstance().forceLogMessage( + LogUtilsSearch.independenceFactMsg(x, y, z, p)); + } + } + + if (Double.isNaN(p)) { + throw new RuntimeException("Undefined p-value encountered in for test: " + LogUtilsSearch.independenceFact(x, y, z)); + } else { + IndependenceResult result = new IndependenceResult(new IndependenceFact(x, y, z), independent, p, alpha - p); + facts.put(new IndependenceFact(x, y, z), result); + return result; + } } + } - boolean independent = p > this.alpha; + /** + * Determines whether variable x is independent of variable y given a list of conditioning variables z. + * + * @param xVar the one variable being compared. + * @param yVar the second variable being compared. + * @param _z the list of conditioning variables. + * @return True iff x _||_ y | z. + * @throws RuntimeException if a matrix singularity is encountered. + */ + private IndependenceResult checkIndependencePseudoinverse(Node xVar, Node yVar, Set _z) { - if (this.verbose) { - if (independent) { - TetradLogger.getInstance().forceLogMessage( - LogUtilsSearch.independenceFactMsg(x, y, z, p)); + if (this.data == null) this.data = dataSet.getDoubleData(); + + if (_z == null) { + throw new NullPointerException(); + } + + for (Node node : _z) { + if (node == null) { + throw new NullPointerException(); } } - if (Double.isNaN(p)) { - throw new RuntimeException("Undefined p-value encountered in for test: " + LogUtilsSearch.independenceFact(x, y, z)); + List z = new ArrayList<>(_z); + Collections.sort(z); + + int size = z.size(); + int[] zCols = new int[size]; + + int xIndex = getVariables().indexOf(xVar); + int yIndex = getVariables().indexOf(yVar); + + for (int i = 0; i < z.size(); i++) { + zCols[i] = getVariables().indexOf(z.get(i)); + } + + int[] rows; + + if (this.rows == null) { + rows = new int[this.data.getNumRows()]; + for (int i = 0; i < rows.length; i++) { + rows[i] = i; + } } else { - return new IndependenceResult(new IndependenceFact(x, y, z), - independent, p, alpha - p); + rows = new int[this.rows.size()]; + for (int i = 0; i < rows.length; i++) { + rows[i] = this.rows.get(i); + } } + + Vector x = this.data.getSelection(rows, new int[]{xIndex}).getColumn(0); + Vector y = this.data.getSelection(rows, new int[]{yIndex}).getColumn(0); + + CovarianceMatrix cov = new CovarianceMatrix(dataSet); + + SemBicScore.CovAndCoefs covAndCoefsX = SemBicScore.getCovAndCoefs(xIndex, zCols, this.data, + cov, true, this.rows); + SemBicScore.CovAndCoefs covAndCoefsY = SemBicScore.getCovAndCoefs(yIndex, zCols, this.data, + cov, true, this.rows); + + Matrix selection = data.getSelection(rows, zCols); + edu.cmu.tetrad.util.Vector xPred = selection.times(covAndCoefsX.b()).getColumn(0); + edu.cmu.tetrad.util.Vector yPred = selection.times(covAndCoefsY.b()).getColumn(0); + + Vector xRes = xPred.minus(x); + Vector yRes = yPred.minus(y); + + // Note that r will be NaN if either xRes or yRes is constant. + double r = StatUtils.correlation(xRes.toArray(), yRes.toArray()); + + double fisherZ = FastMath.sqrt(rows.length - z.size() - 3.0) * + 0.5 * (FastMath.log(1.0 + r) - FastMath.log(1.0 - r)); + + double p = 2 * (1.0 - this.normal.cumulativeProbability(abs(fisherZ))); + + if (Double.isNaN(fisherZ)) { + throw new IllegalArgumentException("The Fisher's Z " + + "score for independence fact " + xVar + " _||_ " + yVar + + " | " + z + " is undefined."); + } + + + if (this.verbose) { + if (p > alpha) { + TetradLogger.getInstance().forceLogMessage(LogUtilsSearch.independenceFactMsg(xVar, yVar, _z, p)); + } + } + + return new IndependenceResult(new IndependenceFact(xVar, yVar, _z), p > alpha, p, getAlpha() - p); } /** @@ -357,7 +472,8 @@ public List getDataSets() { */ @Override public int getSampleSize() { - return this.cor.getSampleSize(); + if (dataSet != null) return dataSet.getNumRows(); + else return this.cor.getSampleSize(); } /** @@ -392,28 +508,121 @@ public String toString() { * @param x The conditioned variable. */ public boolean determines(List z, Node x) throws UnsupportedOperationException { - int[] parents = new int[z.size()]; + if (usePseudoinverse) { + return determinesPseudoinverse(z, x); + } else { + + int[] parents = new int[z.size()]; + + for (int j = 0; j < parents.length; j++) { + parents[j] = indexMap.get(z.get(j).getName()); + } + + if (parents.length > 0) { + + // Regress z onto i, yielding regression coefficients b. + Matrix Czz = this.cor.getSelection(parents, parents); + + try { + Czz.inverse(); + } catch (SingularMatrixException e) { + System.out.println(LogUtilsSearch.determinismDetected(new HashSet<>(z), x)); + return true; + } + } - for (int j = 0; j < parents.length; j++) { - parents[j] = indexMap.get(z.get(j).getName()); + return false; } + } - if (parents.length > 0) { + /** + * Returns true just in case the varialbe in zList determine xVar. + * + * @return True, if so. + */ + private boolean determinesPseudoinverse(List zList, Node xVar) { + if (zList == null) { + throw new NullPointerException(); + } - // Regress z onto i, yielding regression coefficients b. - Matrix Czz = this.cor.getSelection(parents, parents); + if (zList.isEmpty()) { + return false; + } - try { - Czz.inverse(); - } catch (SingularMatrixException e) { - System.out.println(LogUtilsSearch.determinismDetected(new HashSet<>(z), x)); - return true; + for (Node node : zList) { + if (node == null) { + throw new NullPointerException(); } } - return false; + int size = zList.size(); + int[] zCols = new int[size]; + + int xIndex = getVariables().indexOf(xVar); + Vector x = this.data.getColumn(xIndex); + + for (int i = 0; i < zList.size(); i++) { + zCols[i] = getVariables().indexOf(zList.get(i)); + } + + CovarianceMatrix cov = new CovarianceMatrix(dataSet); + + int[] rows; + + if (this.rows == null) { + rows = new int[this.data.getNumRows()]; + for (int i = 0; i < rows.length; i++) { + rows[i] = i; + } + } else { + rows = new int[this.rows.size()]; + for (int i = 0; i < rows.length; i++) { + rows[i] = this.rows.get(i); + } + } + + SemBicScore.CovAndCoefs covAndCoefsX = SemBicScore.getCovAndCoefs(xIndex, zCols, this.data, + cov, true, this.rows); + + Matrix selection = data.getSelection(rows, zCols); + Vector xPred = selection.times(covAndCoefsX.b()).getColumn(0); + Vector xRes = xPred.minus(x); + + double SSE = 0; + + for (int i = 0; i < xRes.size(); i++) { + SSE += xRes.get(i) * xRes.get(i); + } + + double variance = SSE / (this.data.getNumRows() - (zList.size() + 1)); + + boolean determined = variance < getAlpha(); + + if (determined) { + StringBuilder sb = new StringBuilder(); + sb.append("Determination found: ").append(xVar).append( + " is determined by {"); + + for (int i = 0; i < zList.size(); i++) { + sb.append(zList.get(i)); + + if (i < zList.size() - 1) { + sb.append(", "); + } + } + + sb.append("}"); + + sb.append(" SSE = ").append(NumberFormatUtil.getInstance().getNumberFormat().format(SSE)); + + TetradLogger.getInstance().log("independencies", sb.toString()); + System.out.println(sb); + } + + return determined; } + private double partialCorrelation(Node x, Node y, Set _z, List rows) throws SingularMatrixException { List z = new ArrayList<>(_z); Collections.sort(z); @@ -470,7 +679,8 @@ private double getR(Node x, Node y, Set z, List rows) { } private int sampleSize() { - return covMatrix().getSampleSize(); + if (dataSet != null) return dataSet.getNumRows(); + else return covMatrix().getSampleSize(); } private ICovarianceMatrix covMatrix() { @@ -498,6 +708,10 @@ private Map indexMap(List variables) { } private List getRows(List allVars, Map nodesHash) { + if (this.rows != null) { + return this.rows; + } + List rows = new ArrayList<>(); K: @@ -511,6 +725,40 @@ private List getRows(List allVars, Map nodesHash) return rows; } + + /** + * Returns the rows used in the test. + * + * @return The rows used in the test. + */ + public List getRows() { + return rows; + } + + /** + * Allows the user to set which rows are used in the test. Otherwise, all rows are used, except those with missing + * values. + * + * @param rows The rows to use. + */ + public void setRows(List rows) { + if (dataSet == null) { + return; + } + + for (Integer row : rows) { + if (row < 0 || row >= sampleSize()) { + throw new IllegalArgumentException("Row index out of bounds."); + } + } + + this.rows = rows; + cor = null; + } + + public void setUsePseudoinverse(boolean usePseudoinverse) { + this.usePseudoinverse = usePseudoinverse; + } } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestFisherZConcatenateResiduals.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestFisherZConcatenateResiduals.java index b422a41d22..682a73210a 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestFisherZConcatenateResiduals.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestFisherZConcatenateResiduals.java @@ -37,7 +37,9 @@ import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; /** * Calculates independence from pooled residuals using the Fisher Z method. @@ -47,26 +49,17 @@ */ public final class IndTestFisherZConcatenateResiduals implements IndependenceTest { - - /** - * The variables of the covariance matrix, in order. (Unmodifiable list.) - */ + // The variables of the covariance matrix, in order. (Unmodifiable list.) private final List variables; - + // The regressions. private final ArrayList regressions; - + // A cache of results for independence facts. + private final Map facts = new ConcurrentHashMap<>(); + // The data sets. private List dataSets; - - /** - * The significance level of the independence tests. - */ + // The significance level of the independence tests. private double alpha; - /** - * The value of the Fisher's Z statistic associated with the last calculated partial correlation. - */ -// private double fisherZ; - - private double pValue = Double.NaN; + // True if verbose output should be printed. private boolean verbose; /** @@ -117,6 +110,9 @@ public IndependenceTest indTestSubset(List vars) { * @see IndependenceResult */ public IndependenceResult checkIndependence(Node x, Node y, Set _z) { + if (facts.containsKey(new IndependenceFact(x, y, _z))) { + return facts.get(new IndependenceFact(x, y, _z)); + } x = getVariable(this.variables, x.getName()); List z = GraphUtils.replaceNodes(new ArrayList<>(_z), new ArrayList<>(this.variables)); @@ -169,18 +165,18 @@ public IndependenceResult checkIndependence(Node x, Node y, Set _z) { throw new RuntimeException("Undefined p-value encountered for test: " + LogUtilsSearch.independenceFact(x, y, _z)); } - this.pValue = pValue; boolean independent = pValue > this.alpha; if (this.verbose) { if (independent) { TetradLogger.getInstance().forceLogMessage( - LogUtilsSearch.independenceFactMsg(x, y, _z, this.pValue)); + LogUtilsSearch.independenceFactMsg(x, y, _z, pValue)); } } - return new IndependenceResult(new IndependenceFact(x, y, _z), independent, pValue, pValue - getAlpha()); - + IndependenceResult result = new IndependenceResult(new IndependenceFact(x, y, _z), independent, pValue, pValue - getAlpha()); + facts.put(new IndependenceFact(x, y, _z), result); + return result; } /** diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestFisherZFisherPValue.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestFisherZFisherPValue.java index 59381346e2..e6a5830bc4 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestFisherZFisherPValue.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestFisherZFisherPValue.java @@ -21,7 +21,10 @@ package edu.cmu.tetrad.search.test; -import edu.cmu.tetrad.data.*; +import edu.cmu.tetrad.data.CovarianceMatrix; +import edu.cmu.tetrad.data.DataSet; +import edu.cmu.tetrad.data.DataTransforms; +import edu.cmu.tetrad.data.ICovarianceMatrix; import edu.cmu.tetrad.graph.IndependenceFact; import edu.cmu.tetrad.graph.Node; import edu.cmu.tetrad.search.IndependenceTest; @@ -33,30 +36,38 @@ import org.apache.commons.math3.linear.SingularMatrixException; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import static org.apache.commons.math3.util.FastMath.*; /** - *

Calculates independence from multiple datasets from using the Fisher method - * of pooling independence results. See this paper for details:

- * - *

Tillman, R. E., & Eberhardt, F. (2014). Learning causal structure from - * multiple datasets with similar variable sets. Behaviormetrika, 41(1), 41-64.

+ * Calculates independence from multiple datasets from using the Fisher method of pooling independence results. See this + * paper for details: + *

+ * Tillman, R. E., & Eberhardt, F. (2014). Learning causal structure from multiple datasets with similar variable + * sets. Behaviormetrika, 41(1), 41-64. * * @author robertillman * @author josephramsey */ public final class IndTestFisherZFisherPValue implements IndependenceTest { + // The variables of the covariance data, in order. (Unmodifiable list.) private final List variables; + // The number of samples in each dataset. private final int sampleSize; + // The datasets. private final List dataSets; + // The covariance matrices of the datasets. private final List ncov; - private final Map variablesMap; + // A hash of nodes to indices. + private final Map nodesMap; + // A cache of results for independence facts. + private final Map facts = new ConcurrentHashMap<>(); + // The significance level of the independence tests. private double alpha; - private double pValue = Double.NaN; + // True if verbose output should be printed. private boolean verbose; - /** * Constructor. * @@ -74,9 +85,9 @@ public IndTestFisherZFisherPValue(List dataSets, double alpha) { } this.variables = dataSets.get(0).getVariables(); - this.variablesMap = new HashMap<>(); + this.nodesMap = new HashMap<>(); for (int i = 0; i < this.variables.size(); i++) { - this.variablesMap.put(this.variables.get(i), i); + this.nodesMap.put(this.variables.get(i), i); } for (DataSet dataSet : dataSets) { @@ -103,15 +114,19 @@ public IndependenceTest indTestSubset(List vars) { * @throws RuntimeException if a matrix singularity is encountered. */ public IndependenceResult checkIndependence(Node x, Node y, Set _z) { + if (facts.containsKey(new IndependenceFact(x, y, _z))) { + return facts.get(new IndependenceFact(x, y, _z)); + } + try { List z = new ArrayList<>(); Collections.sort(z); int[] all = new int[z.size() + 2]; - all[0] = this.variablesMap.get(x); - all[1] = this.variablesMap.get(y); + all[0] = this.nodesMap.get(x); + all[1] = this.nodesMap.get(y); for (int i = 0; i < z.size(); i++) { - all[i + 2] = this.variablesMap.get(z.get(i)); + all[i + 2] = this.nodesMap.get(z.get(i)); } List pValues = new ArrayList<>(); @@ -152,19 +167,19 @@ public IndependenceResult checkIndependence(Node x, Node y, Set _z) { throw new RuntimeException("Undefined p-value encountered for test: " + LogUtilsSearch.independenceFact(x, y, _z)); } - this.pValue = p; - boolean independent = p > this.alpha; if (this.verbose) { if (independent) { TetradLogger.getInstance().forceLogMessage( - LogUtilsSearch.independenceFactMsg(x, y, _z, this.pValue)); + LogUtilsSearch.independenceFactMsg(x, y, _z, p)); } } - return new IndependenceResult(new IndependenceFact(x, y, _z), independent, p, getAlpha() - p); + IndependenceResult result = new IndependenceResult(new IndependenceFact(x, y, _z), independent, p, getAlpha() - p); + facts.put(new IndependenceFact(x, y, _z), result); + return result; } catch (SingularMatrixException e) { throw new RuntimeException("Singularity encountered when testing " + LogUtilsSearch.independenceFact(x, y, _z)); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestGSquare.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestGSquare.java index 0c847c44ce..16e30aaf39 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestGSquare.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestGSquare.java @@ -30,10 +30,8 @@ import edu.cmu.tetrad.util.TetradLogger; import java.text.NumberFormat; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Set; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; /** * Checks the conditional independence X _||_ Y | S, where S is a set of discrete variable, and X and Y are discrete @@ -42,40 +40,35 @@ * equivalent to the formulation on page 142 of Fienberg. * * @author josephramsey - * @see GSquareTest + * @see ChiSquareTest */ -public final class IndTestGSquare implements IndependenceTest { +public final class IndTestGSquare implements IndependenceTest, RowsSettable { - /** - * The standard number formatter for Tetrad. - */ + // The standard number formatter for Tetrad. private static final NumberFormat nf = NumberFormatUtil.getInstance().getNumberFormat(); - /** - * The G Square tester. - */ - private final GSquareTest gSquareTest; - /** - * The variables in the discrete data sets or which conditional independence judgements are desired. - */ + // The G Square tester. + private final ChiSquareTest gSquareTest; + // The variables in the discrete data sets or which conditional independence judgements are desired. private final List variables; - /** - * The dataset of discrete variables. - */ + // The dataset of discrete variables. private final DataSet dataSet; - /** - * The significance level for the test. - */ + // The significance level for the test. private final double alpha; - /** - * The p value associated with the most recent call of isIndependent. - */ + // A cache of results for independence facts. + private final Map facts = new ConcurrentHashMap<>(); + // The p value associated with the most recent call of isIndependent. private double pValue; - /** - * The lower bound of percentages of observation of some category in the data, given some particular combination of - * values of conditioning variables, that coefs as 'determining." - */ + // The lower bound of percentages of observation of some category in the data, given some particular combination of + // values of conditioning variables, that coefs as 'determining.' private double determinationP = 0.99; + // True if verbose output should be printed. private boolean verbose; + // The minimum expected number of counts per conditional table for chi-square for that table and its degrees of + // freedom to be included in the overall chi-square and degrees of freedom. Note that this should not be too small, + // or the chi-square distribution will not be a good approximation to the distribution of the test statistic. + private double minCountPerCell = 1.0; + // The rows to use for the test. If null, all rows are used. + private List rows = null; /** * Constructs a new independence checker to check conditional independence facts for discrete data using a g square @@ -101,7 +94,8 @@ public IndTestGSquare(DataSet dataSet, double alpha) { this.alpha = alpha; this.variables = new ArrayList<>(dataSet.getVariables()); - this.gSquareTest = new GSquareTest(dataSet, alpha); + this.gSquareTest = new ChiSquareTest(dataSet, alpha, ChiSquareTest.TestType.G_SQUARE); + this.gSquareTest.setMinCountPerCell(minCountPerCell); } /** @@ -147,16 +141,8 @@ public double getPValue() { * @return True iff x _||_ y | z. */ public IndependenceResult checkIndependence(Node x, Node y, Set _z) { - if (x == null) { - throw new NullPointerException(); - } - - if (y == null) { - throw new NullPointerException(); - } - - if (_z == null) { - throw new NullPointerException(); + if (this.facts.containsKey(new IndependenceFact(x, y, _z))) { + return facts.get(new IndependenceFact(x, y, _z)); } for (Node node : _z) { @@ -165,6 +151,7 @@ public IndependenceResult checkIndependence(Node x, Node y, Set _z) { } } + List z = new ArrayList<>(_z); Collections.sort(z); @@ -187,16 +174,9 @@ public IndependenceResult checkIndependence(Node x, Node y, Set _z) { } } - // System.out.println("Testing " + x + " _||_ " + y + " | " + z); - - GSquareTest.Result result = this.gSquareTest.calcGSquare(testIndices); + ChiSquareTest.Result result = this.gSquareTest.calcChiSquare(testIndices); this.pValue = result.getPValue(); - if (Double.isNaN(this.pValue)) { - throw new RuntimeException("Undefined p-value encountered when testing " + - LogUtilsSearch.independenceFact(x, y, _z)); - } - if (this.verbose) { if (result.isIndep()) { TetradLogger.getInstance().forceLogMessage( @@ -204,8 +184,10 @@ public IndependenceResult checkIndependence(Node x, Node y, Set _z) { } } - return new IndependenceResult(new IndependenceFact(x, y, _z), + IndependenceResult result1 = new IndependenceResult(new IndependenceFact(x, y, _z), result.isIndep(), result.getPValue(), alpha - result.getPValue()); + facts.put(new IndependenceFact(x, y, _z), result1); + return result1; } /** @@ -228,7 +210,7 @@ public void setAlpha(double alpha) { } /** - * Return the list of variables over which this independence checker is capable of determinine independence + * Return the list of variables over which this independence checker is capable of determining independence * relations-- that is, all the variables in the given graph or the given data set. * * @return This list. @@ -311,7 +293,7 @@ public boolean determines(Set _z, Node x) { } /** - * Sets the threshold for making judgments of detemrination. + * Sets the threshold for making judgments of determination. * * @param determinationP This threshold. */ @@ -347,6 +329,50 @@ public boolean isVerbose() { public void setVerbose(boolean verbose) { this.verbose = verbose; } + + /** + * The minimum number of counts per conditional table for chi-square for that table and its degrees of freedom to be + * included in the overall chi-square and degrees of freedom. Note that this should not be too small, or the + * chi-square distribution will not be a good approximation to the distribution of the test statistic. + * + * @param minCountPerCell The minimum number of counts per conditional table. The default is 1; this must be >= 0. + */ + public void setMinCountPerCell(double minCountPerCell) { + this.minCountPerCell = minCountPerCell; + this.gSquareTest.setMinCountPerCell(minCountPerCell); + } + + /** + * Returns the rows used for the test. If null, all rows are used. + * + * @return The rows used for the test. Can be null. + */ + @Override + public List getRows() { + return new ArrayList<>(rows); + } + + /** + * Sets the rows to use for the test. If null, all rows are used. + * + * @param rows The rows to use for the test. Can be null. + */ + @Override + public void setRows(List rows) { + if (rows == null) { + this.rows = null; + gSquareTest.setRows(null); + } else { + for (int i : rows) { + if (i < 0 || i >= dataSet.getNumRows()) { + throw new IllegalArgumentException("Row " + i + " is out of bounds."); + } + } + + this.rows = new ArrayList<>(rows); + gSquareTest.setRows(this.rows); + } + } } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestHsic.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestHsic.java index 5f046e23c8..39b7c3fb6f 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestHsic.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestHsic.java @@ -39,18 +39,15 @@ import org.apache.commons.math3.util.FastMath; import java.text.NumberFormat; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Set; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; /** - *

Checks the conditional independence X _||_ Y | S, where S is a set of continuous variable, - * and X and Y are discrete variable not in S, using the Hilbert-Schmidth Independence Criterion (HSIC), a kernel based - * nonparametric test for conditional independence.

- * - *

The Kpc algorithm by Tillman had run PC using this test; to run Kpc, simply select this test - * for PC.

+ * Checks the conditional independence X _||_ Y | S, where S is a set of continuous variable, and X and Y are discrete + * variable not in S, using the Hilbert-Schmidth Independence Criterion (HSIC), a kernel based nonparametric test for + * conditional independence. + *

+ * The Kpc algorithm by Tillman had run PC using this test; to run Kpc, simply select this test for PC. * * @author Robert Tillman * @see edu.cmu.tetrad.search.work_in_progress.Kpc @@ -58,45 +55,27 @@ public final class IndTestHsic implements IndependenceTest { - /** - * Formats as 0.0000. - */ + // Number format for printing p-values. private static final NumberFormat nf = NumberFormatUtil.getInstance().getNumberFormat(); - /** - * The variables of the covariance matrix, in order. (Unmodifiable list.) - */ + // The variables of the covariance matrix, in order. (Unmodifiable list.) private final List variables; - /** - * Stores a reference to the dataset being analyzed. - */ + // Stores a reference to the dataset being analyzed. private final DataSet dataSet; - /** - * The significance level of the independence tests. - */ + // A cache of results for independence facts. + private final Map facts = new ConcurrentHashMap<>(); + // The significance level of the independence tests. private double alpha; - /** - * The cutoff value for 'alpha' - */ + // The cutoff value for 'alpha' private double thresh = Double.NaN; - /** - * A stored p value, if the deterministic test was used. - */ + // A stored p value, if the deterministic test was used. private double pValue = Double.NaN; - - /** - * The regularizer - */ + // The regularizer private double regularizer = 0.0001; - - /** - * Number of permutations to approximate the null distribution - */ + // Number of permutations to approximate the null distribution private int perms = 100; - - /** - * Use incomplete Choleksy decomposition to calculate Gram matrices - */ + // Use incomplete Choleksy decomposition to calculate Gram matrices private double useIncompleteCholesky = 1e-18; + // Whether to print verbose output. private boolean verbose; @@ -172,6 +151,10 @@ public IndependenceTest indTestSubset(List vars) { * @return True iff x _||_ y | z. */ public IndependenceResult checkIndependence(Node y, Node x, Set _z) { + if (facts.containsKey(new IndependenceFact(x, y, _z))) { + return facts.get(new IndependenceFact(x, y, _z)); + } + List z = new ArrayList<>(_z); Collections.sort(z); @@ -339,7 +322,9 @@ public IndependenceResult checkIndependence(Node y, Node x, Set _z) { } } - return new IndependenceResult(new IndependenceFact(x, y, _z), independent, this.pValue, alpha - pValue); + IndependenceResult result = new IndependenceResult(new IndependenceFact(x, y, _z), independent, this.pValue, alpha - pValue); + facts.put(new IndependenceFact(x, y, _z), result); + return result; } /** diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestMulti.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestMulti.java index 4eb3437c22..bc52d099e8 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestMulti.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestMulti.java @@ -31,7 +31,9 @@ import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; /** * Pools together a set of independence tests using a specified method. @@ -40,26 +42,24 @@ */ public final class IndTestMulti implements IndependenceTest { - - /** - * The variables of the covariance matrix, in order. (Unmodifiable list.) - */ + // The variables of the covariance matrix, in order. (Unmodifiable list.) private final List variables; - - /** - * The independence test associated with each data set. - */ + // The independence test associated with each data set. private final List independenceTests; - - /** - * Pooling method - */ + // Pooling method private final ResolveSepsets.Method method; + // A cache of results for independence facts. + private final Map facts = new ConcurrentHashMap<>(); + // True if verbose output should be printed. private boolean verbose; -// private DataSet concatenatedData; - - + /** + * Constructs a new pooled independence test for the given data sets. + * + * @param independenceTests the independence tests to pool. + * @param method the method to use for pooling. + * @see ResolveSepsets.Method + */ public IndTestMulti(List independenceTests, ResolveSepsets.Method method) { Set nodeNames = new HashSet<>(); for (IndependenceTest independenceTest : independenceTests) { @@ -73,7 +73,9 @@ public IndTestMulti(List independenceTests, ResolveSepsets.Met this.method = method; } - + /** + * @throws UnsupportedOperationException Method not implemented. + */ public IndependenceTest indTestSubset(List vars) { throw new UnsupportedOperationException(); } @@ -88,6 +90,10 @@ public IndependenceTest indTestSubset(List vars) { * @throws RuntimeException if a matrix singularity is encountered. */ public IndependenceResult checkIndependence(Node x, Node y, Set z) { + if (facts.containsKey(new IndependenceFact(x, y, z))) { + return facts.get(new IndependenceFact(x, y, z)); + } + boolean independent = ResolveSepsets.isIndependentPooled(this.method, this.independenceTests, x, y, z); if (independent) { @@ -96,7 +102,10 @@ public IndependenceResult checkIndependence(Node x, Node y, Set z) { TetradLogger.getInstance().log("dependencies", "In aggregate dependent: " + LogUtilsSearch.independenceFact(x, y, z)); } - return new IndependenceResult(new IndependenceFact(x, y, z), independent, Double.NaN, Double.NaN); + IndependenceResult result = new IndependenceResult(new IndependenceFact(x, y, z), independent, + Double.NaN, Double.NaN); + facts.put(new IndependenceFact(x, y, z), result); + return result; } /** diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestMvpLrt.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestMvpLrt.java index ba1e962108..7a46de25eb 100755 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestMvpLrt.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestMvpLrt.java @@ -33,23 +33,30 @@ import org.apache.commons.math3.util.FastMath; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; /** - *

Performs a test of conditional independence X _||_ Y | Z1...Zn where all - * variables are either continuous or discrete. This test is valid for both ordinal and non-ordinal discrete - * searchVariables.

- * - *

Andrews, B., Ramsey, J., & Cooper, G. F. (2018). Scoring Bayesian networks of - * mixed variables. International journal of data science and analytics, 6, 3-18.

+ * Performs a test of conditional independence X _||_ Y | Z1...Zn where all variables are either continuous or discrete. + * This test is valid for both ordinal and non-ordinal discrete searchVariables. + *

+ * Andrews, B., Ramsey, J., & Cooper, G. F. (2018). Scoring Bayesian networks of mixed variables. International + * journal of data science and analytics, 6, 3-18. * * @author Bryan Andrews */ public class IndTestMvpLrt implements IndependenceTest { + + // The data set. private final DataSet data; + // A hash of nodes to indices. private final Map nodesHash; // Likelihood function private final MvpLikelihood likelihood; + // A cache of results for independence facts. + private final Map facts = new ConcurrentHashMap<>(); + // The significance level of the independence tests. private double alpha; + // True if verbose output should be printed. private boolean verbose; /** @@ -63,9 +70,7 @@ public class IndTestMvpLrt implements IndependenceTest { public IndTestMvpLrt(DataSet data, double alpha, int fDegree, boolean discretize) { this.data = data; this.likelihood = new MvpLikelihood(data, -1, fDegree, discretize); - this.nodesHash = new HashedMap<>(); - List variables = data.getVariables(); for (int i = 0; i < variables.size(); i++) { @@ -92,6 +97,10 @@ public IndependenceTest indTestSubset(List vars) { * @see IndependenceResult */ public IndependenceResult checkIndependence(Node x, Node y, Set _z) { + if (facts.containsKey(new IndependenceFact(x, y, _z))) { + return facts.get(new IndependenceFact(x, y, _z)); + } + List z = new ArrayList<>(_z); Collections.sort(z); @@ -132,12 +141,12 @@ public IndependenceResult checkIndependence(Node x, Node y, Set _z) { try { p_0 = 1.0 - new ChiSquaredDistribution(dof_0).cumulativeProbability(2.0 * lik_0); } catch (Exception e) { - e.printStackTrace(); + TetradLogger.getInstance().forceLogMessage(e.getMessage()); } try { p_1 = 1.0 - new ChiSquaredDistribution(dof_1).cumulativeProbability(2.0 * lik_1); } catch (Exception e) { - e.printStackTrace(); + TetradLogger.getInstance().forceLogMessage(e.getMessage()); } double pValue = FastMath.min(p_0, p_1); @@ -156,7 +165,10 @@ public IndependenceResult checkIndependence(Node x, Node y, Set _z) { } } - return new IndependenceResult(new IndependenceFact(x, y, _z), independent, pValue, alpha - pValue); + IndependenceResult result = new IndependenceResult(new IndependenceFact(x, y, _z), independent, pValue, + alpha - pValue); + facts.put(new IndependenceFact(x, y, _z), result); + return result; } /** diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestProbabilistic.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestProbabilistic.java index 64e7c64172..0d567239f8 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestProbabilistic.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestProbabilistic.java @@ -34,6 +34,7 @@ import edu.pitt.dbmi.algo.bayesian.constraint.inference.BCInference; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; /** * Uses BCInference by Cooper and Bui to calculate probabilistic conditional independence judgments. @@ -42,33 +43,29 @@ */ public class IndTestProbabilistic implements IndependenceTest { - /** - * The data set for which conditional independence judgments are requested. - */ + // A cache of results for independence facts, used only if threshold is false. + private final Map facts = new ConcurrentHashMap<>(); + //The data set for which conditional independence judgments are requested. private final DataSet data; - /** - * The nodes of the data set. - */ + // The nodes of the data set. private final List nodes; - /** - * Indices of the nodes. - */ + // Indices of the nodes. private final Map indices; - /** - * A map from independence facts to their probabilities of independence. - */ + // A map from independence facts to their probabilities of independence. private final Map H; + // The BCInference object. private final BCInference bci; - /** - * Calculates probabilities of independence for conditional independence facts. - */ + // True if the independence test should be thresholded, false if it should be randomized. private boolean threshold; + // The posterior probability of the last independence test. private double posterior; + // True if verbose output should be printed. private boolean verbose; + // The cutoff for the independence test. private double cutoff = 0.5; + // The prior equivalent sample size. private double priorEquivalentSampleSize = 10; - /** * Initializes the test using a discrete data sets. */ @@ -106,43 +103,50 @@ public IndTestProbabilistic(DataSet dataSet) { this.bci = setup(_data); } - private BCInference setup(DataSet dataSet) { - int[] nodeDimensions = new int[dataSet.getNumColumns() + 2]; - - for (int j = 0; j < dataSet.getNumColumns(); j++) { - DiscreteVariable variable = (DiscreteVariable) (dataSet.getVariable(j)); - int numCategories = variable.getNumCategories(); - nodeDimensions[j + 1] = numCategories; - } - - int[][] cases = new int[dataSet.getNumRows() + 1][dataSet.getNumColumns() + 2]; - - for (int i = 0; i < dataSet.getNumRows(); i++) { - for (int j = 0; j < dataSet.getNumColumns(); j++) { - cases[i + 1][j + 1] = dataSet.getInt(i, j) + 1; - } - } - - BCInference bci = new BCInference(cases, nodeDimensions); - bci.setPriorEqivalentSampleSize(this.priorEquivalentSampleSize); - return bci; - } - + /** + * @throws UnsupportedOperationException Method not implemented. + */ @Override public IndependenceTest indTestSubset(List vars) { throw new UnsupportedOperationException(); } + /** + * Returns an independence result that states whether x _||_y | z and what the p-value of the test is. + * + * @param x The first variable. + * @param y The second variable. + * @param _z The conditioning set. + * @return an independence result (see) + * @see IndependenceResult + */ @Override public IndependenceResult checkIndependence(Node x, Node y, Set _z) { + if (!threshold && facts.containsKey(new IndependenceFact(x, y, _z))) { + return facts.get(new IndependenceFact(x, y, _z)); + } + + // Notice that we do not cache the results of the independence tests here. This is because + // these results have a random component and so caching them would be inappropriate. List z = new ArrayList<>(_z); Collections.sort(z); Node[] nodes = new Node[z.size()]; for (int i = 0; i < z.size(); i++) nodes[i] = z.get(i); - return checkIndependence(x, y, nodes); + IndependenceResult independenceResult = checkIndependence(x, y, nodes); + if (!threshold) facts.put(new IndependenceFact(x, y, _z), independenceResult); + return independenceResult; } + /** + * Returns an independence result that states whether x _||_y | z and what the p-value of the test is. + * + * @param x The first variable. + * @param y The second variable. + * @param z The conditioning set. + * @return an independence result (see) + * @see IndependenceResult + */ @Override public IndependenceResult checkIndependence(Node x, Node y, Node... z) { IndependenceFact key = new IndependenceFact(x, y, z); @@ -222,6 +226,17 @@ public IndependenceResult checkIndependence(Node x, Node y, Node... z) { } + /** + * Returns the probability of the constraint x op y | z. + * + * @param bci The BCInference object. + * @param op The operator. + * @param x The first variable. + * @param y The second variable. + * @param z The conditioning set. + * @param indices A map from nodes to their indices. + * @return The probability. + */ public double probConstraint(BCInference bci, BCInference.OP op, Node x, Node y, Node[] z, Map indices) { int _x = indices.get(x) + 1; @@ -236,11 +251,18 @@ public double probConstraint(BCInference bci, BCInference.OP op, Node x, Node y, return bci.probConstraint(op, _x, _y, _z); } + /** + * Returns the variables of the data set. + * @return The variables. + */ @Override public List getVariables() { return this.nodes; } + /** + * Returns the variable with the given name. + */ @Override public Node getVariable(String name) { for (Node node : this.nodes) { @@ -250,48 +272,85 @@ public Node getVariable(String name) { return null; } + /** + * @throws UnsupportedOperationException Method not implemented. + */ @Override public boolean determines(Set z, Node y) { throw new UnsupportedOperationException(); } + /** + * @throws UnsupportedOperationException Method not implemented. + */ @Override public double getAlpha() { throw new UnsupportedOperationException("The Probabiistic Test doesn't use an alpha parameter"); } + /** + * @throws UnsupportedOperationException Method not implemented. + */ @Override public void setAlpha(double alpha) { throw new UnsupportedOperationException(); } + /** + * Returns the data set for which conditional independence judgments are requested. + * @return The data set. + */ @Override public DataModel getData() { return this.data; } + /** + * Returns a map from independence facts to their probabilities of independence. + * @return The map. + */ public Map getH() { return new HashMap<>(this.H); } + /** + * Returns the posterior probability of the last independence test. + * @return The posterior probability. + */ public double getPosterior() { return this.posterior; } + /** + * Returns true if verbose output should be printed. + * @return True, if so. + */ @Override public boolean isVerbose() { return this.verbose; } + /** + * Sets whether verbose output should be printed. + * @param verbose True, if so. + */ @Override public void setVerbose(boolean verbose) { this.verbose = verbose; } - public void setThreshold(boolean noRandomizedGeneratingConstraints) { - this.threshold = noRandomizedGeneratingConstraints; + /** + * Sets whether the independence test should be thresholded (true) or randomized (false). + * @param threshold true if the independence test should be thresholded, false if it should be randomized. + */ + public void setThreshold(boolean threshold) { + this.threshold = threshold; } + /** + * Sets the cutoff for the independence test. + * @param cutoff the cutoff for the independence test. + */ public void setCutoff(double cutoff) { this.cutoff = cutoff; } @@ -300,6 +359,28 @@ public void setPriorEquivalentSampleSize(double priorEquivalentSampleSize) { this.priorEquivalentSampleSize = priorEquivalentSampleSize; } + private BCInference setup(DataSet dataSet) { + int[] nodeDimensions = new int[dataSet.getNumColumns() + 2]; + + for (int j = 0; j < dataSet.getNumColumns(); j++) { + DiscreteVariable variable = (DiscreteVariable) (dataSet.getVariable(j)); + int numCategories = variable.getNumCategories(); + nodeDimensions[j + 1] = numCategories; + } + + int[][] cases = new int[dataSet.getNumRows() + 1][dataSet.getNumColumns() + 2]; + + for (int i = 0; i < dataSet.getNumRows(); i++) { + for (int j = 0; j < dataSet.getNumColumns(); j++) { + cases[i + 1][j + 1] = dataSet.getInt(i, j) + 1; + } + } + + BCInference bci = new BCInference(cases, nodeDimensions); + bci.setPriorEqivalentSampleSize(this.priorEquivalentSampleSize); + return bci; + } + private List getRows(DataSet dataSet, List allVars, Map nodesHash) { List rows = new ArrayList<>(); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestRegression.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestRegression.java index ce6887a15c..08749fe574 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestRegression.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestRegression.java @@ -39,10 +39,8 @@ import edu.cmu.tetrad.util.TetradLogger; import java.text.NumberFormat; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Set; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; /** * Checks independence of X _||_ Y | Z for variables X and Y and list Z of variables by regressing X on {Y} U Z and @@ -53,29 +51,21 @@ */ public final class IndTestRegression implements IndependenceTest { - /** - * The standard number formatter for Tetrad. - */ + // The standard number formatter for Tetrad. private static final NumberFormat nf = NumberFormatUtil.getInstance().getNumberFormat(); - /** - * The correlation matrix. - */ + // The correlation matrix. private final DoubleMatrix2D data; - /** - * The variables of the correlation matrix, in order. (Unmodifiable list.) - */ + // The variables of the correlation matrix, in order. (Unmodifiable list.) private final List variables; + // The data set. private final DataSet dataSet; - /** - * The significance level of the independence tests. - */ + // The significance level of the independence tests. private double alpha; - /** - * The value of the Fisher's Z statistic associated with the las calculated partial correlation. - */ - private double fishersZ; + // The value of the Fisher's Z statistic associated with the las calculated partial correlation. private boolean verbose; + // A cache of results for independence facts. + private final Map facts = new ConcurrentHashMap<>(); /** * Constructs a new Independence test which checks independence facts based on the correlation matrix implied by the @@ -109,12 +99,12 @@ public IndependenceTest indTestSubset(List vars) { * @param xVar the one variable being compared. * @param yVar the second variable being compared. * @param zList the list of conditioning variables. - * @return true iff x _||_ y | z. + * @return The independence result. * @throws RuntimeException if a matrix singularity is encountered. */ public IndependenceResult checkIndependence(Node xVar, Node yVar, Set zList) { - if (zList == null) { - throw new NullPointerException(); + if (facts.containsKey(new IndependenceFact(xVar, yVar, zList))) { + return facts.get(new IndependenceFact(xVar, yVar, zList)); } for (Node node : zList) { @@ -164,8 +154,10 @@ public IndependenceResult checkIndependence(Node xVar, Node yVar, Set zLis } } - return new IndependenceResult(new IndependenceFact(xVar, yVar, zList), + IndependenceResult result1 = new IndependenceResult(new IndependenceFact(xVar, yVar, zList), independent, p, getAlpha() - p); + facts.put(new IndependenceFact(xVar, yVar, zList), result1); + return result1; } /** @@ -268,14 +260,24 @@ public boolean determines(List zList, Node xVar) { return determined; } + /** + * Returns the data used. + * @return the data used. + */ public DataSet getData() { return this.dataSet; } + /** + * Returns true if the test prints verbose output. + */ public boolean isVerbose() { return this.verbose; } + /** + * Sets whether the test prints verbose output. + */ public void setVerbose(boolean verbose) { this.verbose = verbose; } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestTrekSep.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestTrekSep.java index 285ece87c0..9b79820977 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestTrekSep.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndTestTrekSep.java @@ -41,17 +41,27 @@ * @author Adam Brodie */ public final class IndTestTrekSep implements IndependenceTest { + // The variables of the covariance matrix, in order. (Unmodifiable list.) private static final NumberFormat nf = NumberFormatUtil.getInstance().getNumberFormat(); + // The covariance matrix. private final ICovarianceMatrix covMatrix; + // The latents in order. (Unmodifiable list.) private final List latents; + // The variables clusterings. private final List> clustering; + // A hash of nodes to indices. private final Map indexMap; + // A hash of nodes to names. private final Map nameMap; + // A cache of results for independence facts. + private final Map facts = new ConcurrentHashMap<>(); + // True if verbose output should be printed. private boolean verbose; + // The variables of the covariance matrix, in order. (Unmodifiable list.) private List variables; + // The significance level of the independence tests. private double alpha; - /** * Constructs a new independence test that will determine conditional independence facts using the given correlation * matrix and the given significance level. @@ -112,29 +122,38 @@ public IndependenceTest indTestSubset(List vars) { * @throws org.apache.commons.math3.linear.SingularMatrixException if a matrix singularity is encountered. */ public IndependenceResult checkIndependence(Node x, Node y, Set z) { + if (facts.containsKey(new IndependenceFact(x, y, z))) { + return facts.get(new IndependenceFact(x, y, z)); + } + int n = sampleSize(); int xi = this.latents.indexOf(x); int yi = this.latents.indexOf(y); int nA = this.clustering.get(xi).size(); int nB = this.clustering.get(yi).size(); + for (Node node : z) { int s = this.latents.indexOf(node); int m = this.clustering.get(s).size() / 2; nA += m; nB += m; } + int[] A = new int[nA]; int[] B = new int[nB]; int a = 0; int b = 0; + for (int i = 0; i < this.clustering.get(xi).size(); i++) { A[i] = this.variables.indexOf(this.clustering.get(xi).get(i)); a++; } + for (int i = 0; i < this.clustering.get(yi).size(); i++) { B[i] = this.variables.indexOf(this.clustering.get(yi).get(i)); b++; } + for (Node node : z) { int s = this.latents.indexOf(node); int m = this.clustering.get(s).size() / 2; @@ -146,16 +165,13 @@ public IndependenceResult checkIndependence(Node x, Node y, Set z) { } } - //With one indicator per latent per set. - double[][] CovMatrix = this.covMatrix.getMatrix().toArray(); - - int rank = new EstimateRank().Estimate(A, B, CovMatrix, n, this.alpha); -// return rank <= z.size(); - + int rank = EstimateRank.estimate(A, B, CovMatrix, n, this.alpha); boolean independent = rank <= z.size(); - return new IndependenceResult(new IndependenceFact(x, y, z), independent, Double.NaN, Double.NaN); + final IndependenceResult result = new IndependenceResult(new IndependenceFact(x, y, z), independent, Double.NaN, Double.NaN); + facts.put(new IndependenceFact(x, y, z), result); + return result; } @@ -214,8 +230,7 @@ public Node getVariable(String name) { } /** - * If isDeterminismAllowed(), defers to IndTestFisherZD; otherwise throws - * UnsupportedOperationException. + * If isDeterminismAllowed(), defers to IndTestFisherZD; otherwise throws UnsupportedOperationException. * * @return True if so * @throws UnsupportedOperationException If the above condition is not met. diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndependenceResult.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndependenceResult.java index 8e1740369f..1ca866c5ce 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndependenceResult.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/IndependenceResult.java @@ -7,8 +7,8 @@ import edu.cmu.tetrad.util.TetradSerializableUtils; /** - *

Stores a single conditional independence result, e.g., whether - * X _||_ Y | Z1,..,Zn holds or does not, and the p-value of the test.

+ * Stores a single conditional independence result, e.g., whether X _||_ Y | Z1,..,Zn holds or does not, and the p-value + * of the test. * * @author josephramsey */ @@ -19,20 +19,40 @@ public final class IndependenceResult implements TetradSerializable { private final boolean indep; private final double pValue; private final double score; + private final boolean isValid; /** - * Constructor. + * Constructor. For this constructor, is it assumed that the test is valid. * * @param fact The fact itself. * @param indep The conditional independence result, true if the fact holds, false if not. * @param pValue The p-values of the independence result, under the null (independence) hypothesis. + * @param score The score of the test, which is alpha - p if the test returns a p-value or else a bump if the test + * is based on a score. * @see IndependenceFact */ public IndependenceResult(IndependenceFact fact, boolean indep, double pValue, double score) { + this(fact, indep, pValue, score, true); + } + + /** + * Constructor. For this constructor, the validity of the test is specified. + * + * @param fact The fact itself. + * @param indep The conditional independence result, true if the fact holds, false if not. + * @param pValue The p-values of the independence result, under the null (independence) hypothesis. + * @param score The score of the test, which is alpha - p if the test returns a p-value or else a bump if the test + * is based on a score. + * @param isValid Whether the result is valid or not. A test is not valid if the test is not able to determine + * whether the fact holds or not. + * @see IndependenceFact + */ + public IndependenceResult(IndependenceFact fact, boolean indep, double pValue, double score, boolean isValid) { this.fact = fact; this.indep = indep; this.pValue = pValue; this.score = score; + this.isValid = isValid; } /** @@ -89,7 +109,7 @@ public double getPValue() { } /** - * Returns a string represnetation of this independence fact. + * Returns a string representation of this independence fact. * * @return This string. */ @@ -98,7 +118,23 @@ public String toString() { NumberFormatUtil.getInstance().getNumberFormat().format(getPValue()); } + /** + * Returns the score of the test, which is alpha - p if the test returns a p-value or else a bump if the test is + * based on a score. + * + * @return The score of the test. + */ public double getScore() { return score; } + + /** + * Returns whether the result is valid or not. A test is not valid if the test is not able to determine whether the + * fact holds or not. + * + * @return True if the result is valid, false if not. + */ + public boolean isValid() { + return isValid; + } } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/Kci.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/Kci.java index 47a333f4ee..30c3ec1d5a 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/Kci.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/Kci.java @@ -1,6 +1,9 @@ package edu.cmu.tetrad.search.test; -import edu.cmu.tetrad.data.*; +import edu.cmu.tetrad.data.DataModel; +import edu.cmu.tetrad.data.DataSet; +import edu.cmu.tetrad.data.DataTransforms; +import edu.cmu.tetrad.data.ICovarianceMatrix; import edu.cmu.tetrad.graph.IndependenceFact; import edu.cmu.tetrad.graph.Node; import edu.cmu.tetrad.search.IndependenceTest; @@ -24,18 +27,18 @@ import static org.apache.commons.math3.util.FastMath.*; /*** - *

Gives an implementation of the Kernal Independence Test (KCI) by Kun Zhang, which is a - * general test of conditional independence. The reference is here:

- * - *

Zhang, K., Peters, J., Janzing, D., and Schölkopf, B. (2012). Kernel-based conditional independence - * test and application in causal discovery. arXiv preprint arXiv:1202.3775.

- * - *

Please see that paper, especially Theorem 4 and Proposition 5.

- * - *

Using optimal kernel bandwidths suggested by Bowman and Azzalini (1997):

- * - *

Bowman, A. W., and Azzalini, A. (1997). Applied smoothing techniques for data analysis: the kernel - * approach with S-Plus illustrations (Vol. 18). OUP Oxford.

+ * Gives an implementation of the Kernal Independence Test (KCI) by Kun Zhang, which is a + * general test of conditional independence. The reference is here: + *

+ * Zhang, K., Peters, J., Janzing, D., and Schölkopf, B. (2012). Kernel-based conditional independence + * test and application in causal discovery. arXiv preprint arXiv:1202.3775. + *

+ * Please see that paper, especially Theorem 4 and Proposition 5. + *

+ * Using optimal kernel bandwidths suggested by Bowman and Azzalini (1997): + *

+ * Bowman, A. W., and Azzalini, A. (1997). Applied smoothing techniques for data analysis: the kernel + * approach with S-Plus illustrations (Vol. 18). OUP Oxford. * * @author kunzhang * @author Vineet Raghu on 7/3/2016 @@ -45,7 +48,6 @@ public class Kci implements IndependenceTest { // The supplied data set, standardized private final DataSet data; - // Variables in data private final List variables; private final double[] h; @@ -68,9 +70,8 @@ public class Kci implements IndependenceTest { private double widthMultiplier = 1.0; // Epsilon for Propositio 5. private double epsilon = 0.001; - + // True if verbose output should be printed. private boolean verbose; -// private IndependenceFact latestFact = null; /** * Constructor. @@ -80,7 +81,6 @@ public class Kci implements IndependenceTest { */ public Kci(DataSet data, double alpha) { this.data = DataTransforms.standardizeData(data); -// _data = data.getDoubleData().transpose().toArray(); this.variables = data.getVariables(); int n = this.data.getNumRows(); @@ -121,6 +121,10 @@ public IndependenceTest indTestSubset(List vars) { * @see IndependenceResult */ public IndependenceResult checkIndependence(Node x, Node y, Set z) { + if (facts.containsKey(new IndependenceFact(x, y, z))) { + return facts.get(new IndependenceFact(x, y, z)); + } + try { if (Thread.currentThread().isInterrupted()) { @@ -134,7 +138,6 @@ public IndependenceResult checkIndependence(Node x, Node y, Set z) { allVars.addAll(z); IndependenceFact fact = new IndependenceFact(x, y, z); -// this.latestFact = fact; if (facts.containsKey(fact)) { IndependenceResult result = facts.get(fact); @@ -199,7 +202,10 @@ public IndependenceResult checkIndependence(Node x, Node y, Set z) { IndependenceResult result = facts.get(fact); if (this.facts.get(fact) != null) { - return new IndependenceResult(fact, result.isIndependent(), result.getPValue(), getAlpha() - result.getPValue()); + IndependenceResult result1 = new IndependenceResult(fact, result.isIndependent(), + result.getPValue(), getAlpha() - result.getPValue()); + facts.put(fact, result1); + return result1; } else { if (z.isEmpty()) { result = isIndependentUnconditional(x, y, fact, _data, h, N, hash); @@ -219,7 +225,10 @@ public IndependenceResult checkIndependence(Node x, Node y, Set z) { } } - return new IndependenceResult(fact, result.isIndependent(), result.getPValue(), getAlpha() - result.getPValue()); + IndependenceResult result1 = new IndependenceResult(fact, result.isIndependent(), + result.getPValue(), getAlpha() - result.getPValue()); + facts.put(fact, result1); + return result1; } } catch (SingularMatrixException e) { throw new RuntimeException("Singularity encountered when testing " + diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/MsepTest.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/MsepTest.java index bfc2da94a1..a50b48a604 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/MsepTest.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/MsepTest.java @@ -32,31 +32,30 @@ import edu.cmu.tetrad.util.TetradLogger; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; /** - *

Checks independence facts for variables associated with the nodes in a given graph by - * checking m-separation facts on the underlying nodes. We use the IndependenceTest interface here so that this - * m-separation test can be used in place of a statistical conditional independence test in algorithms to provide oracle - * information.

+ * Checks independence facts for variables associated with the nodes in a given graph by checking m-separation facts on + * the underlying nodes. We use the IndependenceTest interface here so that this m-separation test can be used in place + * of a statistical conditional independence test in algorithms to provide oracle information. * * @author josephramsey */ public class MsepTest implements IndependenceTest { + // A cache of results for independence facts. + private final Map facts = new ConcurrentHashMap<>(); private Map> ancestorMap; private IndependenceFacts independenceFacts; - - /** - * The graph for which this is a variable map. - */ + // The graph for which this is a variable map. private Graph graph; - - /** - * The list of observed variables (i.e. variables for observed nodes). - */ + //The list of observed variables (i.e. variables for observed nodes). private List observedVars; + // The list of translated observed variables (i.e. variables for observed nodes). private List _observedVars; + // Whether verbose output should be printed. private boolean verbose = false; + // The "p-value" of the last test (this is 0 or 1). private double pvalue = 0; /** @@ -73,7 +72,7 @@ public MsepTest(Graph graph) { * Constructor. * * @param facts Independence facts to be used for direct calculations of m-separation. - * @param variables The variables for the facts, if different from those that independenceFacts would return. + * @param variables The variables for the facts, if different from those that independence facts would return. * @see IndependenceFacts */ public MsepTest(IndependenceFacts facts, List variables) { @@ -205,6 +204,10 @@ public IndependenceResult checkIndependence(Node x, Node y, Set z) { } } + if (facts.containsKey(new IndependenceFact(x, y, z))) { + return facts.get(new IndependenceFact(x, y, z)); + } + boolean mSeparated; if (graph != null) { @@ -235,7 +238,9 @@ public IndependenceResult checkIndependence(Node x, Node y, Set z) { this.pvalue = pValue; - return new IndependenceResult(new IndependenceFact(x, y, z), mSeparated, pValue, pvalue == 1 ? -1 : 1); + IndependenceResult result = new IndependenceResult(new IndependenceFact(x, y, z), mSeparated, pValue, pvalue == 1 ? -1 : 1); + facts.put(new IndependenceFact(x, y, z), result); + return result; } /** @@ -254,7 +259,7 @@ public boolean isMSeparated(Node x, Node y, Set z) { } } - return getGraph().paths().isMSeparatedFrom(x, y, z); + return getGraph().paths().isMSeparatedFrom(x, y, z, ancestorMap); } /** diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/RowsSettable.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/RowsSettable.java new file mode 100644 index 0000000000..43de224774 --- /dev/null +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/RowsSettable.java @@ -0,0 +1,25 @@ +package edu.cmu.tetrad.search.test; + +import java.util.List; + +/** + * Interface for tests that can have their rows set on the fly. + * + * @author josephramsey + */ +public interface RowsSettable { + + /** + * Gets the rows to use for the test. These rows over override testwise deletion if set. + * + * @return The rows to use for the test. Can be null. + */ + List getRows(); + + /** + * Sets the rows to use for the test. This will override testwise deletion. + * + * @param rows The rows to use for the test. Can be null. + */ + void setRows(List rows); +} diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/ScoreIndTest.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/ScoreIndTest.java index de7e21e1f7..5bbd3632cf 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/ScoreIndTest.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/test/ScoreIndTest.java @@ -40,14 +40,12 @@ import java.util.Set; /** - *

Gives a way of interpreting a score as an independence test. The contract is that - * the score returned will be negative for independence and positive for dependence; this simply reports these - * differences.

+ * Gives a way of interpreting a score as an independence test. The contract is that the score returned will be negative + * for independence and positive for dependence; this simply reports these differences. * * @author josephramsey */ public class ScoreIndTest implements IndependenceTest { - private final Score score; private final List variables; private final DataModel data; @@ -94,9 +92,6 @@ public IndependenceResult checkIndependence(Node x, Node y, Set z) { int N = score.getSampleSize(); - // No. -// double p = 5 * exp(-2 * v - 2 * log(N)) / ((N) * log(N)); - boolean independent = v <= 0; if (this.verbose) { diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/AdLeafTree.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/AdLeafTree.java index a4c96872b2..c8eb64b54c 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/AdLeafTree.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/AdLeafTree.java @@ -60,7 +60,6 @@ public AdLeafTree(DataSet dataSet) { Node v = dataSet.getVariable(j); this.nodesHash.put(v, j); } - } /** diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/BayesImParser.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/BayesImParser.java index 605a6ba104..428fde9518 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/BayesImParser.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/BayesImParser.java @@ -43,6 +43,7 @@ */ public class BayesImParser { + // Whether to use display names. private boolean useDisplayNames; /** @@ -61,7 +62,7 @@ public void setUseDisplayNames(boolean useDisplayNames) { } /** - * Takes an xml representation of a Bayes IM and reinstantiates the IM + * Takes an xml representation of a Bayes IM and reinstantiates the IM. * * @param element the xml of the IM * @return the BayesIM diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/Bes.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/Bes.java index bbc0753016..f0a0bf85eb 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/Bes.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/Bes.java @@ -20,16 +20,14 @@ /** - *

Extracts the backward step of GES for use GES but also in other - * algorithms. The GES algorithm consists of a forward phase (FES = Forward Equivalence Search) and a backward phase - * (BES = Backward Equivalence Search). We find the BES step by itself is useful in a number of algorithms, so we - * extract this step and give as a separate algorithm.

- * - *

The idea of the backward search is to start with a model that is - * Markov and removed edges from it and do the corresponding reorientations, improving the score each time, until the - * score can no longer be improved.

- *

We use the optimized implementation used in the FGES implementation - * of GES.

+ * Extracts the backward step of GES for use GES but also in other algorithms. The GES algorithm consists of a forward + * phase (FES = Forward Equivalence Search) and a backward phase (BES = Backward Equivalence Search). We find the BES + * step by itself is useful in a number of algorithms, so we extract this step and give as a separate algorithm. + *

+ * The idea of the backward search is to start with a model that is Markov and removed edges from it and do the + * corresponding reorientations, improving the score each time, until the score can no longer be improved. + *

+ * We use the optimized implementation used in the FGES implementation of GES. * * @author bryanandrews * @author josephramsey @@ -37,12 +35,23 @@ * @see Boss */ public class Bes { + + // The variables being searched over. private final List variables; + // The score. private final Score score; + // The knowledge. private Knowledge knowledge = new Knowledge(); + // True if verbose output should be printed. private boolean verbose = true; + // The depth of the search. private int depth = 4; + /** + * Constructs the search. + * + * @param score The score. + */ public Bes(@NotNull Score score) { this.score = score; this.variables = score.getVariables(); @@ -139,10 +148,6 @@ public void bes(Graph graph, List variables) { } } - private Knowledge getKnowledge() { - return knowledge; - } - /** * Sets the knowledge for the search. * @@ -153,6 +158,10 @@ public void setKnowledge(Knowledge knowledge) { this.knowledge = new Knowledge((Knowledge) knowledge); } + private Knowledge getKnowledge() { + return knowledge; + } + private void delete(Node x, Node y, Set H, double bump, Set naYX, Graph graph) { Edge oldxy = graph.getEdge(x, y); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/BesPermutation.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/BesPermutation.java index 0242ddaa16..08b7106682 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/BesPermutation.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/BesPermutation.java @@ -37,11 +37,14 @@ * @see Boss */ public class BesPermutation { + // The variables. private final List variables; + // The score. private final Score score; + // The knowledge. private Knowledge knowledge = new Knowledge(); + // Whether verbose output should be printed. private boolean verbose = true; - private int depth = -1; /** * Constructor. @@ -81,15 +84,11 @@ private void buildIndexing(List nodes, Map hashIndices) { } } -// public void setDepth(int depth) { -// if (depth < -1) throw new IllegalArgumentException("Depth should be >= -1."); -// this.depth = depth; -// } - /** * Runs BES. - * @param graph The graph. - * @param order The order. + * + * @param graph The graph. + * @param order The order. * @param suborder The suborder. */ public void bes(Graph graph, List order, List suborder) { @@ -228,6 +227,11 @@ private double scoreGraphChange(Node x, Node y, Set parents, Map revertToCPDAG(Graph graph) { @@ -442,6 +446,8 @@ private void calculateArrowsBackward(Node a, Node b, Graph if (storedConfig != null && storedConfig.equals(config)) return; arrowsMapBackward.put(directedEdge(a, b), new ArrowConfigBackward(naYX, parents)); + // The depth. + int depth = -1; int _depth = min(depth, _naYX.size()); final SublistGenerator gen = new SublistGenerator(_naYX.size(), _depth);//_naYX.size()); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/BpcAlgorithmType.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/BpcAlgorithmType.java index a130741bb5..b7a5110e19 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/BpcAlgorithmType.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/BpcAlgorithmType.java @@ -25,14 +25,44 @@ /** * Enumerates the algorithm types for BuildPureClusters, and Purify. + * + * @author josephramsey */ public enum BpcAlgorithmType implements TetradSerializable { + + /** + * This one will work and does a good job for medium-sized models. + */ BUILD_PURE_CLUSTERS, + + /** + * This will work and does a good job for small models, no more than 4 latents. + */ SIMPLIFIED_BPC_DEPTH_0, + + /** + * This is very slow. + */ SIMPLIFIED_BPC_DEPTH_1, + + /** + * Even slower. + */ SIMPLIFIED_BPC, + + /** + * This option doesn't do any purify. + */ TETRAD_PURIFY_WASHDOWN, + + /** + * FOFC algorithm + */ FIND_ONE_FACTOR_CLUSTERS, + + /** + * FTFC algorithm. + */ FIND_TWO_FACTOR_CLUSTERS; private static final long serialVersionUID = 23L; @@ -41,6 +71,11 @@ public static BpcAlgorithmType serializableInstance() { return BpcAlgorithmType.BUILD_PURE_CLUSTERS; } + /** + * Returns the algorithm descriptions. + * + * @return The algorithm descriptions. + */ public static BpcAlgorithmType[] getAlgorithmDescriptions() { return new BpcAlgorithmType[]{ BpcAlgorithmType.BUILD_PURE_CLUSTERS, diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/BpcTestType.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/BpcTestType.java index a5cf29545a..6193e197f4 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/BpcTestType.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/BpcTestType.java @@ -28,31 +28,85 @@ */ public enum BpcTestType implements TetradSerializable { - // This one will work and does a good job for medium sized models. + /** + * This one will work and does a good job for medium sized models. + */ GAUSSIAN_PVALUE, - // This will work and does a good job for small models, no more than 4 latents. + /** + * This will work and does a good job for small models, no more than 4 latents. + */ GAUSSIAN_SCORE_MARKS, - // This is very slow. + /** + * This is very slow. + */ GAUSSIAN_SCORE, - // Even slower. + /** + * Even slower. + */ GAUSSIAN_SCORE_ITERATE, - // This option doesn't do any purify. + /** + * This option doesn't do any purify. + */ NONE, - DISCRETE_LRT, DISCRETE_VARIATIONAL, - - - // TETRAD_DELTA is kept for purpospes of serialization. - GAUSSIAN_FACTOR, DISCRETE, TETRAD_BOLLEN, TETRAD_DELTA, TETRAD_WISHART, - TETRAD_BASED, POPULATION, - - // For FTFC - SAG, GAP; - + /** + * Discrete LRT. + */ + DISCRETE_LRT, + + /** + * Discrete Variational. + */ + DISCRETE_VARIATIONAL, + + /** + * Gaussian Factor. + */ + GAUSSIAN_FACTOR, + + /** + * Discrete. + */ + DISCRETE, + + /** + * Bollen Tetrad test. + */ + TETRAD_BOLLEN, + + /** + * Delta Tetrad test. + */ + TETRAD_DELTA, + + /** + * Wishart Tetrad test. + */ + TETRAD_WISHART, + + /** + * Tetrad-based test. + */ + TETRAD_BASED, + + /** + * Population test. + */ + POPULATION, + + /** + * SAG test, for FTFC. + */ + SAG, + + /** + * GAP test, for FTFC. + */ + GAP; private static final long serialVersionUID = 23L; @@ -60,7 +114,11 @@ public static BpcTestType serializableInstance() { return BpcTestType.GAUSSIAN_PVALUE; } - + /** + * Returns the test type descriptions for the Purify algorithm. + * + * @return the test type descriptions for the Purify algorithm. + */ public static BpcTestType[] getPurifyTestDescriptions() { return new BpcTestType[]{ @@ -73,6 +131,11 @@ public static BpcTestType[] getPurifyTestDescriptions() { }; } + /** + * Returns the test type descriptions for the BuildPureClusters algorithm. + * + * @return the test type descriptions for the BuildPureClusters algorithm. + */ public static BpcTestType[] getTestDescriptions() { return new BpcTestType[]{ BpcTestType.TETRAD_WISHART, diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/ClusterSignificance.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/ClusterSignificance.java index 4d000327a9..d96e16496c 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/ClusterSignificance.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/ClusterSignificance.java @@ -25,11 +25,19 @@ * @author josephramsey */ public class ClusterSignificance { - + // The variables in the model. private final List variables; + // The data model. private final DataModel dataModel; + // The type of check to perform. private CheckType checkType = CheckType.Clique; + /** + * Constructs a new cluster significance object. + * + * @param variables The variables in the model. + * @param dataModel The data model. + */ public ClusterSignificance(List variables, DataModel dataModel) { if (variables == null) throw new NullPointerException("Variable null."); if (dataModel == null) throw new NullPointerException("Data model null."); @@ -37,6 +45,13 @@ public ClusterSignificance(List variables, DataModel dataModel) { this.dataModel = dataModel; } + /** + * Converts a list of indices into a list of Nodes representing a cluster. + * + * @param cluster The indices of the variables. + * @param variables The variables. + * @return The extracted node list. + */ public static List variablesForIndices(List cluster, List variables) { List _cluster = new ArrayList<>(); @@ -47,6 +62,13 @@ public static List variablesForIndices(List cluster, List v return _cluster; } + /** + * Converts a list of indices into a list of Nodes representing a cluster. + * + * @param clusters The indices of the variables. + * @param _variables The variables. + * @return The extracted node list. + */ public static List> variablesForIndices2(Set> clusters, List _variables) { List> variables = new ArrayList<>(); @@ -75,10 +97,15 @@ private static int dofHarman(int n) { return dof; } - public void printClusterPValues(Set> out) { + /** + * Prints the p-values for the given clusters. + * + * @param clusters The clusters. + */ + public void printClusterPValues(Set> clusters) { NumberFormat nf = new DecimalFormat("0.000"); - for (List _out : out) { + for (List _out : clusters) { ClusterSignificance clusterSignificance = new ClusterSignificance(variables, dataModel); try { @@ -92,10 +119,23 @@ public void printClusterPValues(Set> out) { } } + /** + * Sets the type of check to perform. + * + * @param checkType The type of check. + * @see CheckType + */ public void setCheckType(CheckType checkType) { this.checkType = checkType; } + /** + * Returns the p-value for the given cluster. + * + * @param cluster The cluster. + * @param alpha The alpha level. + * @return The p-value. + */ public boolean significant(List cluster, double alpha) { if (checkType == CheckType.None) { return true; @@ -108,6 +148,12 @@ public boolean significant(List cluster, double alpha) { } } + /** + * Returns the p-value for the given cluster. + * + * @param clusters The clusters. + * @return The p-value. + */ public double getModelPValue(List> clusters) { SemIm im = estimateModel(clusters); return im.getPValue(); @@ -250,6 +296,4 @@ private SemIm estimateModel(List> clusters) { * or could check to see if the cluster is a clique, or could not do the check. */ public enum CheckType {Significance, Clique, None} - - } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/ClusterUtils.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/ClusterUtils.java index fb6ad4e8cb..e6e7591c40 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/ClusterUtils.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/ClusterUtils.java @@ -31,15 +31,24 @@ import java.util.Set; /** - *

Provides some general utilities for dealing with clustering input and output.

- *

The method of this class are used only internally and so are not documented - * for public use.

+ * Provides some general utilities for dealing with clustering input and output. + *

+ * The method of this class are used only internally and so are not documented for public use. * * @author josephramsey */ public class ClusterUtils { + + // The prefix for latent variables. public static final String LATENT_PREFIX = "_L"; + /** + * Converts a list of indices into a list of Nodes representing a cluster. + * + * @param partition The indices of the variables. + * @param nodes The variables. + * @return The extracted node list. + */ public static List convertListToInt(List> partition, List nodes) { List _partition = new ArrayList<>(); @@ -60,6 +69,13 @@ public static List convertListToInt(List> partition, List> convertIntToList(List partition, List nodes) { List> _partition = new ArrayList<>(); @@ -76,6 +92,13 @@ static List> convertIntToList(List partition, List nodes return _partition; } + /** + * Converts a list of indices into a list of Nodes representing a cluster. + * + * @param clusters The indices of the variables. + * @param variables The variables. + * @return The extracted node list. + */ public static List> clustersToPartition(Clusters clusters, List variables) { List> inputPartition = new ArrayList<>(); @@ -96,6 +119,12 @@ public static List> clustersToPartition(Clusters clusters, List return inputPartition; } + /** + * Converts a list of indices into a list of Nodes representing a cluster. + * + * @param partition The indices of the variables. + * @return The extracted node list. + */ public static Clusters partitionToClusters(List> partition) { Clusters clusters = new Clusters(); @@ -110,6 +139,13 @@ public static Clusters partitionToClusters(List> partition) { return clusters; } + /** + * Converts a list of indices into a list of Nodes representing a cluster. + * + * @param clusters The indices of the variables. + * @param varNames The variables. + * @return The extracted node list. + */ public static Graph convertSearchGraph(List clusters, String[] varNames) { List nodes = new ArrayList<>(); @@ -153,6 +189,12 @@ public static Graph convertSearchGraph(List clusters, String[] varNames) return graph; } + /** + * Converts a list of indices into a list of Nodes representing a cluster. + * + * @param mim The graph to convert. + * @return The extracted node list. + */ public static Clusters mimClusters(Graph mim) { List latents = new ArrayList<>(); @@ -180,6 +222,12 @@ public static Clusters mimClusters(Graph mim) { } + /** + * Logs the clusters. + * + * @param clusters The clusters. + * @param variables The variables. + */ public static void logClusters(Set> clusters, List variables) { int num = 1; StringBuilder buf = new StringBuilder(); @@ -206,6 +254,12 @@ public static void logClusters(Set> clusters, List variables) TetradLogger.getInstance().log("clusters", buf.toString()); } + /** + * Generates a list of latent variable names. + * + * @param total The number of latent variables to generate. + * @return The list of latent variable names. + */ public static List generateLatentNames(int total) { List output = new ArrayList<>(); for (int i = 0; i < total; i++) { diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/DagInCpcagIterator.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/DagInCpcagIterator.java index 67c24ca356..03d97e9061 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/DagInCpcagIterator.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/DagInCpcagIterator.java @@ -34,14 +34,16 @@ */ public class DagInCpcagIterator { - /** - * 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. - */ + // The stack of graphs, with annotations as to the arbitrary undirected edges chosen in them and whether + // these edges have already been oriented left and/or right. private final LinkedList decoratedGraphs = new LinkedList<>(); + // The set of colliders in the original CPDAG. private final LinkedList colliders; + // Whether to allow new colliders in the graphs. private final boolean allowNewColliders; + // The graph to be returned by next() if it is not null. private Graph storedGraph; + // Whether the first graph has been returned. private boolean returnedOne; /** @@ -154,6 +156,8 @@ public Graph next() { } /** + * Returns true just in case there is still a DAG remaining in the enumeration of DAGs for this CPDAG. + * * @return true just in case there is still a DAG remaining in the enumeration of DAGs for this CPDAG. */ public boolean hasNext() { @@ -313,7 +317,6 @@ public void setChangedEdges(Map> changedEdges) { public boolean isAllowArbitraryOrientation() { return this.allowArbitraryOrientation; } - } } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/DagIterator.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/DagIterator.java index 8353c6ce4d..905269b748 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/DagIterator.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/DagIterator.java @@ -36,11 +36,10 @@ */ 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. - */ + // The stack of graphs, with annotations as to the arbitrary undirected edges chosen in them and whether + //these edges have already been oriented left and/or right. private final LinkedList decoratedGraphs = new LinkedList<>(); + // The DAG that is returned by the next() method. private Graph storedDag; /** @@ -135,6 +134,8 @@ public Graph next() { } /** + * Returns true just in case there is still a DAG remaining in the enumeration of DAGs for this pattern. + * * @return true just in case there is still a DAG remaining in the enumeration of DAGs for this pattern. */ public boolean hasNext() { @@ -145,7 +146,6 @@ public boolean hasNext() { return this.storedDag != null; } - private static class DecoratedGraph { private Graph graph; private Edge edge; diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/DagSepsets.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/DagSepsets.java index a1cddfe9aa..dd172802e6 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/DagSepsets.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/DagSepsets.java @@ -35,6 +35,7 @@ * @author josephramsey */ public class DagSepsets implements SepsetProducer { + // The DAG being analyzed. private final EdgeListGraph dag; /** @@ -72,7 +73,6 @@ public boolean isUnshieldedCollider(Node i, Node j, Node k) { return sepset != null && !sepset.contains(j); } - /** * Not implemented; required for an interface. * diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/EstimateRank.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/EstimateRank.java index 0f68865558..655ebb2a07 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/EstimateRank.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/EstimateRank.java @@ -65,7 +65,7 @@ public static double[] CanCor(int[] iA, int[] iB, double[][] cov) { /** * Estimate rank from data. */ - public static int Estimate(double[][] A, double[][] B, double alpha) { + public static int estimate(double[][] A, double[][] B, double alpha) { double[] Cors = CanCor(A, B); int rank = 0; boolean reject = true; @@ -90,7 +90,7 @@ public static int Estimate(double[][] A, double[][] B, double alpha) { /** * Estimate rank from covariance matrix. */ - public static int Estimate(int[] iA, int[] iB, double[][] cov, int N, double alpha) { + public static int estimate(int[] iA, int[] iB, double[][] cov, int N, double alpha) { double[] Cors = CanCor(iA, iB, cov); int rank = 0; boolean reject = true; diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/FciOrient.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/FciOrient.java index 59d5f48a30..92ed49f382 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/FciOrient.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/FciOrient.java @@ -32,26 +32,23 @@ import java.util.*; /** - *

Performs the final orientation steps of the FCI algorithms, which - * is a useful tool to use in a variety of FCI-like algorithms.

- * - *

There are two versions of these final orientation steps, one due to - * Peter Spirtes (the original, in Causation, Prediction and Search), which is arrow complete, and the other which Jiji - * Zhang worked out in his Ph.D. dissertation, which is both arrow and tail complete. The references for these are as - * follows.

- * - *

Spirtes, P., Glymour, C. N., Scheines, R., & Heckerman, D. (2000). - * Causation, prediction, and search. MIT press.

- * - *

Zhang, J. (2008). On the completeness of orientation rules for causal - * discovery in the presence of latent confounders and selection bias. Artificial Intelligence, 172(16-17), - * 1873-1896.

- * - *

These final rules are used in all algorithms in Tetrad that - * follow and refine the FCI algorithm--for example, the GFCI and RFCI algorihtms.

- * - *

We've made the methods for each of the separate rules publicly - * accessible in case someone wants to use the individual rules in the context of their own algorithms.

+ * Performs the final orientation steps of the FCI algorithms, which is a useful tool to use in a variety of FCI-like + * algorithms. + *

+ * There are two versions of these final orientation steps, one due to Peter Spirtes (the original, in Causation, + * Prediction and Search), which is arrow complete, and the other which Jiji Zhang worked out in his Ph.D. dissertation, + * which is both arrow and tail complete. The references for these are as follows. + *

+ * Spirtes, P., Glymour, C. N., Scheines, R., & Heckerman, D. (2000). Causation, prediction, and search. MIT press. + *

+ * Zhang, J. (2008). On the completeness of orientation rules for causal discovery in the presence of latent confounders + * and selection bias. Artificial Intelligence, 172(16-17), 1873-1896. + *

+ * These final rules are used in all algorithms in Tetrad that follow and refine the FCI algorithm--for example, the + * GFCI and RFCI algorihtms. + *

+ * We've made the methods for each of the separate rules publicly accessible in case someone wants to use the individual + * rules in the context of their own algorithms. * * @author Erin Korber, June 2004 * @author Alex Smith, December 2008 @@ -501,8 +498,8 @@ public void ruleR2(Node a, Node b, Node c, Graph graph) { } /** - * Implements the double-triangle orientation rule, which states that if D*-oB, A*->B<-*C and A*-oDo-*C, and !adj(a, - * c), D*-oB, then D*->B. + * Implements the double-triangle orientation rule, which states that if D*-oB, A*->B<-*C and A*-oDo-*C, and + * !adj(a, c), D*-oB, then D*->B. *

* This is Zhang's rule R3. */ @@ -1021,7 +1018,9 @@ public boolean ruleR9(Node a, Node c, Graph graph) { * Orients according to background knowledge */ public void fciOrientbk(Knowledge bk, Graph graph, List variables) { - this.logger.forceLogMessage("Starting BK Orientation."); + if (verbose) { + this.logger.forceLogMessage("Starting BK Orientation."); + } for (Iterator it = bk.forbiddenEdgesIterator(); it.hasNext(); ) { @@ -1083,7 +1082,9 @@ public void fciOrientbk(Knowledge bk, Graph graph, List variables) { this.logger.forceLogMessage(LogUtilsSearch.edgeOrientedMsg("Knowledge", graph.getEdge(from, to))); } - this.logger.forceLogMessage("Finishing BK Orientation."); + if (verbose) { + this.logger.forceLogMessage("Finishing BK Orientation."); + } } /** @@ -1170,8 +1171,8 @@ public void setDoDiscriminatingPathTailRule(boolean doDiscriminatingPathTailRule *

* MAY HAVE WEIRD EFFECTS ON ARBITRARY NODE PAIRS. *

- * R10: If Ao->C, B-->C<--D, there is an uncovered p.d. path u1=<A,M,...,B> and an uncovered p.d. path u2= - * <A,N,...,D> with M != N and M,N nonadjacent then A-->C. + * R10: If Ao->C, B-->C<--D, there is an uncovered p.d. path u1=<A,M,...,B> and an uncovered p.d. + * path u2= <A,N,...,D> with M != N and M,N nonadjacent then A-->C. * * @param a The node A. * @param c The node C. diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/FgesOrienter.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/FgesOrienter.java index d91ab15023..5e8be11fc8 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/FgesOrienter.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/FgesOrienter.java @@ -1436,7 +1436,7 @@ private double localSemScore(int i, int[] parents) { covxxInv = covxx.inverse(); } catch (Exception e) { printMinimalLinearlyDependentSet(parents, cov); - this.out.println("Using generalized inverse."); + this.out.println("Using pseudoinverse."); covxxInv = covxx.ginverse(); } Vector covxy = getSelection2(cov, parents, i); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/GraphSearchUtils.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/GraphSearchUtils.java index 642cd9ade1..f8027522a3 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/GraphSearchUtils.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/GraphSearchUtils.java @@ -69,8 +69,6 @@ public static void pcOrientbk(Knowledge bk, Graph graph, List nodes) { // Orient to-->from graph.removeEdge(from, to); graph.addDirectedEdge(to, from); - - TetradLogger.getInstance().log("knowledgeOrientations", LogUtilsSearch.edgeOrientedMsg("Knowledge", graph.getEdge(to, from))); } for (Iterator it = bk.requiredEdgesIterator(); it.hasNext(); ) { @@ -347,6 +345,96 @@ public static void basicCpdagRestricted2(Graph graph, Node node) { } } + /** + * Returns true just in case the given graph is a CPDAG. + * + * @param graph the graph to check. + * @return true just in case the given graph is a CPDAG. + */ + public static boolean isPdag(Graph graph) { + + // Make sure all the edges are directed or undirected. + for (Edge edge : graph.getEdges()) { + if (!(Edges.isDirectedEdge(edge) || Edges.isUndirectedEdge(edge))) { + return false; + } + } + + // Make sure there are no 2-cycles. + List nodes = graph.getNodes(); + + for (int i = 0; i < nodes.size(); i++) { + for (int j = i + 1; j < nodes.size(); j++) { + if (graph.getEdges(nodes.get(i), nodes.get(j)).size() > 1) { + return false; + } + } + } + + // Make sure there are no underlinings. + if (!graph.getUnderLines().isEmpty()) { + return false; + } + if (!graph.getDottedUnderlines().isEmpty()) { + return false; + } + + // Make sure there's no way to orient a directed cycle using the Meek rules. + MeekRules rules = new MeekRules(); + rules.setRevertToUnshieldedColliders(true); + rules.orientImplied(graph); + + if (graph.paths().existsDirectedCycle()) return false; + + rules.setRevertToUnshieldedColliders(false); + + NEXT: + while (true) { + for (Edge edge : graph.getEdges()) { + Node x = edge.getNode1(); + Node y = edge.getNode2(); + + if (Edges.isUndirectedEdge(edge)) { + Graph _graph = new EdgeListGraph(graph); + + if (!_graph.paths().isAncestorOf(y, x)) { + direct(x, y, graph); + } else { + direct(y, x, graph); + } + + rules.orientImplied(_graph); + if (_graph.paths().existsDirectedCycle()) return false; + + _graph = new EdgeListGraph(graph); + + if (!_graph.paths().isAncestorOf(y, x)) { + direct(x, y, graph); + } else { + direct(y, x, graph); + } + + rules.orientImplied(_graph); + if (_graph.paths().existsDirectedCycle()) return false; + + graph = _graph; + continue NEXT; + } + } + + break; + } + + return true; + } + + private static void direct(Node a, Node c, Graph graph) { + Edge before = graph.getEdge(a, c); + Edge after = Edges.directedEdge(a, c); + graph.removeEdge(before); + graph.addEdge(after); + } + public static LegalPagRet isLegalPag(Graph pag) { for (Node n : pag.getNodes()) { @@ -390,7 +478,7 @@ public static LegalPagRet isLegalPag(Graph pag) { "a MAG and PAG"; } - if (!edgeMismatch.equals("")) { + if (!edgeMismatch.isEmpty()) { reason = reason + ". " + edgeMismatch; } @@ -516,7 +604,7 @@ public static void arrangeByKnowledgeTiers(Graph graph, int x = 0; int y = 50 - ySpace; - if (notInTier.size() > 0) { + if (!notInTier.isEmpty()) { y += ySpace; for (String name : notInTier) { @@ -640,7 +728,7 @@ public static Set getReachableNodes(List initialNodes, int pathLength = 1; - while (nextEdges.size() > 0) { + while (!nextEdges.isEmpty()) { // System.out.println("Path length = " + pathLength); if (++pathLength > maxPathLength) { return reachable; @@ -837,20 +925,11 @@ private static int structuralHammingDistanceOneEdge(Edge e1, Edge e2) { if (!e1.equals(e2)) { error++; } - } else if (e2 == null) { - if (Edges.isUndirectedEdge(e1)) { - error++; - } else { - error++; - error++; - } + } else if (Edges.isUndirectedEdge(Objects.requireNonNullElse(e2, e1))) { + error++; } else { - if (Edges.isUndirectedEdge(e2)) { - error++; - } else { - error++; - error++; - } + error++; + error++; } } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/LogUtilsSearch.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/LogUtilsSearch.java index 3bbd503f04..e23963caae 100755 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/LogUtilsSearch.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/LogUtilsSearch.java @@ -27,8 +27,10 @@ import edu.cmu.tetrad.graph.Graph; import edu.cmu.tetrad.graph.GraphTransforms; import edu.cmu.tetrad.graph.Node; +import edu.cmu.tetrad.search.score.GraphScore; import edu.cmu.tetrad.search.score.Score; import edu.cmu.tetrad.util.NumberFormatUtil; +import edu.cmu.tetrad.util.TetradLogger; import org.jetbrains.annotations.NotNull; import java.text.NumberFormat; @@ -157,9 +159,11 @@ public static Map buildIndexing(List nodes) { } @NotNull - public static void stampWithScores(Graph graph, DataModel dataModel, Score score) { + public static void stampWithScore(Graph graph, Score score) { + if (score instanceof GraphScore) return; + if (!graph.getAllAttributes().containsKey("Score")) { - Graph dag = GraphTransforms.dagFromCPDAG(graph); + Graph dag = GraphTransforms.dagFromCpdag(graph); Map hashIndices = buildIndexing(dag.getNodes()); double _score = 0.0; @@ -179,13 +183,16 @@ public static void stampWithScores(Graph graph, DataModel dataModel, Score score graph.addAttribute("Score", _score); } - - stampWithBic(graph, dataModel); } public static void stampWithBic(Graph graph, DataModel dataModel) { - if (!graph.getAllAttributes().containsKey("BIC")) { - graph.addAttribute("BIC", new BicEst().getValue(null, graph, dataModel)); + if (dataModel != null && (dataModel.isContinuous() || dataModel.isDiscrete()) + && !graph.getAllAttributes().containsKey("BIC")) { + try { + graph.addAttribute("BIC", new BicEst().getValue(null, graph, dataModel)); + } catch (Exception e) { + TetradLogger.getInstance().forceLogMessage("Error computing BIC: " + e.getMessage()); + } } } } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/MbUtils.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/MbUtils.java index 7d320a1bfc..b81957cc2b 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/MbUtils.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/MbUtils.java @@ -238,7 +238,7 @@ public static List generateMbDags(Graph mbCPDAG, * @return An example DAG in this CPDAG. */ public static Graph getOneMbDag(Graph mbCpdag) { - return GraphTransforms.dagFromCPDAG(mbCpdag, null); + return GraphTransforms.dagFromCpdag(mbCpdag, null); } /** diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/SepsetProducer.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/SepsetProducer.java index 58efec8aa3..1f61d72964 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/SepsetProducer.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/SepsetProducer.java @@ -27,8 +27,7 @@ import java.util.Set; /** - *

Provides a covenience interface for classes that can generate and keep - * track of sepsets.

+ * Provides a covenience interface for classes that can generate and keep track of sepsets. * * @author josephramsey * @see SepsetMap diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/SepsetsGreedy.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/SepsetsGreedy.java index 9b441e666a..9f4e2d3c78 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/SepsetsGreedy.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/SepsetsGreedy.java @@ -37,8 +37,8 @@ import java.util.Set; /** - *

Provides a SepsetProcuder that selects the first sepset it comes to from - * among the extra sepsets or the adjacents of i or k, or null if none is found.

+ * Provides a SepsetProcuder that selects the first sepset it comes to from among the extra sepsets or the adjacents of + * i or k, or null if none is found. * * @author josephramsey * @see SepsetProducer @@ -99,6 +99,7 @@ public boolean isVerbose() { @Override public void setVerbose(boolean verbose) { + independenceTest.setVerbose(verbose); this.verbose = verbose; } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/SvarFciOrient.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/SvarFciOrient.java index b9b7b03020..adb4af7111 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/SvarFciOrient.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/utils/SvarFciOrient.java @@ -868,7 +868,9 @@ private void ruleR10(Node a, Node c, Graph graph) { * Orients according to background knowledge */ private void fciOrientbk(Knowledge bk, Graph graph, List variables) { - this.logger.log("info", "Starting BK Orientation."); + if (verbose) { + this.logger.log("info", "Starting BK Orientation."); + } for (Iterator it = bk.forbiddenEdgesIterator(); it.hasNext(); ) { @@ -916,7 +918,9 @@ private void fciOrientbk(Knowledge bk, Graph graph, List variables) { this.logger.log("knowledgeOrientation", LogUtilsSearch.edgeOrientedMsg("Knowledge", graph.getEdge(from, to))); } - this.logger.log("info", "Finishing BK Orientation."); + if (verbose) { + this.logger.log("info", "Finishing BK Orientation."); + } } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/Fas2.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/Fas2.java deleted file mode 100644 index 0e6fe4e7b2..0000000000 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/Fas2.java +++ /dev/null @@ -1,410 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// 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 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.IFas; -import edu.cmu.tetrad.search.IndependenceTest; -import edu.cmu.tetrad.search.utils.PcCommon; -import edu.cmu.tetrad.search.utils.SepsetMap; -import edu.cmu.tetrad.util.ChoiceGenerator; -import edu.cmu.tetrad.util.TetradLogger; - -import java.io.PrintStream; -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 Joseph Ramsey. - */ -public class Fas2 implements IFas { - - /** - * The search nodes. - */ - private final List nodes; - - /** - * 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(); - /** - * 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 sepsets found during the search. - */ - private SepsetMap sepset = new SepsetMap(); - - /** - * The depth 0 graph, specified initially. - */ - private Graph initialGraph; - - /** - * True iff verbose output should be printed. - */ - private boolean verbose = false; - - private PrintStream out = System.out; - private PcCommon.PcHeuristicType pcHeuristicType; - - //==========================CONSTRUCTORS=============================// - - /** - * Constructs a new FastAdjacencySearch. - */ - public Fas2(Graph initialGraph, IndependenceTest test) { - if (initialGraph != null) { - this.initialGraph = new EdgeListGraph(initialGraph); - } - this.test = test; - this.nodes = test.getVariables(); - } - - public Fas2(IndependenceTest test) { - this.test = test; - this.nodes = test.getVariables(); - } - - //==========================PUBLIC METHODS===========================// - - public Graph search(List nodes) { -// return search(nodes, new Knowledge()); - throw new UnsupportedOperationException(); - } - - /** - * 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."); - - sepset = new SepsetMap(); -// sepset.setReturnEmptyIfNotSet(sepsetsReturnEmptyIfNotFixed); - - int _depth = depth; - - if (_depth == -1) { - _depth = 1000; - } - - Map> adjacencies = new HashMap<>(); - - for (Node node : nodes) { - adjacencies.put(node, new TreeSet<>()); - } - - for (int d = 0; d <= _depth; d++) { - boolean more; - - if (d == 0) { - more = searchAtDepth0(nodes, test, adjacencies); - } else { - more = searchAtDepth(nodes, test, adjacencies, d); - } - - if (!more) { - break; - } - } - - Graph graph = new EdgeListGraph(nodes); - - 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)) { - graph.addUndirectedEdge(x, y); - } - } - } - - this.logger.log("info", "Finishing Fast Adjacency Search."); - - return graph; - } - - public int getDepth() { - return 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 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 (verbose) { - if ((i + 1) % 100 == 0) out.println("Node # " + (i + 1)); - } - - if (Thread.currentThread().isInterrupted()) { - break; - } - - Node x = nodes.get(i); - - for (int j = i + 1; j < nodes.size(); j++) { - - Node y = nodes.get(j); - - if (initialGraph != null) { - Node x2 = initialGraph.getNode(x.getName()); - Node y2 = initialGraph.getNode(y.getName()); - - if (!initialGraph.isAdjacentTo(x2, y2)) { - continue; - } - } - - boolean independent; - - try { - numIndependenceTests++; - independent = test.checkIndependence(x, y, empty).isIndependent(); - } catch (Exception e) { - e.printStackTrace(); - independent = false; - } - - boolean noEdgeRequired = - knowledge.noEdgeRequired(x.getName(), y.getName()); - - if (independent && noEdgeRequired) { - getSepsets().set(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 (knowledge.isForbidden(name1, name2) && - knowledge.isForbidden(name2, name1)) { - System.out.println(Edges.undirectedEdge(x, y) + " because it was " + - "forbidden by background knowledge."); - - return true; - } - - return false; - } - - private boolean searchAtDepth(List nodes, final IndependenceTest test, Map> adjacencies, int depth) { - int count = 0; - - for (Node x : nodes) { - if (verbose) { - if (++count % 100 == 0) out.println("count " + count + " of " + nodes.size()); - } - - if (Thread.currentThread().isInterrupted()) { - break; - } - - 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, knowledge); - - if (ppx.size() >= depth) { - ChoiceGenerator cg = new ChoiceGenerator(ppx.size(), depth); - int[] choice; - - while ((choice = cg.next()) != null) { - if (Thread.currentThread().isInterrupted()) { - break; - } - - Set condSet = GraphUtils.asSet(choice, ppx); - - boolean independent; - - try { - numIndependenceTests++; - independent = test.checkIndependence(x, y, condSet).isIndependent(); - } catch (Exception e) { - independent = false; - } - - boolean noEdgeRequired = - knowledge.noEdgeRequired(x.getName(), y.getName()); - - if (independent && noEdgeRequired) { - adjacencies.get(x).remove(y); - adjacencies.get(y).remove(x); - - getSepsets().set(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 numIndependenceTests; - } - - public SepsetMap getSepsets() { - return sepset; - } - - public boolean isVerbose() { - return verbose; - } - - public void setVerbose(boolean verbose) { - this.verbose = verbose; - } - - @Override - public long getElapsedTime() { - return 0; - } - - @Override - public List getNodes() { - return test.getVariables(); - } - - @Override - public List getAmbiguousTriples(Node node) { - return null; - } - - @Override - public void setOut(PrintStream out) { - this.out = out; - } - - public void setPcHeuristicType(PcCommon.PcHeuristicType pcHeuristicType) { - this.pcHeuristicType = pcHeuristicType; - } - - public void setStable(boolean b) { - boolean stable = b; - } -} diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/Fas3.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/Fas3.java deleted file mode 100644 index d8801baf24..0000000000 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/Fas3.java +++ /dev/null @@ -1,459 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// 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 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.Fci; -import edu.cmu.tetrad.search.IFas; -import edu.cmu.tetrad.search.IndependenceTest; -import edu.cmu.tetrad.search.Pc; -import edu.cmu.tetrad.search.test.IndependenceResult; -import edu.cmu.tetrad.search.utils.PcCommon; -import edu.cmu.tetrad.search.utils.SepsetMap; -import edu.cmu.tetrad.util.ChoiceGenerator; -import edu.cmu.tetrad.util.MillisecondTimes; -import edu.cmu.tetrad.util.TetradLogger; - -import java.io.PrintStream; -import java.util.*; - -/** - *

Implements the Fast Adjacency Search (FAS), which is the adjacency search of the PC algorithm (see). This is a - * useful algorithm in many contexts, including as the first step of FCI (see).

- * - *

The idea of FAS is that 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.

- * - *

FAS may optionally use a heuristic from Causation, Prediction and Search, which (like PC-Stable) - * renders the output invariant to the order of the input variables.

- * - *

This algorithm was described in the earlier edition of this book:

- * - *

Spirtes, P., Glymour, C. N., Scheines, R., & Heckerman, D. (2000). Causation, prediction, and search. MIT - * press.

- * - *

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

- * - * @author peterspirtes - * @author clarkglymour - * @author josephramsey. - * @see Pc - * @see Fci - * @see Knowledge - */ -public class Fas3 implements IFas { - private final IndependenceTest test; - private final TetradLogger logger = TetradLogger.getInstance(); - private Knowledge knowledge = new Knowledge(); - private int numIndependenceTests; - private SepsetMap sepset = new SepsetMap(); - private PcCommon.PcHeuristicType heuristic = PcCommon.PcHeuristicType.NONE; - private int depth = 1000; - private boolean stable = true; - private long elapsedTime = 0L; - private PrintStream out = System.out; - private boolean verbose = false; - - //==========================CONSTRUCTORS=============================// - - /** - * Constructor. - * - * @param test The test to use for oracle conditional independence test results. - */ - public Fas3(IndependenceTest test) { - this.test = test; - } - - //==========================PUBLIC METHODS===========================// - - /** - * Runs the search and returns the resulting (undirected) graph. - * - * @return This graph. - */ - @Override - public Graph search() { - return search(test.getVariables()); - } - - /** - * 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. - * - * @param nodes A list of nodes to search over. - * @return An undirected graph that summarizes the conditional independendencies that obtain in the data. - */ - public Graph search(List nodes) { - long startTime = MillisecondTimes.timeMillis(); - nodes = new ArrayList<>(nodes); - - this.logger.addOutputStream(out); - - if (verbose) { - this.logger.forceLogMessage("Starting Fast Adjacency Search."); - } - - this.test.setVerbose(this.verbose); - - int _depth = this.depth; - - if (_depth == -1) { - _depth = 1000; - } - - this.sepset = new SepsetMap(); - - List edges = new ArrayList<>(); - Map scores = new HashMap<>(); - - if (this.heuristic == PcCommon.PcHeuristicType.HEURISTIC_1) { - Collections.sort(nodes); - } - - for (int i = 0; i < nodes.size(); i++) { - for (int j = i + 1; j < nodes.size(); j++) { - edges.add(Edges.undirectedEdge(nodes.get(i), nodes.get(j))); - } - } - - for (Edge edge : edges) { - IndependenceResult result = this.test.checkIndependence(edge.getNode1(), edge.getNode2(), new HashSet<>()); - scores.put(edge, result.getScore()); - } - - if (this.heuristic == PcCommon.PcHeuristicType.HEURISTIC_2 || this.heuristic == PcCommon.PcHeuristicType.HEURISTIC_3) { - edges.sort(Comparator.comparing(scores::get)); - } - - Map> adjacencies = new HashMap<>(); - - for (Node node : nodes) { - Set set = new LinkedHashSet<>(); - - for (Node _node : nodes) { - if (_node == node) continue; - set.add(_node); - } - - adjacencies.put(node, set); - } - - for (Edge edge : new ArrayList<>(edges)) { - if (scores.get(edge) != null && scores.get(edge) < 0 - || (this.knowledge.isForbidden(edge.getNode1().getName(), edge.getNode2().getName()) - && (this.knowledge.isForbidden(edge.getNode2().getName(), edge.getNode1().getName())))) { - edges.remove(edge); - adjacencies.get(edge.getNode1()).remove(edge.getNode2()); - adjacencies.get(edge.getNode2()).remove(edge.getNode1()); - this.sepset.set(edge.getNode1(), edge.getNode2(), new HashSet<>()); - } - } - - for (int d = 0; d <= _depth; d++) { - System.out.println("Depth: " + d); - - boolean more; - - if (this.stable) { - Map> adjacenciesCopy = new HashMap<>(); - - for (Node node : adjacencies.keySet()) { - adjacenciesCopy.put(node, new LinkedHashSet<>(adjacencies.get(node))); - } - - adjacencies = adjacenciesCopy; - } - - more = searchAtDepth(scores, edges, this.test, adjacencies, d); - - if (!more) { - break; - } - } - - // The search graph. It is assumed going in that all 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. - Graph graph = new EdgeListGraph(nodes); - - 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)) { - graph.addUndirectedEdge(x, y); - } - } - } - - if (verbose) { - this.logger.forceLogMessage("Finishing Fast Adjacency Search."); - } - - this.elapsedTime = MillisecondTimes.timeMillis() - startTime; - - return graph; - } - - /** - * Sets the depth of the search, which is the maximum number of variables that ben be conditioned on in any - * conditional independence test. - * - * @param depth This maximum. - */ - public void setDepth(int depth) { - if (depth < -1) { - throw new IllegalArgumentException( - "Depth must be -1 (unlimited) or >= 0."); - } - - this.depth = depth; - } - - /** - * Sets the knowledge to be used int the search. - * - * @param knowledge This knoweldge. - * @see Knowledge - */ - public void setKnowledge(Knowledge knowledge) { - this.knowledge = new Knowledge(knowledge); - } - - /** - * Returns the number of independence tests that were done. - * - * @return This number. - */ - public int getNumIndependenceTests() { - return this.numIndependenceTests; - } - - /** - * Returns the sepsets that were discovered in the search. A 'sepset' for test X _||_ Y | Z1,...,Zm would be - * {Z1,...,Zm} - * - * @return A map of these sepsets indexed by {X, Y}. - */ - public SepsetMap getSepsets() { - return this.sepset; - } - - /** - * Sets whether verbose output should be printed. - * - * @param verbose True iff the case. - */ - public void setVerbose(boolean verbose) { - this.verbose = verbose; - } - - /** - * Returns the elapsed time of the search. - * - * @return This elapsed time. - */ - public long getElapsedTime() { - return elapsedTime; - } - - /** - * Returns the nodes from the test. - * - * @return These nodes. - */ - @Override - public List getNodes() { - return this.test.getVariables(); - } - - /** - * There are no ambiguous triples for this search, for any nodes. - * - * @param node The nodes in question. - * @return An empty list. - */ - @Override - public List getAmbiguousTriples(Node node) { - return new ArrayList<>(); - } - - /** - * @param out This print stream. - */ - @Override - public void setOut(PrintStream out) { - this.out = out; - } - - /** - * @param pcHeuristic Which PC heuristic to use (see Causation, Prediction and Search). Default is - * PcHeuristicType.NONE. - * @see PcCommon.PcHeuristicType - */ - public void setPcHeuristicType(PcCommon.PcHeuristicType pcHeuristic) { - this.heuristic = pcHeuristic; - } - - /** - *

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; - } - - //==============================PRIVATE METHODS======================/ - - private int freeDegree(Map> adjacencies) { - int max = 0; - - for (Node x : adjacencies.keySet()) { - Set opposites = adjacencies.get(x); - - for (Node y : opposites) { - Set adjx = new LinkedHashSet<>(opposites); - adjx.remove(y); - - if (adjx.size() > max) { - max = adjx.size(); - } - } - } - - return max; - } - - private boolean searchAtDepth(Map scores, List edges, IndependenceTest test, Map> adjacencies, int depth) { - - for (Edge edge : edges) { - Node x = edge.getNode1(); - Node y = edge.getNode2(); - - if (Thread.currentThread().isInterrupted()) { - break; - } - - boolean b = checkSide(scores, test, adjacencies, depth, x, y); - if (!b) checkSide(scores, test, adjacencies, depth, y, x); - } - - return freeDegree(adjacencies) > depth; - } - - private boolean checkSide(Map scores, IndependenceTest test, Map> adjacencies, int depth, Node x, Node y) { - if (!adjacencies.get(x).contains(y)) return false; - - List _adjx = new ArrayList<>(adjacencies.get(x)); - _adjx.remove(y); - - if (this.heuristic == PcCommon.PcHeuristicType.HEURISTIC_1 || this.heuristic == PcCommon.PcHeuristicType.HEURISTIC_2) { - Collections.sort(_adjx); - } - - List ppx = possibleParents(x, _adjx, this.knowledge, y); - - Map scores2 = new HashMap<>(); - - for (Node node : ppx) { - Double _score = scores.get(Edges.undirectedEdge(node, x)); - scores2.put(node, _score); - } - - if (this.heuristic == PcCommon.PcHeuristicType.HEURISTIC_3) { - ppx.sort(Comparator.comparing(scores2::get)); - Collections.reverse(ppx); - } - - Graph g0 = new EdgeListGraph(getNodes()); - - if (ppx.size() >= depth) { - ChoiceGenerator cg = new ChoiceGenerator(ppx.size(), depth); - int[] choice; - - while ((choice = cg.next()) != null) { - if (Thread.currentThread().isInterrupted()) { - break; - } - - Set Z = GraphUtils.asSet(choice, ppx); - - this.numIndependenceTests++; - - boolean independent = test.checkIndependence(x, y, Z).isIndependent(); - - boolean noEdgeRequired = this.knowledge.noEdgeRequired(x.getName(), y.getName()); - - if (independent && noEdgeRequired) { - adjacencies.get(x).remove(y); - adjacencies.get(y).remove(x); - - getSepsets().set(x, y, Z); - - return true; - } - } - } - - return false; - } - - private List possibleParents(Node x, List adjx, - Knowledge knowledge, Node y) { - List possibleParents = new LinkedList<>(); - String _x = x.getName(); - - for (Node z : adjx) { - if (z == x) continue; - if (z == y) continue; - 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); - } -} - diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/GraspTol.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/GraspTol.java index cf6d3e5f42..f031c8e836 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/GraspTol.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/GraspTol.java @@ -384,8 +384,8 @@ public Graph getGraph(boolean cpDag) { if (this.scorer == null) throw new IllegalArgumentException("Please run algorithm first."); Graph graph = this.scorer.getGraph(cpDag); - NumberFormat nf = NumberFormatUtil.getInstance().getNumberFormat(); - graph.addAttribute("score ", nf.format(this.scorer.score())); +// NumberFormat nf = NumberFormatUtil.getInstance().getNumberFormat(); +// graph.addAttribute("score ", nf.format(this.scorer.score())); return graph; } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/HbsmsBeam.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/HbsmsBeam.java index 4cf15d1fe4..f0a1cf542a 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/HbsmsBeam.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/HbsmsBeam.java @@ -83,7 +83,7 @@ public HbsmsBeam(Graph graph, CovarianceMatrix cov, Knowledge knowledge) { public Graph search() { EdgeListGraph _graph = new EdgeListGraph(this.externalGraph); addRequiredEdges(_graph); - Graph bestGraph = GraphTransforms.dagFromCPDAG(_graph, null); + Graph bestGraph = GraphTransforms.dagFromCpdag(_graph, null); if (getGraph().getNumEdges() == 0) { System.out.println("Found one!"); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/HbsmsGes.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/HbsmsGes.java index debf8bf9d1..ccdc2a31c0 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/HbsmsGes.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/HbsmsGes.java @@ -166,7 +166,7 @@ private void saveModelIfSignificant(Graph graph) { } public Score scoreGraph(Graph graph) { - Graph dag = GraphTransforms.dagFromCPDAG(graph, getKnowledge()); + Graph dag = GraphTransforms.dagFromCpdag(graph, getKnowledge()); this.scorer.score(dag); return new Score(this.scorer); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/IndTestFisherZGeneralizedInverse.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/IndTestFisherZGeneralizedInverse.java deleted file mode 100644 index f7dafb2aa7..0000000000 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/IndTestFisherZGeneralizedInverse.java +++ /dev/null @@ -1,410 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// 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 cern.colt.matrix.DoubleMatrix1D; -import cern.colt.matrix.DoubleMatrix2D; -import cern.colt.matrix.impl.DenseDoubleMatrix2D; -import cern.colt.matrix.linalg.Algebra; -import cern.jet.math.Functions; -import edu.cmu.tetrad.data.DataSet; -import edu.cmu.tetrad.data.DataTransforms; -import edu.cmu.tetrad.graph.IndependenceFact; -import edu.cmu.tetrad.graph.Node; -import edu.cmu.tetrad.search.IndependenceTest; -import edu.cmu.tetrad.search.test.IndependenceResult; -import edu.cmu.tetrad.search.utils.LogUtilsSearch; -import edu.cmu.tetrad.util.*; -import org.apache.commons.math3.util.FastMath; - -import java.text.NumberFormat; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Set; - -/** - * Checks independence of X _||_ Y | Z for variables X and Y and list Z of variables. Partial correlations are - * calculated using generalized inverses, so linearly dependent variables do not throw exceptions. Must supply a - * continuous data set; don't know how to do this with covariance or correlation matrices. - * - * @author josephramsey - * @author Frank Wimberly adapted IndTestCramerT for Fisher's Z - */ -public final class IndTestFisherZGeneralizedInverse implements IndependenceTest { - - /** - * Formats as 0.0000. - */ - private static final NumberFormat nf = NumberFormatUtil.getInstance().getNumberFormat(); - /** - * The correlation matrix. - */ - private final DoubleMatrix2D data; - /** - * The variables of the correlation matrix, in order. (Unmodifiable list.) - */ - private final List variables; - private final DataSet dataSet; - /** - * The significance level of the independence tests. - */ - private double alpha; - /** - * The cutoff value for 'alpha' area in the two tails of the partial correlation distribution function. - */ - private double thresh = Double.NaN; - /** - * The value of the Fisher's Z statistic associated with the las calculated partial correlation. - */ - private double fishersZ; - private boolean verbose; - - //==========================CONSTRUCTORS=============================// - - /** - * Constructs a new Independence test which checks independence facts based on the correlation matrix implied by the - * given data set (must be continuous). The given significance level is used. - * - * @param dataSet A data set containing only continuous columns. - * @param alpha The alpha level of the test. - */ - public IndTestFisherZGeneralizedInverse(DataSet dataSet, double alpha) { - if (!(alpha >= 0 && alpha <= 1)) { - throw new IllegalArgumentException("Alpha mut be in [0, 1]"); - } - - this.dataSet = dataSet; - - this.data = new DenseDoubleMatrix2D(DataTransforms.center(this.dataSet).getDoubleData().toArray()); - this.variables = Collections.unmodifiableList(this.dataSet.getVariables()); - setAlpha(alpha); - } - - //==========================PUBLIC METHODS=============================// - - /** - * Creates a new IndTestCramerT instance for a subset of the variables. - */ - public IndependenceTest indTestSubset(List vars) { - return null; - } - - /** - * Determines whether variable x is independent of variable y given a list of conditioning variables z. - * - * @param xVar the one variable being compared. - * @param yVar the second variable being compared. - * @param _z the list of conditioning variables. - * @return True iff x _||_ y | z. - * @throws RuntimeException if a matrix singularity is encountered. - */ - public IndependenceResult checkIndependence(Node xVar, Node yVar, Set _z) { - if (_z == null) { - throw new NullPointerException(); - } - - for (Node node : _z) { - if (node == null) { - throw new NullPointerException(); - } - } - - List z = new ArrayList<>(_z); - Collections.sort(z); - - int size = z.size(); - int[] zCols = new int[size]; - - int xIndex = getVariables().indexOf(xVar); - int yIndex = getVariables().indexOf(yVar); - - for (int i = 0; i < z.size(); i++) { - zCols[i] = getVariables().indexOf(z.get(i)); - } - - int[] zRows = new int[this.data.rows()]; - for (int i = 0; i < this.data.rows(); i++) { - zRows[i] = i; - } - - DoubleMatrix2D Z = this.data.viewSelection(zRows, zCols); - DoubleMatrix1D x = this.data.viewColumn(xIndex); - DoubleMatrix1D y = this.data.viewColumn(yIndex); - DoubleMatrix2D Zt = new Algebra().transpose(Z); - DoubleMatrix2D ZtZ = new Algebra().mult(Zt, Z); - Matrix _ZtZ = new Matrix(ZtZ.toArray()); - Matrix ginverse = _ZtZ.inverse(); - DoubleMatrix2D G = new DenseDoubleMatrix2D(ginverse.toArray()); - - DoubleMatrix2D Zt2 = Zt.like(); - Zt2.assign(Zt); - DoubleMatrix2D GZt = new Algebra().mult(G, Zt2); - - DoubleMatrix1D b_x = new Algebra().mult(GZt, x); - DoubleMatrix1D b_y = new Algebra().mult(GZt, y); - - DoubleMatrix1D xPred = new Algebra().mult(Z, b_x); - DoubleMatrix1D yPred = new Algebra().mult(Z, b_y); - - DoubleMatrix1D xRes = xPred.copy().assign(x, Functions.minus); - DoubleMatrix1D yRes = yPred.copy().assign(y, Functions.minus); - - // Note that r will be NaN if either xRes or yRes is constant. - double r = StatUtils.correlation(xRes.toArray(), yRes.toArray()); - - if (Double.isNaN(this.thresh)) { - this.thresh = cutoffGaussian(); - } - - if (Double.isNaN(r)) { - if (this.verbose) { - TetradLogger.getInstance().log("independencies", LogUtilsSearch.independenceFactMsg(xVar, yVar, _z, getPValue())); - } - return new IndependenceResult(new IndependenceFact(xVar, yVar, _z), false, Double.NaN, Double.NaN); - } - - if (r > 1) r = 1; - if (r < -1) r = -1; - - this.fishersZ = FastMath.sqrt(sampleSize() - z.size() - 3.0) * - 0.5 * (FastMath.log(1.0 + r) - FastMath.log(1.0 - r)); - - if (Double.isNaN(this.fishersZ)) { - throw new IllegalArgumentException("The Fisher's Z " + - "score for independence fact " + xVar + " _||_ " + yVar + - " | " + z + " is undefined."); - } - - boolean indFisher = !(FastMath.abs(this.fishersZ) > this.thresh); - - //System.out.println("thresh = " + thresh); - //if(FastMath.abs(fishersZ) > 1.96) indFisher = false; //Two sided with alpha = 0.05 - //Two sided - - if (this.verbose) { - TetradLogger.getInstance().log("independencies", LogUtilsSearch.independenceFactMsg(xVar, yVar, _z, getPValue())); - } - - if (Double.isNaN(getPValue())) { - throw new RuntimeException("Undefined p-value encountered for test: " + LogUtilsSearch.independenceFact(xVar, yVar, _z)); - } - - if (this.verbose) { - if (indFisher) { - TetradLogger.getInstance().forceLogMessage( - LogUtilsSearch.independenceFactMsg(xVar, yVar, _z, getPValue())); - } - } - - return new IndependenceResult(new IndependenceFact(xVar, yVar, _z), indFisher, getPValue(), getAlpha() - getPValue()); - } - - /** - * @return the probability associated with the most recently computed independence test. - */ - public double getPValue() { - return 2.0 * (1.0 - RandomUtil.getInstance().normalCdf(0, 1, FastMath.abs(this.fishersZ))); - } - - /** - * Gets the getModel significance level. - */ - public double getAlpha() { - return this.alpha; - } - - /** - * Sets the significance level at which independence judgments should be made. Affects the cutoff for partial - * correlations to be considered statistically equal to zero. - */ - public void setAlpha(double alpha) { - if (alpha < 0.0 || alpha > 1.0) { - throw new IllegalArgumentException("Significance out of range."); - } - - this.alpha = alpha; - } - - /** - * @return the list of variables over which this independence checker is capable of determinine independence - * relations-- that is, all the variables in the given graph or the given data set. - */ - public List getVariables() { - return this.variables; - } - - /** - * @return the variable with the given name. - */ - - - public String toString() { - return "Fisher's Z - Generalized Inverse, alpha = " + IndTestFisherZGeneralizedInverse.nf.format(getAlpha()); - } - - /** - * Returns the data being analyzed. - * - * @return This data. - */ - public DataSet getData() { - return this.dataSet; - } - - /** - * Returns True just in case verbose output should be printed. - * - * @return This. - */ - public boolean isVerbose() { - return this.verbose; - } - - /** - * Sets whether verbose output should be printed. - * - * @param verbose True, if so. - */ - public void setVerbose(boolean verbose) { - this.verbose = verbose; - } - - /** - * Returns true just in case the varialbe in zList determine xVar. - * - * @return True, if so. - */ - public boolean determines(List zList, Node xVar) { - if (zList == null) { - throw new NullPointerException(); - } - - if (zList.isEmpty()) { - return false; - } - - for (Node node : zList) { - if (node == null) { - throw new NullPointerException(); - } - } - - int size = zList.size(); - int[] zCols = new int[size]; - - int xIndex = getVariables().indexOf(xVar); - - for (int i = 0; i < zList.size(); i++) { - zCols[i] = getVariables().indexOf(zList.get(i)); - } - - int[] zRows = new int[this.data.rows()]; - for (int i = 0; i < this.data.rows(); i++) { - zRows[i] = i; - } - - DoubleMatrix2D Z = this.data.viewSelection(zRows, zCols); - DoubleMatrix1D x = this.data.viewColumn(xIndex); - DoubleMatrix2D Zt = new Algebra().transpose(Z); - DoubleMatrix2D ZtZ = new Algebra().mult(Zt, Z); - - Matrix _ZtZ = new Matrix(ZtZ.toArray()); - Matrix ginverse = _ZtZ.inverse(); - DoubleMatrix2D G = new DenseDoubleMatrix2D(ginverse.toArray()); - -// DoubleMatrix2D G = MatrixUtils.ginverse(ZtZ); - DoubleMatrix2D Zt2 = Zt.copy(); - DoubleMatrix2D GZt = new Algebra().mult(G, Zt2); - DoubleMatrix1D b_x = new Algebra().mult(GZt, x); - DoubleMatrix1D xPred = new Algebra().mult(Z, b_x); - DoubleMatrix1D xRes = xPred.copy().assign(x, Functions.minus); - double SSE = xRes.aggregate(Functions.plus, Functions.square); - - double variance = SSE / (this.data.rows() - (zList.size() + 1)); - - boolean determined = variance < getAlpha(); - - if (determined) { - StringBuilder sb = new StringBuilder(); - sb.append("Determination found: ").append(xVar).append( - " is determined by {"); - - for (int i = 0; i < zList.size(); i++) { - sb.append(zList.get(i)); - - if (i < zList.size() - 1) { - sb.append(", "); - } - } - - sb.append("}"); - -// sb.append(" p = ").append(nf.format(p)); - sb.append(" SSE = ").append(IndTestFisherZGeneralizedInverse.nf.format(SSE)); - - TetradLogger.getInstance().log("independencies", sb.toString()); - System.out.println(sb); - } - - return determined; - } - - /** - * Computes that value x such that P(abs(N(0,1) > x) < alpha. Note that this is a two sided test of the null - * hypothesis that the Fisher's Z value, which is distributed as N(0,1) is not equal to 0.0. - */ - private double cutoffGaussian() { - double upperTail = 1.0 - getAlpha() / 2.0; - final double epsilon = 1e-14; - - // Find an upper bound. - double lowerBound = -1.0; - double upperBound = 0.0; - - while (RandomUtil.getInstance().normalCdf(0, 1, upperBound) < upperTail) { - lowerBound += 1.0; - upperBound += 1.0; - } - - while (upperBound >= lowerBound + epsilon) { - double midPoint = lowerBound + (upperBound - lowerBound) / 2.0; - - if (RandomUtil.getInstance().normalCdf(0, 1, midPoint) <= upperTail) { - lowerBound = midPoint; - } else { - upperBound = midPoint; - } - } - - return lowerBound; - } - - private int sampleSize() { - return this.data.rows(); - } -} - - - - - diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/README.txt b/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/README.txt deleted file mode 100644 index 429e929595..0000000000 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/search/work_in_progress/README.txt +++ /dev/null @@ -1,2 +0,0 @@ -These classes are put here in the "Work In Progress" directory because -they're either old (but not disposable) or require more work. \ No newline at end of file diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/sem/SemIm.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/sem/SemIm.java index 6f0a62aca9..47d3d5fe81 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/sem/SemIm.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/sem/SemIm.java @@ -1033,15 +1033,12 @@ public double getTruncLL() { */ public double getBicScore() { int dof = getSemPm().getDof(); -// return getChiSquare() - dof * FastMath.log(sampleSize); - return getChiSquare() - dof * FastMath.log(this.sampleSize); } @Override public double getRmsea() { - double v = getChiSquare() - this.semPm.getDof(); double v1 = this.semPm.getDof() * (getSampleSize() - 1); return sqrt(v) / sqrt(v1); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/sem/SemXmlParser.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/sem/SemXmlParser.java index fe6e7e6e7b..829e1ff50a 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/sem/SemXmlParser.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/sem/SemXmlParser.java @@ -108,7 +108,7 @@ private static SemIm makeEdges(Element edgesElement, Dag semGraph) { edge = edges.get(i); causeNode = semGraph.getNode(edge.getAttributeValue(SemXmlConstants.CAUSE_NODE)); effectNode = semGraph.getNode(edge.getAttributeValue(SemXmlConstants.EFFECT_NODE)); - semIm.setParamValue(causeNode, effectNode, new Double(edge.getAttributeValue(SemXmlConstants.COEF))); + semIm.setParamValue(causeNode, effectNode, Double.parseDouble(edge.getAttributeValue(SemXmlConstants.COEF))); //semIm.getSemPm().getParameter(causeNode, effectNode).setFixed(new Boolean(edge.getAttributeValue(SemXmlConstants.FIXED)).booleanValue()); Parameter covarianceParameter = semIm.getSemPm().getCovarianceParameter(causeNode, effectNode); @@ -153,7 +153,7 @@ private static void addMarginalErrorDistribution(Element marginalDistributionEle node = graph.getExogenous(graph.getNode(normal.getAttributeValue(SemXmlConstants.VARIABLE))); //can't set mean at this point... - semIm.setParamValue(node, node, new Double(normal.getAttributeValue(SemXmlConstants.VARIANCE))); + semIm.setParamValue(node, node, Double.parseDouble(normal.getAttributeValue(SemXmlConstants.VARIANCE))); } } @@ -170,7 +170,7 @@ private static void addJointErrorDistribution(Element jointDistributionElement, normal = normals.get(i); node1 = semIm.getSemPm().getGraph().getExogenous(semIm.getSemPm().getGraph().getNode(normal.getAttributeValue(SemXmlConstants.NODE_1))); node2 = semIm.getSemPm().getGraph().getExogenous(semIm.getSemPm().getGraph().getNode(normal.getAttributeValue(SemXmlConstants.NODE_2))); - semIm.setParamValue(node1, node2, new Double(normal.getAttributeValue(SemXmlConstants.COVARIANCE))); + semIm.setParamValue(node1, node2, Double.parseDouble(normal.getAttributeValue(SemXmlConstants.COVARIANCE))); } } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/simulation/HsimAutoC.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/simulation/HsimAutoC.java index c01171c804..9aeb4f6bfd 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/simulation/HsimAutoC.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/simulation/HsimAutoC.java @@ -71,7 +71,7 @@ public double[] run(int resimSize) { Graph estGraph = fges.search(); //if (verbose) System.out.println(estGraph); - Graph estGraphDAG = GraphTransforms.dagFromCPDAG(estGraph, null); + Graph estGraphDAG = GraphTransforms.dagFromCpdag(estGraph, null); Dag estDAG = new Dag(estGraphDAG); //Dag estDAG = new Dag(estGraph); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/simulation/HsimAutoRun.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/simulation/HsimAutoRun.java index 9c37e02850..f07619227b 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/simulation/HsimAutoRun.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/simulation/HsimAutoRun.java @@ -89,7 +89,7 @@ public double[] run(int resimSize) { //if (verbose) System.out.println(estGraph); Graph estCPDAG = new EdgeListGraph(estGraph); - Graph estGraphDAG = GraphTransforms.dagFromCPDAG(estCPDAG, null); + Graph estGraphDAG = GraphTransforms.dagFromCpdag(estCPDAG, null); Dag estDAG = new Dag(estGraphDAG); //===========Identify the nodes to be resimulated=========== diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/simulation/HsimEvalFromData.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/simulation/HsimEvalFromData.java index ca82e2e486..d4919e452a 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/simulation/HsimEvalFromData.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/simulation/HsimEvalFromData.java @@ -89,7 +89,7 @@ public static void main(String[] args) { for (whichFrepeat = 0; whichFrepeat < fsimRepeat.size(); whichFrepeat++) { ArrayList errorsList = new ArrayList<>(); for (int r = 0; r < fsimRepeat.get(whichFrepeat); r++) { - Graph fgsDag = GraphTransforms.dagFromCPDAG(oFGSGraph, null); + Graph fgsDag = GraphTransforms.dagFromCpdag(oFGSGraph, null); Dag fgsdag2 = new Dag(fgsDag); //then fit an IM to this dag and the data. GeneralizedSemEstimator seems to bug out diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/simulation/HsimRobustCompare.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/simulation/HsimRobustCompare.java index 86f9911c9a..d70b675050 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/simulation/HsimRobustCompare.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/simulation/HsimRobustCompare.java @@ -64,7 +64,7 @@ public static List run(int numVars, double edgesPerNode, int numCases, //create various simulated data sets ////let's do the full simulated data set first: a dag in the FGES CPDAG fit to the data set. - Graph fgesDag = GraphTransforms.dagFromCPDAG(oGraphOut, null); + Graph fgesDag = GraphTransforms.dagFromCpdag(oGraphOut, null); Dag fgesdag2 = new Dag(fgesDag); BayesPm simBayesPm = new BayesPm(fgesdag2, bayesPm); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/simulation/HsimRun.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/simulation/HsimRun.java index f4b9d720bb..a779fbe92d 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/simulation/HsimRun.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/simulation/HsimRun.java @@ -49,7 +49,7 @@ public static void run(String readfilename, String filenameOut, char delimiter, System.out.println(estGraph); Graph estCPDAG = new EdgeListGraph(estGraph); - Graph estGraphDAG = GraphTransforms.dagFromCPDAG(estCPDAG, null); + Graph estGraphDAG = GraphTransforms.dagFromCpdag(estCPDAG, null); Dag estDAG = new Dag(estGraphDAG); //===========Identify the nodes to be resimulated=========== diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/study/RBExperiments.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/study/RBExperiments.java index 6828eefd88..d27ec0165f 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/study/RBExperiments.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/study/RBExperiments.java @@ -187,7 +187,7 @@ public void experiment(String modelName, int numCases, int numModels, int numBoo // learn structure of constraints using empirical data Graph depCPDAG = runFGS(depData); - Graph estDepBN = GraphTransforms.dagFromCPDAG(depCPDAG, null); + Graph estDepBN = GraphTransforms.dagFromCpdag(depCPDAG, null); System.out.println("estDepBN: " + estDepBN.getEdges()); out.println("DepGraph(nodes,edges):" + estDepBN.getNumNodes() + "," + estDepBN.getNumEdges()); System.out.println("Dependency graph done!"); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/study/examples/conditions/ExampleCompareSimulationDiscrete.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/study/examples/conditions/ExampleCompareSimulationDiscrete.java index 157dbf11ea..c0793409b6 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/study/examples/conditions/ExampleCompareSimulationDiscrete.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/study/examples/conditions/ExampleCompareSimulationDiscrete.java @@ -27,7 +27,7 @@ import edu.cmu.tetrad.algcomparison.algorithm.oracle.cpdag.Pc; import edu.cmu.tetrad.algcomparison.graph.RandomForward; import edu.cmu.tetrad.algcomparison.independence.ChiSquare; -import edu.cmu.tetrad.algcomparison.independence.Gsquare; +import edu.cmu.tetrad.algcomparison.independence.GSquare; import edu.cmu.tetrad.algcomparison.score.BdeuScore; import edu.cmu.tetrad.algcomparison.score.ConditionalGaussianBicScore; import edu.cmu.tetrad.algcomparison.score.DiscreteBicScore; @@ -88,7 +88,7 @@ public static void main(String... args) { Algorithms algorithms = new Algorithms(); algorithms.add(new Pc(new ChiSquare())); - algorithms.add(new Pc(new Gsquare())); + algorithms.add(new Pc(new GSquare())); // algorithms.add(new Fges(new BdeuScore())); algorithms.add(new Fges(new DiscreteBicScore())); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/study/gene/tetrad/gene/algorithm/biolingua/Biolingua.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/study/gene/tetrad/gene/algorithm/biolingua/Biolingua.java index b46dca415c..e3d508137b 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/study/gene/tetrad/gene/algorithm/biolingua/Biolingua.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/study/gene/tetrad/gene/algorithm/biolingua/Biolingua.java @@ -36,22 +36,12 @@ public class Biolingua { private static final float ALMOST_ZERO = (float) 0.00001; - // private static final double LOG_2 = FastMath.log(2); - - // TODO: consider making the signif level another parameter of the algorithm private static final float SIGNIF_LEVEL = (float) 0.05; - - // TODO: these values are part of what is rather ad hoc and - // questionable in the paper, I will report on different - // behaviors of the algorithm having different values here. private static float bitsAnnotat = (float) .1; private static float bitsErrors = (float) 3; private static float bitsLinks = (float) 4; private static float bitsPredic = (float) 3; - - // TODO: add comments describing each of these static vars private static int nvars; - // private static BiolinguaDigraph origG; private static BiolinguaDigraph g; private static SymMatrixF cm; private static SymMatrixF sm; @@ -59,15 +49,12 @@ public class Biolingua { private static boolean[] visited; private static boolean cycle; private static int targetParent; - private static float emtempG; private static float emCurrentModel; private static float em1StepBest; - private static int bestEnode1; private static int bestEnode2; private static int bestChange; - private static int pos; private static int neg; @@ -78,8 +65,11 @@ private Biolingua() { /** * Runs the biolingua algorithm using the given correlation matrix (all values are assumed significant) and the * initial graph, and uses some default values for the coefficients in the evaluation metric for annotations, - * errors, links, and predictions. Returns the graph found after the search stopped improving the evaluation metric. - * TODO: include Javadoc explanations of k* + * errors, links, and predictions. Returns the graph found after the search stopped improving the evaluation + * metric. + * + * @param correlMatrix the correlation matrix + * @param initGraph the initial graph */ public static synchronized BiolinguaDigraph BiolinguaAlgorithm( SymMatrixF correlMatrix, BiolinguaDigraph initGraph) { @@ -97,6 +87,12 @@ public static synchronized BiolinguaDigraph BiolinguaAlgorithm( * Runs the biolingua algorithm using the given correlation matrix (all values are assumed significant), an initial * graph, and the coefficients in the evaluation metric for annotations, errors, links, and predictions. Returns the * graph found after the search stopped improving the evaluation metric. + * @param correlMatrix the correlation matrix + * @param initGraph the initial graph + * @param vBitsAnnotat the coefficient for annotations in the evaluation metric + * @param vBitsErrors the coefficient for errors in the evaluation metric + * @param vbitsLinks the coefficient for links in the evaluation metric + * @param vBitsPredic the coefficient for predictions in the evaluation metric */ public static synchronized BiolinguaDigraph BiolinguaAlgorithm( SymMatrixF correlMatrix, BiolinguaDigraph initGraph, @@ -110,6 +106,13 @@ public static synchronized BiolinguaDigraph BiolinguaAlgorithm( * Runs the biolingua algorithm using the given correlation matrix, significance matrix, the initial graph, and the * coefficients in the evaluation metric for annotations, errors, links, and predictions. Returns the graph found * after the search stopped improving the evaluation metric. + * @param correlMatrix the correlation matrix + * @param signifMatrix the significance matrix + * @param initGraph the initial graph + * @param vBitsAnnotat the coefficient for annotations in the evaluation metric + * @param vBitsErrors the coefficient for errors in the evaluation metric + * @param vbitsLinks the coefficient for links in the evaluation metric + * @param vBitsPredic the coefficient for predictions in the evaluation metric */ public static synchronized BiolinguaDigraph BiolinguaAlgorithm( SymMatrixF correlMatrix, SymMatrixF signifMatrix, @@ -118,7 +121,6 @@ public static synchronized BiolinguaDigraph BiolinguaAlgorithm( return Biolingua.doBiolinguaAlgorithm(correlMatrix, signifMatrix, initGraph, vbitsLinks, vBitsPredic, vBitsAnnotat, vBitsErrors); } - private static BiolinguaDigraph doBiolinguaAlgorithm( SymMatrixF correlMatrix, SymMatrixF signifMatrix, BiolinguaDigraph initGraph, float vBitsAnnotat, float vBitsErrors, @@ -245,6 +247,7 @@ private static BiolinguaDigraph doBiolinguaAlgorithm( * accordingly.

Count the # of predictions that agree with the input correlation matrix given to Biolingua, as * well as the # of errors (erroneous predictions) After checking all undirectedPaths, compute the evaluation * metric + * @return the evaluation metric for the current model */ private static float evalCurrentModel() { int annotations = 0; @@ -287,7 +290,7 @@ private static float evalCurrentModel() { // Determine the predicted sign according to all undirectedPaths // between these variables int predictedSign = - ((Biolingua.pos == Biolingua.neg) ? 0 : (Biolingua.pos > Biolingua.neg ? 1 : -1)); + (Integer.compare(Biolingua.pos, Biolingua.neg)); // Value of edge between vi and vj in the correlation matrix float correlValue = Biolingua.cm.getValue(vi, vj); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/study/gene/tetrad/gene/algorithm/biolingua/BiolinguaDigraph.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/study/gene/tetrad/gene/algorithm/biolingua/BiolinguaDigraph.java index e5c2606894..6ba3aefc81 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/study/gene/tetrad/gene/algorithm/biolingua/BiolinguaDigraph.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/study/gene/tetrad/gene/algorithm/biolingua/BiolinguaDigraph.java @@ -92,6 +92,7 @@ public Object clone() { * * @param p the parent node * @param c the child node + * @return true if node p is parent of node c. */ public boolean isParent(int p, int c) { return (this.getEdges().getDoubleValue(p, c) != 0.0); @@ -100,6 +101,7 @@ public boolean isParent(int p, int c) { /** * Returns a string with the indexes of all parents of node i separated by spaces (useful for printouts) * @param i the node whose parents are requested + * @return a string with the indexes of all parents of node i separated by spaces */ public String strOfParents(int i) { int[] ap = this.getParents(i); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/study/gene/tetrad/gene/algorithm/biolingua/BiolinguaRunner.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/study/gene/tetrad/gene/algorithm/biolingua/BiolinguaRunner.java index 95e101dc01..a34c6d095e 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/study/gene/tetrad/gene/algorithm/biolingua/BiolinguaRunner.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/study/gene/tetrad/gene/algorithm/biolingua/BiolinguaRunner.java @@ -81,6 +81,11 @@ static void bailout(String errorMsg, int exitCode) { System.exit(exitCode); } + /** + * Main method, runs the Biolingua algorithm + * + * @param args command line arguments + */ public static void main(String[] args) { if ((args.length > 0) && (args[0].equals("/?"))) { // Help invoked, or no arguments -> show usage info diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/study/gene/tetrad/gene/algorithm/biolingua/Digraph.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/study/gene/tetrad/gene/algorithm/biolingua/Digraph.java index 94fb87fa9f..65c385acc5 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/study/gene/tetrad/gene/algorithm/biolingua/Digraph.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/study/gene/tetrad/gene/algorithm/biolingua/Digraph.java @@ -51,7 +51,7 @@ public class Digraph extends BasicGraph { /** * Creates a OldDigraph with gName name, and n nodes. * - * @param gName the name of the graph + * @param gName the name of the graph * @param nNodes the number of nodes */ public Digraph(String gName, int nNodes) { @@ -69,6 +69,8 @@ public Digraph(String fname) throws IOException { /** * Copy constructor. + * + * @param digraph the graph to copy. */ public Digraph(Digraph digraph) { this("Clone_of_[" + digraph + "]", digraph.nNodes); @@ -82,6 +84,7 @@ public Digraph(Digraph digraph) { /** * Returns a clone of this graph + * @return a clone of this graph */ public Object clone() { Digraph g2 = @@ -105,8 +108,9 @@ protected void initializeEdges() { /** * Sets a value of edge between nodes i and j - * @param i the first node - * @param j the second node + * + * @param i the first node + * @param j the second node * @param value the value of the edge */ public void setEdge(int i, int j, double value) { @@ -125,8 +129,10 @@ public void setEdge(int i, int j, double value) { /** * Returns the value of edge between nodes i and j + * * @param i the first node * @param j the second node + * @return the value of edge between nodes i and j */ public double getEdge(int i, int j) { return this.getEdges().getDoubleValue(i, j); @@ -134,6 +140,7 @@ public double getEdge(int i, int j) { /** * Returns a string representation of the set of edges in this graph + * * @return a string representation of the set of edges in this graph. */ public String EdgesToString() { @@ -154,6 +161,7 @@ public String EdgesToString() { /** * Returns the number of parents of node i. + * * @param i the node * @return the number of parents of node i. */ @@ -167,7 +175,9 @@ public int getNumParents(int i) { /** * Returns an array with the indexes of the parents of node i. If node i has no parents it returns an array of size * 0 (e.g. not null) + * * @param j the index of the node + * @return */ public int[] getParents(int j) { if ((j < 0) || (j >= this.nNodes)) { @@ -186,6 +196,7 @@ public int[] getParents(int j) { /** * Returns the edge matrix. + * * @return the edge matrix. */ public MatrixF getEdges() { diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/study/gene/tetrad/gene/history/BooleanFunction.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/study/gene/tetrad/gene/history/BooleanFunction.java index 1c2db5b9e2..11d05df60c 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/study/gene/tetrad/gene/history/BooleanFunction.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/study/gene/tetrad/gene/history/BooleanFunction.java @@ -26,6 +26,7 @@ import java.io.IOException; import java.io.ObjectInputStream; +import java.io.Serial; /** * Stores a boolean function from a set of boolean-valued parents to a single boolean-valued column. @@ -33,21 +34,14 @@ * @author josephramsey */ public class BooleanFunction implements TetradSerializable { + @Serial private static final long serialVersionUID = 23L; - /** - * The array of parents for the stored boolean function. - * - * @serial - */ + // The array of parents for the stored boolean function. private final IndexedParent[] parents; - /** - * The stored boolean function. The order of the rows (for the given parents array, for two parents) is 00, 01, 10, - * 11, and so on for higher numbers of parents. - * - * @serial - */ + // The stored boolean function. The order of the rows (for the given parents array, for two parents) is 00, 01, 10, + // 11, and so on for higher numbers of parents. private final boolean[] lookupTable; //==============================CONSTRUCTORS=========================// @@ -81,6 +75,7 @@ public BooleanFunction(IndexedParent[] parents) { /** * Generates a simple exemplar of this class to test serialization. + * @return a simple exemplar of this class to test serialization. */ public static BooleanFunction serializableInstance() { IndexedParent[] parents = new IndexedParent[2]; @@ -105,6 +100,8 @@ public Object[] getParents() { * values, use the method * getRow * + * @param row the row of the table. + * @return the value in the table. * @see #getRow */ public boolean getValue(int row) { @@ -116,6 +113,8 @@ public boolean getValue(int row) { * values, use the method * getRow * + * @param row the row of the table. + * @param value the value to set. * @see #getRow */ public void setValue(int row, boolean value) { @@ -133,6 +132,7 @@ public void setValue(int row, boolean value) { * * @param parentValues an array of parent values. Should be in the same order as the parents, as returned by * getParents. + * @return the row of the table. * @see #getParents */ public int getRow(boolean[] parentValues) { @@ -148,14 +148,15 @@ public int getRow(boolean[] parentValues) { } /** - * Returns the number of rows in the table. + * @return the number of rows in the table. */ public int getNumRows() { return this.lookupTable.length; } /** - * Returns the combination of parent values represented by a given row in the table. + * @param row the row of the table. + * @return the combination of parent values represented by a given row in the table. */ public boolean[] getParentValues(int row) { @@ -188,6 +189,8 @@ public void randomize() { * "I define as a canalyzing Boolean function any Boolean function having the property that it has at least one * input having at least one value (1 or 0) which suffices to guarantee that the regulated element assumes a * specific value (1 or 0)" (page 203-4). + * + * @return true if the getModel function is canalyzing, false if not. */ public boolean isCanalyzing() { @@ -210,23 +213,19 @@ public boolean isCanalyzing() { int value = this.lookupTable[row] ? 1 : 0; int parentValue = (row / jump) % 2 == 0 ? 1 : 0; - if (-2 == lastValues[parentValue]) { - - // The pattern's already been broken for this - // value. - } else if (value == lastValues[parentValue]) { + if (-2 != lastValues[parentValue]) { + if (value != lastValues[parentValue]) { + if (-1 == lastValues[parentValue]) { - // We're in the middle of a pattern for this - // value; keep going. - } else if (-1 == lastValues[parentValue]) { + // We're encountering this parent value for the + // first time. + lastValues[parentValue] = value; + } else { - // We're encountering this parent value for the - // first time. - lastValues[parentValue] = value; - } else { - - // The pattern has just been broken. - lastValues[parentValue] = -2; + // The pattern has just been broken. + lastValues[parentValue] = -2; + } + } } } @@ -301,19 +300,12 @@ public String toString() { * semantic checks can be specified and do not need to stay the same from version to version. A readObject method of * this form may be added to any class, even if Tetrad sessions were previously saved out using a version of the * class that didn't include it. (That's what the "s.defaultReadObject();" is for. See J. Bloch, Effective Java, for - * help. + * help.) */ + @Serial private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); - - if (this.parents == null) { - throw new NullPointerException(); - } - - if (this.lookupTable == null) { - throw new NullPointerException(); - } } } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/study/gene/tetrad/gene/history/BooleanGlassFunction.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/study/gene/tetrad/gene/history/BooleanGlassFunction.java index 562dcfa3d1..3a94ff69c2 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/study/gene/tetrad/gene/history/BooleanGlassFunction.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/study/gene/tetrad/gene/history/BooleanGlassFunction.java @@ -27,85 +27,51 @@ import java.io.IOException; import java.io.ObjectInputStream; +import java.io.Serial; import java.util.ArrayList; import java.util.List; /** - *

Updates a gene given a history using the formula Gi.0 = max(Gi.1 - - * decayRate * -Gi.1 + booleanInfluenceRate * F(Parents(Gi) in the graph \ Gi.1), lowerBound), as described in Edwards - * and Glass, (2000), "Combinatorial explosion in model gene networks", American Institute of Physics. F is a function - * from R^n to R, where each input to the function is sent to -1.0 if it is < 0.0 and +1.0 if is it >= 0.0 and the - * combination of -1.0's and +1.0's is then used to look up a value in a boolean table. The output of the function is - * -1.0 or 1.0. A random boolean Glass fuction is a boolean Glass function in which the boolean lookup table is chosen - * randomly. The procedure used here is as follows. For each factor fi, the lag graph supplied in the constructor - * specifies a set of causal parents among the lagged factors. If fi:1 appears as a causal parent, it is removed from - * the set. The result is a set of n causal parents. A random boolean function is constructed for these n causal - * parents (with 2^n rows) for which each causal parent is "effective"--that is, for which there is some combination of - * the other causal parents for which the lookup table maps either to true or to false depending on the value of the - * given causal parent.

The basal expression level is used in these functions as a threshold, above which a lookup - * value of true is used for the boolean tables and below which a lookup value of false is - * used. A return value of - * true from the boolean lookup is then mapped to some double - * value, which we call the the "true value," and a return value of - * false is mapped to some other (lesser) double value, which we - * call the "false value." The authors allow for the possibility of setting the basal expression to 0.5 and using 0.0 as - * the false value and 1.0 as the true value. Generalizing, we include a constructor to allow the basalExpression, true - * value and false value to be set by the user, with the only condition being that the false value must be less than the - * true value. + * Updates a gene given a history using the formula Gi.0 = max(Gi.1 - decayRate * -Gi.1 + booleanInfluenceRate * + * F(Parents(Gi) in the graph \ Gi.1), lowerBound), as described in Edwards and Glass, (2000), "Combinatorial explosion + * in model gene networks", American Institute of Physics. F is a function from R^n to R, where each input to the + * function is sent to -1.0 if it is < 0.0 and +1.0 if is it >= 0.0 and the combination of -1.0's and +1.0's is + * then used to look up a value in a boolean table. The output of the function is -1.0 or 1.0. A random boolean Glass + * fuction is a boolean Glass function in which the boolean lookup table is chosen randomly. The procedure used here is + * as follows. For each factor fi, the lag graph supplied in the constructor specifies a set of causal parents among + * the lagged factors. If fi:1 appears as a causal parent, it is removed from the set. The result is a set of n causal + * parents. A random boolean function is constructed for these n causal parents (with 2^n rows) for which each causal + * parent is "effective"--that is, for which there is some combination of the other causal parents for which the lookup + * table maps either to true or to false depending on the value of the given causal parent. + *

+ * The basal expression level is used in these functions as a threshold, above which a lookup value of true is used for + * the boolean tables and below which a lookup value of false is used. A return value of true from the boolean lookup is + * then mapped to some double value, which we call the "true value," and a return value of false is mapped to some + * other (lesser) double value, which we call the "false value." The authors allow for the possibility of setting the + * basal expression to 0.5 and using 0.0 as the false value and 1.0 as the true value. Generalizing, we include a + * constructor to allow the basalExpression, true value and false value to be set by the user, with the only condition + * being that the false value must be less than the true value. * * @author josephramsey */ public class BooleanGlassFunction implements UpdateFunction { - private static final long serialVersionUID = 23L; - /** - * The indexed connectivity "snapshot" of the lag graph. - * - * @serial - */ + @Serial + private static final long serialVersionUID = 23L; + // The indexed connectivity "snapshot" of the lag graph. private final IndexedLagGraph connectivity; - - /** - * Stores a boolean function for each factor from a preselected set of lagged factors to the given factor. - * - * @serial - */ + // Stores a boolean function for each factor from a preselected set of lagged factors to the given factor. private final BooleanFunction[] booleanFunctions; - - /** - * Error distributions from which errors are drawn for each of the factors. - * - * @serial - */ + // Error distributions from which errors are drawn for each of the factors. private final Distribution[] errorDistributions; - - /** - * The lower bound for expression levels. Expression levels that wander below this bound will be set to this bound. - * - * @serial - */ + // The lower bound for expression levels. Expression levels that wander below this bound will be set to this bound. private double lowerBound; - - /** - * The basalExpression for determining whether history expression levels should be mapped to "true" or "false" for - * purposes of looking up output values in the Boolean function table. - * - * @serial - */ + // The basalExpression for determining whether history expression levels should be mapped to "true" or "false" for + // purposes of looking up output values in the Boolean function table. private double basalExpression; - - /** - * The rate at which expression levels for a gene tend to return to basal level. - * - * @serial - */ + // The rate at which expression levels for a gene tend to return to basal level. private double decayRate; - - /** - * The rate at which the F function (with outputs -1 and +1) affects the update for a gene. - * - * @serial - */ + // The rate at which the F function (with outputs -1 and +1) affects the update for a gene. private double booleanInfluenceRate; //=============================CONSTRUCTORS=========================// @@ -170,13 +136,13 @@ public BooleanGlassFunction(LagGraph lagGraph, double lowerBound, // The parents of the boolean function have to be // IndexedParent's and cannot include the factor // itself one time step back. - List parentList = new ArrayList(); + List parentList = new ArrayList<>(); for (int j = 0; j < this.connectivity.getNumParents(i); j++) { IndexedParent parent = this.connectivity.getParent(i, j); parentList.add(parent); } - IndexedParent[] parents = (IndexedParent[]) parentList.toArray( + IndexedParent[] parents = parentList.toArray( new IndexedParent[0]); this.booleanFunctions[i] = new BooleanFunction(parents); @@ -200,17 +166,15 @@ public static BooleanGlassFunction serializableInstance() { return new BooleanGlassFunction(BasicLagGraph.serializableInstance()); } - //===============================PUBLIC METHODS========================// - /** - * Returns the indexed connectivity. + * @return the indexed connectivity. */ public IndexedLagGraph getIndexedLagGraph() { return this.connectivity; } /** - * Returns the basalExpression. + * @return the basalExpression. */ public double getBasalExpression() { return this.basalExpression; @@ -218,6 +182,8 @@ public double getBasalExpression() { /** * Sets the basalExpression. + * + * @param basalExpression the new basalExpression. */ public void setBasalExpression(double basalExpression) { this.basalExpression = basalExpression; @@ -225,6 +191,10 @@ public void setBasalExpression(double basalExpression) { /** * Returns the value of the function. + * + * @param factor the index of the factor to calculate a new value for. + * @param history the history using which the new value is to be calculated. + * @return the value of the function. */ public double getValue(int factor, double[][] history) { // 2/15/02: Cutuff expression levels at the low @@ -274,18 +244,18 @@ public double getFValue(int factor, double[][] history) { // We return 1.0 and -1.0 because we use a basalExpression of // 0.0. (If the basalExpression were 1/2, we would use 1 and 0.) - /** - * The real number that is returned if the value from the Boolean lookup - * table is "true". Must be > basalExpression. - * - * @serial + /* + The real number that is returned if the value from the Boolean lookup + table is "true". Must be > basalExpression. + + @serial */ double trueValue = 1.0; - /** - * The real number that is returned if the value from the Boolean lookup - * table is "false". Must be < basalExpression. - * - * @serial + /* + The real number that is returned if the value from the Boolean lookup + table is "false". Must be < basalExpression. + + @serial */ double falseValue = -1.0; return functionValue ? trueValue : falseValue; @@ -293,14 +263,15 @@ public double getFValue(int factor, double[][] history) { } /** - * Returns the boolean function for the given factor. + * @param factor the index of the factor to calculate a new value for. + * @return the boolean function for the given factor. */ public BooleanFunction getSubFunction(int factor) { return this.booleanFunctions[factor]; } /** - * Returns the rate at which expression levels tend to return to equilibrium. + * @return the rate at which expression levels tend to return to equilibrium. */ public double getDecayRate() { return this.decayRate; @@ -308,6 +279,8 @@ public double getDecayRate() { /** * Sets the rate at which expression levels tend to return to equilibrium. Must be > 0.0 and <= 1.0. + * + * @param decayRate the new decay rate. */ public void setDecayRate(double decayRate) { @@ -321,7 +294,7 @@ public void setDecayRate(double decayRate) { } /** - * Returns the rate at which Boolean Glass subfunctions tend to affect the update. + * @return the rate at which Boolean Glass subfunctions tend to affect the update. */ public double getBooleanInfluenceRate() { return this.booleanInfluenceRate; @@ -330,6 +303,8 @@ public double getBooleanInfluenceRate() { /** * Sets the rate at which the output of the Glass function influences the change in expression level of a gene. Must * be > 0.0. + * + * @param booleanInfluenceRate the new boolean influence rate. */ public void setBooleanInfluenceRate(double booleanInfluenceRate) { @@ -350,10 +325,10 @@ public void setLowerBound(double lowerBound) { } /** - * Method setIntenalNoiseModel + * Sets the error distribution for the factor'th factor. * - * @param factor - * @param distribution + * @param factor the factor in question. + * @param distribution the error distribution for factor. */ public void setErrorDistribution(int factor, Distribution distribution) { @@ -375,14 +350,14 @@ public Distribution getErrorDistribution(int factor) { } /** - * Returns the number of factors in the history. This is used to set up the initial history array. + * @return the number of factors in the history. This is used to set up the initial history array. */ public int getNumFactors() { return this.connectivity.getNumFactors(); } /** - * Returns the max lag of the history. This is used to set up the initial history array. + * @return the max lag of the history. This is used to set up the initial history array. */ public int getMaxLag() { int maxLag = 0; @@ -405,6 +380,7 @@ public int getMaxLag() { * class that didn't include it. (That's what the "s.defaultReadObject();" is for. See J. Bloch, Effective Java, for * help. */ + @Serial private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/study/gene/tetrad/gene/history/UpdateFunction.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/study/gene/tetrad/gene/history/UpdateFunction.java index de9a3a077b..1d9a79a3ac 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/study/gene/tetrad/gene/history/UpdateFunction.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/study/gene/tetrad/gene/history/UpdateFunction.java @@ -24,15 +24,15 @@ import edu.cmu.tetrad.util.TetradSerializable; /** - *

Implements a function from the previous time steps of a history array to - * the getModel time step. The function is implemented factor by factor; for each factor, the indexed connectivity - * specifies a specific set of parents (IndexedParents) that the function is permitted to depend on for that factor; the - * getLabel method returns the value for that set of parents in the history. The update function may optionally be - * associated with an IndexedLagGraph to provide information about the intended graphical structure of the - * function (say, from a causal point of view). This IndexedLagGraph gives information about the string names and order - * of the factors and the number and order of the parents (IndexedParent's) for each factor. This information should be - * encoded in the function itself, but there is no requirement that the function be checked against the graph explicitly - * to make sure the graph is actually implemented. + * Implements a function from the previous time steps of a history array to the getModel time step. The function is + * implemented factor by factor; for each factor, the indexed connectivity specifies a specific set of parents + * (IndexedParents) that the function is permitted to depend on for that factor; the getLabel method returns the value + * for that set of parents in the history. The update function may optionally be associated with an IndexedLagGraph to + * provide information about the intended graphical structure of the function (say, from a causal point of view). + * This IndexedLagGraph gives information about the string names and order of the factors and the number and order of + * the parents (IndexedParent's) for each factor. This information should be encoded in the function itself, but there + * is no requirement that the function be checked against the graph explicitly to make sure the graph is actually + * implemented. * * @author josephramsey */ @@ -40,7 +40,7 @@ public interface UpdateFunction extends TetradSerializable { long serialVersionUID = 23L; /** - * Returns the indexed lag graph, if one is available. + * @return the indexed lag graph, if one is available. */ IndexedLagGraph getIndexedLagGraph(); @@ -54,12 +54,12 @@ public interface UpdateFunction extends TetradSerializable { double getValue(int factorIndex, double[][] history); /** - * Returns the number of factors in the history. This is used to set up the initial history array. + * @return the number of factors in the history. This is used to set up the initial history array. */ int getNumFactors(); /** - * Returns the max lag of the gene history. This is used to set up the initial history array. + * @return the max lag of the gene history. This is used to set up the initial history array. */ int getMaxLag(); } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/util/AlgorithmDescriptions.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/util/AlgorithmDescriptions.java index 46fde7a468..001ba37022 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/util/AlgorithmDescriptions.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/util/AlgorithmDescriptions.java @@ -88,7 +88,7 @@ public String get(String shortName) { private List getShortNames() { // get algorithm from annotations List shortNames = AlgorithmAnnotations.getInstance().getAnnotatedClasses().stream() - .map(e -> e.getAnnotation().command()) + .map(e -> e.annotation().command()) .collect(Collectors.toList()); // add additional shortNames not annotated diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/util/IndependenceTestDescriptions.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/util/IndependenceTestDescriptions.java index dfe11a1694..0dff8a3136 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/util/IndependenceTestDescriptions.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/util/IndependenceTestDescriptions.java @@ -78,7 +78,7 @@ public String get(String shortName) { private List getShortNames() { return TestOfIndependenceAnnotations.getInstance().getAnnotatedClasses().stream() - .map(e -> e.getAnnotation().command()) + .map(e -> e.annotation().command()) .collect(Collectors.toList()); } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/util/MatrixUtils.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/util/MatrixUtils.java index f68868fc9d..ece7bc01ff 100755 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/util/MatrixUtils.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/util/MatrixUtils.java @@ -243,8 +243,11 @@ public static double[][] inverse(double[][] m) { } public static double[][] pseudoInverse(double[][] x) { - SingularValueDecomposition svd - = new SingularValueDecomposition(new BlockRealMatrix(x)); + if (x.length == 0) { + return new Matrix(x).toArray(); + } + + SingularValueDecomposition svd = new SingularValueDecomposition(new BlockRealMatrix(x)); RealMatrix U = svd.getU(); RealMatrix V = svd.getV(); diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/util/ParamDescriptions.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/util/ParamDescriptions.java index 923b68262d..a0b89568f8 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/util/ParamDescriptions.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/util/ParamDescriptions.java @@ -47,7 +47,7 @@ private ParamDescriptions() { )); // Read the copied maunal/index.html from within the jar - try (InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("manual/index.html")) { + try (InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("docs/manual/index.html")) { if (inputStream != null) { doc = Jsoup.parse(inputStream, "UTF-8", ""); } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/util/Params.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/util/Params.java index 6668fbdb10..7b490dce63 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/util/Params.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/util/Params.java @@ -74,13 +74,10 @@ public final class Params { public static final String FASK_ADJACENCY_METHOD = "faskAdjacencyMethod"; public static final String FASK_NONEMPIRICAL = "faskNonempirical"; public static final String FAITHFULNESS_ASSUMED = "faithfulnessAssumed"; - // public static final String PC_HEURISTIC = "pcHeuristic"; public static final String FAS_RULE = "fasRule"; public static final String FAST_ICA_A = "fastIcaA"; public static final String FAST_ICA_MAX_ITER = "fastIcaMaxIter"; public static final String FAST_ICA_TOLERANCE = "fastIcaTolerance"; - public static final String ICA_ALGORITHM = "icaAlgorithm"; - public static final String ICA_FUNCTION = "icaFunction"; public static final String THRESHOLD_B = "thresholdBHat"; public static final String GUARANTEE_ACYCLIC = "guaranteeAcyclic"; public static final String THRESHOLD_SPINE = "thresholdSpine"; @@ -106,7 +103,7 @@ public final class Params { public static final String KCI_CUTOFF = "kciCutoff"; public static final String KCI_EPSILON = "kciEpsilon"; public static final String KCI_NUM_BOOTSTRAPS = "kciNumBootstraps"; - public static final String KCI_USE_APPROMATION = "kciUseAppromation"; + public static final String KCI_USE_APPROXIMATION = "kciUseApproximation"; public static final String KERNEL_MULTIPLIER = "kernelMultiplier"; public static final String KERNEL_REGRESSION_SAMPLE_SIZE = "kernelRegressionSampleSize"; public static final String KERNEL_TYPE = "kernelType"; @@ -204,9 +201,7 @@ public final class Params { public static final String USE_BES = "useBes"; public static final String NUM_STARTS = "numStarts"; public static final String CACHE_SCORES = "cacheScores"; - public static final String OTHER_PERM_METHOD = "otherPermMethod"; public static final String BOSS_ALG = "bossAlg"; - public static final String BREAK_TIES = "breakTies"; public static final String OUTPUT_CPDAG = "outputCpdag"; public static final String ZS_RISK_BOUND = "zSRiskBound"; public static final String NUM_ROUNDS = "numRounds"; @@ -250,10 +245,13 @@ public final class Params { public static final String NUMBER_OF_EXPANSIONS = "numberOfExpansions"; public static final String CSTAR_CPDAG_ALGORITHM = "cstarCpdagAlgorithm"; public static final String FILE_OUT_PATH = "fileOutPath"; - public static final String PI_THR = "piThr"; public static final String REMOVE_EFFECT_NODES = "removeEffectNodes"; public static final String SAMPLE_STYLE = "sampleStyle"; public static final String NUM_THREADS = "numThreads"; + public static final String USE_PSEUDOINVERSE = "usePseudoinverse"; + public static String MIN_COUNT_PER_CELL = "minCountPerCell"; + public static String PC_HEURISTIC = "pcHeuristic"; + // All parameters that are found in HTML manual documentation private static final Set ALL_PARAMS_IN_HTML_MANUAL = new HashSet<>(Arrays.asList( @@ -270,7 +268,7 @@ public final class Params { Params.INCLUDE_NEGATIVE_SKEWS_FOR_BETA, Params.INCLUDE_POSITIVE_COEFS, Params.INCLUDE_POSITIVE_SKEWS_FOR_BETA, Params.INCLUDE_STRUCTURE_MODEL, Params.INTERVAL_BETWEEN_RECORDINGS, Params.INTERVAL_BETWEEN_SHOCKS, Params.IPEN, Params.IS, Params.ITR, - Params.KCI_ALPHA, Params.KCI_CUTOFF, Params.KCI_EPSILON, Params.KCI_NUM_BOOTSTRAPS, Params.KCI_USE_APPROMATION, + Params.KCI_ALPHA, Params.KCI_CUTOFF, Params.KCI_EPSILON, Params.KCI_NUM_BOOTSTRAPS, Params.KCI_USE_APPROXIMATION, Params.KERNEL_MULTIPLIER, Params.KERNEL_REGRESSION_SAMPLE_SIZE, Params.KERNEL_TYPE, Params.KERNEL_WIDTH, Params.LATENT_MEASURED_IMPURE_PARENTS, Params.LOWER_BOUND, Params.MAX_CATEGORIES, Params.MAX_DEGREE, Params.MAX_DISTINCT_VALUES_DISCRETE, Params.MAX_INDEGREE, Params.MAX_ITERATIONS, Params.MAX_OUTDEGREE, diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/util/ScoreDescriptions.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/util/ScoreDescriptions.java index a158035947..80a06841bc 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/util/ScoreDescriptions.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/util/ScoreDescriptions.java @@ -78,7 +78,7 @@ public String get(String shortName) { private List getShortNames() { return ScoreAnnotations.getInstance().getAnnotatedClasses().stream() - .map(e -> e.getAnnotation().command()) + .map(e -> e.annotation().command()) .collect(Collectors.toList()); } diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/util/UniformityTest.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/util/UniformityTest.java index b3d9b402c6..b41854f290 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/util/UniformityTest.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/util/UniformityTest.java @@ -10,23 +10,30 @@ public class UniformityTest { public static double getPValue(List points) { - // Convert the list to a primitive double array - double[] data = points.stream().mapToDouble(Double::doubleValue).toArray(); // Create a uniform distribution with the same range as the data double min = points.stream().min(Double::compareTo).orElse(0.0); double max = points.stream().max(Double::compareTo).orElse(1.0); - UniformRealDistribution distribution; + + return getPValue(points, min, max); + } + + public static double getPValue(List points, double min, double max) { + + // Create a uniform distribution with the same range as the data try { - distribution = new UniformRealDistribution(min, max); + double[] data = points.stream().mapToDouble(Double::doubleValue).toArray(); + + UniformRealDistribution distribution = new UniformRealDistribution(min, max); + + // Perform the Kolmogorov-Smirnov test + KolmogorovSmirnovTest test = new KolmogorovSmirnovTest(); + return test.kolmogorovSmirnovTest(distribution, data); } catch (NumberIsTooLargeException e) { e.printStackTrace(); return Double.NaN; } - // Perform the Kolmogorov-Smirnov test - KolmogorovSmirnovTest test = new KolmogorovSmirnovTest(); - return test.kolmogorovSmirnovTest(distribution, data); } public static void main(String[] args) { diff --git a/tetrad-lib/src/main/java/edu/cmu/tetrad/util/dist/ChiSquare.java b/tetrad-lib/src/main/java/edu/cmu/tetrad/util/dist/ChiSquare.java index 2654893d12..095ec817fe 100644 --- a/tetrad-lib/src/main/java/edu/cmu/tetrad/util/dist/ChiSquare.java +++ b/tetrad-lib/src/main/java/edu/cmu/tetrad/util/dist/ChiSquare.java @@ -36,10 +36,10 @@ public class ChiSquare implements Distribution { private static final long serialVersionUID = 23L; /** - * The stored degees of freedom. Needed because the wrapped distribution does not provide getters for its + * The stored degrees of freedom. Needed because the wrapped distribution does not provide getters for its * parameters. */ - private double df = 5.0; + private double df; /** * Constructs a new Chi Square distribution. @@ -104,7 +104,7 @@ public String toString() { * semantic checks can be specified and do not need to stay the same from version to version. A readObject method of * this form may be added to any class, even if Tetrad sessions were previously saved out using a version of the * class that didn't include it. (That's what the "s.defaultReadObject();" is for. See J. Bloch, Effective Java, for - * help. + * help.) * * @param s Ibid. * @throws java.io.IOException If the stream cannot be read. diff --git a/tetrad-lib/src/main/java/edu/pitt/dbmi/algo/bayesian/constraint/inference/BCCausalInference.java b/tetrad-lib/src/main/java/edu/pitt/dbmi/algo/bayesian/constraint/inference/BCCausalInference.java index c713d17e40..0c1991d221 100644 --- a/tetrad-lib/src/main/java/edu/pitt/dbmi/algo/bayesian/constraint/inference/BCCausalInference.java +++ b/tetrad-lib/src/main/java/edu/pitt/dbmi/algo/bayesian/constraint/inference/BCCausalInference.java @@ -31,6 +31,9 @@ */ public class BCCausalInference { + /** + * The value of the PESS constant. + */ private static final double PESS_VALUE = 1.0; private final int numberOfNodes; private final int numberOfCases; @@ -44,6 +47,13 @@ public class BCCausalInference { private final int[] nodeDimension; private final int[][] cases; + /** + * Constructor + * + * @param nodeDimension nodeDimension[0] is the number of nodes, nodeDimension[1] is the number of cases, and the + * rest are the dimensions of the nodes. + * @param cases cases[0] is the number of cases, and the rest are the cases. + */ public BCCausalInference(int[] nodeDimension, int[][] cases) { this.nodeDimension = nodeDimension; this.cases = cases; @@ -74,9 +84,7 @@ private static double lnXpluslnY(double lnX, double lnY) { double lnYminusLnX = lnY - lnX; - return (lnYminusLnX < Double.MIN_EXPONENT) - ? lnX - : FastMath.log1p(FastMath.exp(lnYminusLnX)) + lnX; + return (lnYminusLnX < Double.MIN_EXPONENT) ? lnX : FastMath.log1p(FastMath.exp(lnYminusLnX)) + lnX; } /** @@ -206,10 +214,12 @@ private double scoreNode(int node, int whichList, CountsTracker countsTracker) { } /** - * @param node - * @param instancePtr + * This function scores a node using the first scoring function. + * + * @param node is the node being scored. + * @param instancePtr is the pointer to the first instance of the node. * @param q is the number of possible joint instantiation of the parents of the parents of the node. - * @return + * @return the score of the node. */ private double scoringFn1(int node, int instancePtr, double q, CountsTracker countsTracker) { int[] counts = countsTracker.counts; @@ -232,9 +242,9 @@ private double scoringFn1(int node, int instancePtr, double q, CountsTracker cou /** * Computes the K2 score. * - * @param node - * @param instancePtr - * @return + * @param node is the node being scored. + * @param instancePtr is the pointer to the first instance of the node. + * @return the score of the node. */ private double scoringFn2(int node, int instancePtr, CountsTracker countsTracker) { int[] counts = countsTracker.counts; @@ -252,6 +262,13 @@ private double scoringFn2(int node, int instancePtr, CountsTracker countsTracker return scoreNI; } + /** + * This function files a case for a node. + * + * @param node is the node being filed. + * @param casei is the case being filed. + * @param countsTracker is the tracker for the counts. + */ private void fileCase(int node, int casei, CountsTracker countsTracker) { int nodeDim = (node > this.numberOfNodes) ? countsTracker.xyDim : this.nodeDimension[node]; @@ -338,6 +355,12 @@ private void fileCase(int node, int casei, CountsTracker countsTracker) { counts[cPtr + nodeValue - 1]++; } + /** + * This function creates a tracker for the counts. + * + * @param z is the set of nodes. + * @return the tracker for the counts. + */ private CountsTracker createCountsTracker(int[] z) { CountsTracker tracker = new CountsTracker(); tracker.numOfNodes = this.numberOfNodes; @@ -367,15 +390,22 @@ private CountsTracker createCountsTracker(int[] z) { * prior of 0.5. It can be revised to return an informative prior. The code that calls priorIndependent() currently * assumes that it returns a value in (0, 1), and thus, does not return 0 or 1. * - * @param x - * @param y - * @param z - * @return + * @param x is the node x + * @param y is the node y + * @param z is the set of nodes + * @return the prior probability that X independent Y given Z */ private double priorIndependent(int x, int y, int[] z) { return 0.5; // currently assumes uniform priors } + /** + * This function computes the log of the factorial of the numbers from 1 to maxCases + maxValues. + * + * @param maxCases is the maximum number of cases + * @param maxValues is the maximum number of values + * @return the log of the factorial of the numbers from 1 to maxCases + maxValues + */ private double[] computeLogFactorial(int maxCases, int maxValues) { int size = (2 * maxCases) + maxValues; double[] logFact = new double[size + 1]; @@ -386,6 +416,12 @@ private double[] computeLogFactorial(int maxCases, int maxValues) { return logFact; } + /** + * This function computes the log of the gamma function. + * + * @param xx is the value for which the log of the gamma function is computed. + * @return the log of the gamma function. + */ private double gammln(double xx) { if (xx == 1) { return 0; // this is a correction to a bug that used to be here @@ -399,20 +435,18 @@ private double gammln(double xx) { } } + /** + * This function computes the log of the gamma function for values greater than 1. + * + * @param xx is the value for which the log of the gamma function is computed. + * @return the log of the gamma function. + */ private double gammlnCore(double xx) { final double stp = 2.50662827465; final double half = 0.5; final double one = 1.0; final double fpf = 5.5; - double[] cof = { - 0, - 76.18009173, - -86.50532033, - 24.01409822, - -1.231739516, - 0.120858003E-2, - -0.536382E-5 - }; + double[] cof = {0, 76.18009173, -86.50532033, 24.01409822, -1.231739516, 0.120858003E-2, -0.536382E-5}; double x = xx - one; double tmp = x + fpf; @@ -426,11 +460,25 @@ private double gammlnCore(double xx) { return tmp + FastMath.log(stp * ser); } + /** + * An enum for the type of operation. + */ public enum OP { + + /** + * The operation is dependent. + */ DEPENDENT, + + /** + * The operation is independent. + */ INDEPENDENT } + /** + * This class is a tracker for the counts. + */ private static class CountsTracker { int numOfNodes; diff --git a/tetrad-lib/src/main/java/edu/pitt/dbmi/algo/bayesian/constraint/inference/BCInference.java b/tetrad-lib/src/main/java/edu/pitt/dbmi/algo/bayesian/constraint/inference/BCInference.java index 5adf9035ce..8b4a596dd3 100644 --- a/tetrad-lib/src/main/java/edu/pitt/dbmi/algo/bayesian/constraint/inference/BCInference.java +++ b/tetrad-lib/src/main/java/edu/pitt/dbmi/algo/bayesian/constraint/inference/BCInference.java @@ -324,6 +324,7 @@ private double scoreNode(int node) { /** * @param q is the number of possible joint instantiation of the parents of the parents of the node. * @param pess is the prior equivalent sample size + * @return the score of the node */ private double scoringFn1(int node, int instancePtr, double q, double pess) { int Nij = 0; @@ -509,14 +510,28 @@ private int findMaxValue(int[] nodeDimension) { return maxValue; } + /** + * Sets the prior equivalent sample size. + * + * @param priorEquivalentSampleSize the prior equivalent sample size + */ public void setPriorEqivalentSampleSize(double priorEquivalentSampleSize) { this.priorEquivalentSampleSize = priorEquivalentSampleSize; } + /** + * Enum for the type of constraint. + */ public enum OP { + /** + * The operation is independent. + */ + independent, - independent, dependent - + /** + * The operation is dependent. + */ + dependent } } diff --git a/tetrad-lib/src/main/java/edu/pitt/dbmi/algo/bayesian/constraint/inference/BayesianConstraintInference.java b/tetrad-lib/src/main/java/edu/pitt/dbmi/algo/bayesian/constraint/inference/BayesianConstraintInference.java index 937009d1b6..834e37763f 100644 --- a/tetrad-lib/src/main/java/edu/pitt/dbmi/algo/bayesian/constraint/inference/BayesianConstraintInference.java +++ b/tetrad-lib/src/main/java/edu/pitt/dbmi/algo/bayesian/constraint/inference/BayesianConstraintInference.java @@ -51,6 +51,7 @@ public BayesianConstraintInference() { /** * Main method. + * * @param args the command line arguments */ public static void main(String[] args) { diff --git a/tetrad-lib/src/main/java/edu/pitt/dbmi/algo/bayesian/constraint/inference/BayesianConstraintInferenceTest.java b/tetrad-lib/src/main/java/edu/pitt/dbmi/algo/bayesian/constraint/inference/BayesianConstraintInferenceTest.java index dbd9f81274..81b298e1b8 100644 --- a/tetrad-lib/src/main/java/edu/pitt/dbmi/algo/bayesian/constraint/inference/BayesianConstraintInferenceTest.java +++ b/tetrad-lib/src/main/java/edu/pitt/dbmi/algo/bayesian/constraint/inference/BayesianConstraintInferenceTest.java @@ -36,6 +36,7 @@ public BayesianConstraintInferenceTest() { /** * Main method. + * * @param args the command line arguments */ public static void main(String[] args) { diff --git a/tetrad-lib/src/main/java/edu/pitt/dbmi/algo/bayesian/constraint/search/PagSamplingRfci.java b/tetrad-lib/src/main/java/edu/pitt/dbmi/algo/bayesian/constraint/search/PagSamplingRfci.java index 83166d181d..2b5255f7be 100644 --- a/tetrad-lib/src/main/java/edu/pitt/dbmi/algo/bayesian/constraint/search/PagSamplingRfci.java +++ b/tetrad-lib/src/main/java/edu/pitt/dbmi/algo/bayesian/constraint/search/PagSamplingRfci.java @@ -37,10 +37,20 @@ public class PagSamplingRfci implements IGraphSearch { */ private Knowledge knowledge; + /** + * Constructor. + * + * @param dataSet the data set. + */ public PagSamplingRfci(DataSet dataSet) { this.dataSet = dataSet; } + /** + * Search for a PAG. + * + * @return a PAG. + */ @Override public Graph search() { List graphs = runSearches(); @@ -48,6 +58,12 @@ public Graph search() { return GraphSampling.createGraphWithHighProbabilityEdges(graphs); } + /** + * Create tasks for parallel execution. + * + * @param numOfTasks the number of tasks. + * @return a list of callable tasks. + */ List> createTasks(int numOfTasks) { List> callableTasks = new LinkedList<>(); @@ -105,34 +121,74 @@ private void shutdownAndAwaitTermination(ExecutorService pool) { } } + /** + * Set the number of randomized search models. + * + * @param numRandomizedSearchModels the number of randomized search models. + */ public void setNumRandomizedSearchModels(int numRandomizedSearchModels) { this.numRandomizedSearchModels = numRandomizedSearchModels; } + /** + * Set the verbose flag. + * + * @param verbose the verbose flag. + */ public void setVerbose(boolean verbose) { this.verbose = verbose; } + /** + * Set the depth. + * + * @param depth the depth. + */ public void setDepth(int depth) { this.depth = depth; } + /** + * Set the maximum path length. + * + * @param maxPathLength the maximum path length. + */ public void setMaxPathLength(int maxPathLength) { this.maxPathLength = maxPathLength; } + /** + * Set the threshold. + * + * @param threshold the threshold. + */ public void setThreshold(boolean threshold) { this.threshold = threshold; } + /** + * Set the cutoff. + * + * @param cutoff the cutoff. + */ public void setCutoff(double cutoff) { this.cutoff = cutoff; } + /** + * Set the prior equivalent sample size. + * + * @param priorEquivalentSampleSize the prior equivalent sample size. + */ public void setPriorEquivalentSampleSize(double priorEquivalentSampleSize) { this.priorEquivalentSampleSize = priorEquivalentSampleSize; } + /** + * Set the knowledge. + * + * @param knowledge the knowledge. + */ public void setKnowledge(Knowledge knowledge) { this.knowledge = knowledge; } diff --git a/tetrad-lib/src/main/java/edu/pitt/dbmi/algo/bayesian/constraint/search/RfciBsc.java b/tetrad-lib/src/main/java/edu/pitt/dbmi/algo/bayesian/constraint/search/RfciBsc.java index 534b63a0bc..669a1a1d77 100644 --- a/tetrad-lib/src/main/java/edu/pitt/dbmi/algo/bayesian/constraint/search/RfciBsc.java +++ b/tetrad-lib/src/main/java/edu/pitt/dbmi/algo/bayesian/constraint/search/RfciBsc.java @@ -220,6 +220,11 @@ private static double getLnProb(Graph pag, Map H) { return lnQ; } + /** + * Performs the search. + * + * @return the graph that was learned. + */ @Override public Graph search() { long stop = 0; @@ -246,6 +251,9 @@ class SearchPagTask implements Callable { private final IndTestProbabilistic test; private final Rfci rfci; + /** + * Constructor. + */ public SearchPagTask() { this.test = new IndTestProbabilistic(dataSet); this.test.setThreshold(RfciBsc.this.thresholdNoRandomDataSearch); @@ -256,6 +264,11 @@ public SearchPagTask() { this.rfci = new Rfci(this.test); } + /** + * Performs the search. + * @return true if the search was successful. + * @throws Exception if an error occurred. + */ @Override public Boolean call() throws Exception { @@ -338,6 +351,9 @@ class BootstrapDepDataTask implements Callable { private final IndTestProbabilistic bsTest; + /** + * Constructor. + */ public BootstrapDepDataTask(int row_index, int rows) { this.row_index = row_index; @@ -349,6 +365,12 @@ public BootstrapDepDataTask(int row_index, int rows) { } } + /** + * Performs the search. + * + * @return true if the search was successful. + * @throws Exception if an error occurred. + */ @Override public Boolean call() throws Exception { for (IndependenceFact f : hCopy.keySet()) { @@ -399,7 +421,7 @@ public Boolean call() throws Exception { Graph depPattern = fges.search(); depPattern = GraphUtils.replaceNodes(depPattern, depData.getVariables()); - Graph estDepBN = GraphTransforms.dagFromCPDAG(depPattern, null); + Graph estDepBN = GraphTransforms.dagFromCpdag(depPattern, null); if (this.verbose) { this.out.println("estDepBN:"); @@ -651,38 +673,74 @@ private List getProbability(Node node1, Node node2) { return edgeTypeProbabilities; } + /** + * Sets the number of randomized search models. + * @param numRandomizedSearchModels the number of randomized search models. + */ public void setNumRandomizedSearchModels(int numRandomizedSearchModels) { this.numRandomizedSearchModels = numRandomizedSearchModels; } + /** + * Sets the number of bootstrap samples. + * @param numBscBootstrapSamples the number of bootstrap samples. + */ public void setNumBscBootstrapSamples(int numBscBootstrapSamples) { this.numBscBootstrapSamples = numBscBootstrapSamples; } + /** + * Sets the lower bound. + * @param lowerBound the lower bound. + */ public void setLowerBound(double lowerBound) { this.lowerBound = lowerBound; } + /** + * Sets the upper bound. + * @param upperBound the upper bound. + */ public void setUpperBound(double upperBound) { this.upperBound = upperBound; } + /** + * Sets whether the output should be RBD. + * @param outputRBD true if the output should be RBD. + */ public void setOutputRBD(boolean outputRBD) { this.outputRBD = outputRBD; } + /** + * Returns the graph that was learned using the BSC-D method. + * @return + */ public Graph getGraphRBD() { return this.graphRBD; } + /** + * Returns the graph that was learned using the BSC-I method. + * @return the graph that was learned using the BSC-I method. + */ public Graph getGraphRBI() { return this.graphRBI; } + /** + * Returns the BSC-D score. + * @return the BSC-D score. + */ public double getBscD() { return this.bscD; } + /** + * Returns the BSC-I score. + * @return the BSC-I score. + */ public double getBscI() { return this.bscI; } @@ -708,6 +766,7 @@ private void shutdownAndAwaitTermination(ExecutorService pool) { /** * Sets whether verbose output should be produced. + * @param verbose true if verbose output should be produced. */ public void setVerbose(boolean verbose) { this.verbose = verbose; @@ -722,23 +781,36 @@ public PrintStream getOut() { /** * Sets the output stream that output (except for log output) should be sent to. By detault System.out. + * @param out the output stream that output (except for log output) should be sent to. */ public void setOut(PrintStream out) { this.out = out; } + /** + * @param thresholdNoRandomDataSearch the thresholdNoRandomDataSearch to set + */ public void setThresholdNoRandomDataSearch(boolean thresholdNoRandomDataSearch) { this.thresholdNoRandomDataSearch = thresholdNoRandomDataSearch; } + /** + * @param cutoffDataSearch the cutoffDataSearch to set + */ public void setCutoffDataSearch(double cutoffDataSearch) { this.cutoffDataSearch = cutoffDataSearch; } + /** + * @param thresholdNoRandomConstrainSearch the thresholdNoRandomConstrainSearch to set + */ public void setThresholdNoRandomConstrainSearch(boolean thresholdNoRandomConstrainSearch) { this.thresholdNoRandomConstrainSearch = thresholdNoRandomConstrainSearch; } + /** + * @param cutoffConstrainSearch the cutoffConstrainSearch to set + */ public void setCutoffConstrainSearch(double cutoffConstrainSearch) { this.cutoffConstrainSearch = cutoffConstrainSearch; } diff --git a/tetrad-lib/src/main/java/edu/pitt/dbmi/algo/resampling/GeneralResamplingSearch.java b/tetrad-lib/src/main/java/edu/pitt/dbmi/algo/resampling/GeneralResamplingSearch.java index ec22cd56a9..ea803a9981 100644 --- a/tetrad-lib/src/main/java/edu/pitt/dbmi/algo/resampling/GeneralResamplingSearch.java +++ b/tetrad-lib/src/main/java/edu/pitt/dbmi/algo/resampling/GeneralResamplingSearch.java @@ -3,7 +3,10 @@ import edu.cmu.tetrad.algcomparison.algorithm.Algorithm; import edu.cmu.tetrad.algcomparison.algorithm.MultiDataSetAlgorithm; import edu.cmu.tetrad.algcomparison.score.ScoreWrapper; -import edu.cmu.tetrad.data.*; +import edu.cmu.tetrad.data.DataModel; +import edu.cmu.tetrad.data.DataSet; +import edu.cmu.tetrad.data.DataTransforms; +import edu.cmu.tetrad.data.Knowledge; import edu.cmu.tetrad.graph.Graph; import edu.cmu.tetrad.util.Parameters; import edu.cmu.tetrad.util.Params; @@ -58,48 +61,100 @@ public class GeneralResamplingSearch { private int numNograph = 0; private ScoreWrapper scoreWrapper; + /** + * Constructor. + * + * @param data the data set. + * @param numberResampling the number of resampling. + */ public GeneralResamplingSearch(DataSet data, int numberResampling) { this.data = data; this.pool = ForkJoinPool.commonPool(); this.numberResampling = numberResampling; } + /** + * Constructor. + * + * @param dataSets the data sets. + * @param numberResampling the number of resampling. + */ public GeneralResamplingSearch(List dataSets, int numberResampling) { this.dataSets = dataSets; this.pool = ForkJoinPool.commonPool(); this.numberResampling = numberResampling; } + /** + * Constructor. + * + * @param algorithm the algorithm. + */ public void setAlgorithm(Algorithm algorithm) { this.algorithm = algorithm; this.multiDataSetAlgorithm = null; } + /** + * Constructor. + * + * @param multiDataSetAlgorithm the multi data set algorithm. + */ public void setMultiDataSetAlgorithm(MultiDataSetAlgorithm multiDataSetAlgorithm) { this.multiDataSetAlgorithm = multiDataSetAlgorithm; this.algorithm = null; } + /** + * Sets the number of resampling. + * + * @param percentResampleSize the resampling size. + */ public void setPercentResampleSize(double percentResampleSize) { this.percentResampleSize = percentResampleSize; } + /** + * Sets the resampling with replacement. + * + * @param resamplingWithReplacement the resampling with replacement. + */ public void setResamplingWithReplacement(boolean resamplingWithReplacement) { this.resamplingWithReplacement = resamplingWithReplacement; } + /** + * Sets whether to run in parallel. + * + * @param runParallel whether to run in parallel. + */ public void setRunParallel(boolean runParallel) { this.runParallel = runParallel; } + /** + * Sets whether to add the original dataset. + * + * @param addOriginalDataset whether to add the original dataset. + */ public void setAddOriginalDataset(boolean addOriginalDataset) { this.addOriginalDataset = addOriginalDataset; } + /** + * Sets whether to be verbose. + * + * @param verbose whether to be verbose. + */ public void setVerbose(boolean verbose) { this.verbose = verbose; } + /** + * Sets the data set. + * + * @param data the data set. + */ public void setData(DataSet data) { this.data = data; } @@ -113,6 +168,11 @@ public void setKnowledge(Knowledge knowledge) { this.knowledge = new Knowledge((Knowledge) knowledge); } + /** + * Sets the external graph. + * + * @param externalGraph the external graph. + */ public void setExternalGraph(Graph externalGraph) { this.externalGraph = externalGraph; } @@ -126,15 +186,26 @@ public PrintStream getOut() { /** * Sets the output stream that output (except for log output) should be sent to. By default System.out. + * @param out the output stream. */ public void setOut(PrintStream out) { this.out = out; } + /** + * Sets the parameters. + * + * @param parameters the parameters. + */ public void setParameters(Parameters parameters) { this.parameters = parameters; } + /** + * Performs the search. + * + * @return the list of graphs. + */ public List search() { this.graphs.clear(); @@ -259,10 +330,18 @@ public List search() { return this.graphs; } + /** + * Returns the number of no graph. + * + * @return the number of no graph. + */ public int getNumNograph() { return numNograph; } + /** + * Returns the score wrapper. + */ public void setScoreWrapper(ScoreWrapper scoreWrapper) { this.scoreWrapper = scoreWrapper; } diff --git a/tetrad-lib/src/main/java/edu/pitt/dbmi/algo/resampling/GeneralResamplingTest.java b/tetrad-lib/src/main/java/edu/pitt/dbmi/algo/resampling/GeneralResamplingTest.java index 634af00838..aa9806243a 100644 --- a/tetrad-lib/src/main/java/edu/pitt/dbmi/algo/resampling/GeneralResamplingTest.java +++ b/tetrad-lib/src/main/java/edu/pitt/dbmi/algo/resampling/GeneralResamplingTest.java @@ -39,6 +39,17 @@ public class GeneralResamplingTest { */ private Graph externalGraph; + /** + * Constructor. + * + * @param data the data set. + * @param algorithm the algorithm. + * @param numberResampling the number of resampling. + * @param percentResamplingSize the percent resampling size. + * @param resamplingWithReplacement whether resampling with replacement. + * @param edgeEnsemble the edge ensemble. + * @param addOriginalDataset whether to add the original dataset. + */ public GeneralResamplingTest( DataSet data, Algorithm algorithm, @@ -69,6 +80,17 @@ public GeneralResamplingTest( } } + /** + * Constructor. + * + * @param dataSets the data sets. + * @param multiDataSetAlgorithm the multi data set algorithm. + * @param numberResampling the number of resampling. + * @param percentResamplingSize the percent resampling size. + * @param resamplingWithReplacement whether resampling with replacement. + * @param edgeEnsemble the edge ensemble. + * @param addOriginalDataset whether to add the original dataset. + */ public GeneralResamplingTest( List dataSets, MultiDataSetAlgorithm multiDataSetAlgorithm, int numberResampling, @@ -99,6 +121,12 @@ public GeneralResamplingTest( } } + /** + * Constructor. + * + * @param truth the true graph. + * @param estimate the estimated graph. + */ public static int[][] getAdjConfusionMatrix(Graph truth, Graph estimate) { Graph complete = new EdgeListGraph(estimate.getNodes()); complete.fullyConnect(Endpoint.TAIL); @@ -134,6 +162,12 @@ private static void countAdjConfMatrix(int[][] adjAr, List edges, Graph tr } } + /** + * Constructor. + * + * @param truth the true graph. + * @param estimate the estimated graph. + */ public static int[][] getEdgeTypeConfusionMatrix(Graph truth, Graph estimate) { Graph complete = new EdgeListGraph(estimate.getNodes()); complete.fullyConnect(Endpoint.TAIL); @@ -227,6 +261,8 @@ private static void countEdgeTypeConfMatrix(int[][] edgeAr, List edges, Gr /** * Sets whether verbose output should be produced. + * + * @param verbose whether verbose output should be produced. */ public void setVerbose(boolean verbose) { this.verbose = verbose; @@ -241,11 +277,18 @@ public PrintStream getOut() { /** * Sets the output stream that output (except for log output) should be sent to. By default System.out. + * + * @param out the output stream that output (except for log output) should be sent to. */ public void setOut(PrintStream out) { this.out = out; } + /** + * Sets the parameters. + * + * @param parameters the parameters. + */ public void setParameters(Parameters parameters) { this.parameters = parameters; Object obj = parameters.get(Params.PRINT_STREAM); @@ -270,6 +313,11 @@ public void setExternalGraph(Graph externalGraph) { this.externalGraph = externalGraph; } + /** + * Runs the resampling test. + * + * @return the graph. + */ public Graph search() { long start, stop; @@ -329,10 +377,19 @@ public Graph search() { return graph; } + /** + * Sets the score wrapper. + * + * @param scoreWrapper the score wrapper. + */ public void setScoreWrapper(ScoreWrapper scoreWrapper) { this.scoreWrapper = scoreWrapper; } + /** + * Sets the independence wrapper. + * @param independenceWrapper the independence wrapper. + */ public void setIndTestWrapper(IndependenceWrapper independenceWrapper) { this.independenceWrapper = independenceWrapper; } diff --git a/tetrad-lib/src/main/java/edu/pitt/isp/sverchkov/data/AdTree.java b/tetrad-lib/src/main/java/edu/pitt/isp/sverchkov/data/AdTree.java index 96e4bb5557..c019ab2e55 100644 --- a/tetrad-lib/src/main/java/edu/pitt/isp/sverchkov/data/AdTree.java +++ b/tetrad-lib/src/main/java/edu/pitt/isp/sverchkov/data/AdTree.java @@ -49,6 +49,7 @@ public class AdTree extends AdTreeHelper { /** * Constructs an AD tree for the given data set. + * * @param data The data set. */ public AdTree(DataTable data) { @@ -108,6 +109,7 @@ public AdTree(DataTable data) { /** * Returns the number of rows in the data set. + * * @param attribute The attribute to count. * @return The number of rows in the data set. */ @@ -119,6 +121,7 @@ public List values(A attribute) { /** * Returns the number of rows in the data set. + * * @param assignment The assignment to count. * @return The number of rows in the data set. */ @@ -135,7 +138,8 @@ public int count(Map assignment) { /** * Returns the number of rows in the data set. - * @param attribute The attribute to count. + * + * @param attribute The attribute to count. * @param assignment The assignment to count. * @return The number of rows in the data set. */ @@ -154,6 +158,7 @@ public Map counts(A attribute, Map assignment) { /** * Converts to XML. + * * @return The XML document. * @throws ParserConfigurationException if something goes wrong */ @@ -163,6 +168,7 @@ public Document toXML() throws ParserConfigurationException { /** * Converts to XML. + * * @param builder The builder. * @return The XML document. */ diff --git a/tetrad-lib/src/main/java/edu/pitt/isp/sverchkov/data/AdTreeHelper.java b/tetrad-lib/src/main/java/edu/pitt/isp/sverchkov/data/AdTreeHelper.java index 7ccf40b8aa..2605c77445 100644 --- a/tetrad-lib/src/main/java/edu/pitt/isp/sverchkov/data/AdTreeHelper.java +++ b/tetrad-lib/src/main/java/edu/pitt/isp/sverchkov/data/AdTreeHelper.java @@ -26,7 +26,7 @@ import java.util.List; /** - * @author user + * @author jdramsey */ class AdTreeHelper implements Serializable { @@ -132,7 +132,7 @@ private VaryNode(int attr, int[][] array) { for (int i = 0; i < airity; i++) if (i != this.mcv) { List indexes = childArrayIndexes.get(i); - if (indexes.size() > 0) { + if (!indexes.isEmpty()) { int[][] childArray = new int[indexes.size()][]; int j = 0; for (int index : indexes) diff --git a/tetrad-lib/src/main/java/edu/pitt/isp/sverchkov/data/AdTreeTest.java b/tetrad-lib/src/main/java/edu/pitt/isp/sverchkov/data/AdTreeTest.java index 66208cdc4f..8a2c35ad6b 100644 --- a/tetrad-lib/src/main/java/edu/pitt/isp/sverchkov/data/AdTreeTest.java +++ b/tetrad-lib/src/main/java/edu/pitt/isp/sverchkov/data/AdTreeTest.java @@ -36,8 +36,9 @@ import java.util.TreeMap; /** - *

A test of the AD tree implementation.

- * Author : Jeremy Espino MD Created 6/24/15 3:32 PM + * A test of the AD tree implementation. + * + * @author Jeremy Espino MD Created 6/24/15 3:32 PM */ public class AdTreeTest { diff --git a/tetrad-lib/src/main/java/edu/pitt/isp/sverchkov/data/DataTable.java b/tetrad-lib/src/main/java/edu/pitt/isp/sverchkov/data/DataTable.java index dc30dac4f8..de92acb6c6 100644 --- a/tetrad-lib/src/main/java/edu/pitt/isp/sverchkov/data/DataTable.java +++ b/tetrad-lib/src/main/java/edu/pitt/isp/sverchkov/data/DataTable.java @@ -31,12 +31,25 @@ * @author YUS24 */ public interface DataTable extends Iterable> { + + /** + * @return The names of the variables in the table + */ List variables(); + /** + * @return The number of columns in the table + */ int columnCount(); + /** + * @return The number of rows in the table + */ int rowCount(); + /** + * @param row The index of the row to retrieve + */ void addRow(List row); } diff --git a/tetrad-lib/src/main/java/edu/pitt/isp/sverchkov/data/DataTableImpl.java b/tetrad-lib/src/main/java/edu/pitt/isp/sverchkov/data/DataTableImpl.java index 3864c502df..5f847f628d 100644 --- a/tetrad-lib/src/main/java/edu/pitt/isp/sverchkov/data/DataTableImpl.java +++ b/tetrad-lib/src/main/java/edu/pitt/isp/sverchkov/data/DataTableImpl.java @@ -29,35 +29,50 @@ /** * Data table implementation. * - * @author YUS24 * @param Type of variable names * @param Type of variable values + * @author YUS24 */ public class DataTableImpl implements DataTable { private final List variables; private final List> rows; + /** + * @param vars The names of the variables in the table + */ public DataTableImpl(List vars) { this.variables = Collections.unmodifiableList(new ArrayList<>(vars)); this.rows = new ArrayList<>(); } + /** + * @return The variables in the table + */ @Override public List variables() { return this.variables; } + /** + * @return The number of columns in the table + */ @Override public int columnCount() { return this.variables.size(); } + /** + * @return The number of rows in the table + */ @Override public int rowCount() { return this.rows.size(); } + /** + * @param row The index of the row to retrieve + */ @Override public void addRow(List row) { int diff --git a/tetrad-lib/src/main/java/edu/pitt/isp/sverchkov/data/DataTools.java b/tetrad-lib/src/main/java/edu/pitt/isp/sverchkov/data/DataTools.java index b02f6ab4d6..1f8024f3d7 100644 --- a/tetrad-lib/src/main/java/edu/pitt/isp/sverchkov/data/DataTools.java +++ b/tetrad-lib/src/main/java/edu/pitt/isp/sverchkov/data/DataTools.java @@ -32,11 +32,17 @@ * @author YUS24 */ public class DataTools { - public static final String NEWLINE = System.getProperty("line.separator"); public static final String DELIMITER_REGEX = " *, *"; public static final String DELIMITER = ", "; + /** + * Reads a data table from a file. + * + * @param file The file to read from + * @return The data table + * @throws FileNotFoundException if the file is not found + */ public static DataTable dataTableFromFile(File file) throws FileNotFoundException { DataTable data = null; try (Scanner in = new Scanner(file)) { @@ -47,6 +53,14 @@ public static DataTable dataTableFromFile(File file) throws File return data; } + /** + * Saves a data table to a file. + * + * @param data The data table to save + * @param dest The file to save to + * @param headers Whether to include headers + * @throws IOException if something goes wrong + */ public static void saveCSV(DataTable data, File dest, boolean headers) throws IOException { try (BufferedWriter out = new BufferedWriter(new FileWriter(dest))) { diff --git a/tetrad-lib/src/main/java/jgpml/CsvtoMatrix.java b/tetrad-lib/src/main/java/jgpml/CsvtoMatrix.java index ee159f9797..4944787bd3 100644 --- a/tetrad-lib/src/main/java/jgpml/CsvtoMatrix.java +++ b/tetrad-lib/src/main/java/jgpml/CsvtoMatrix.java @@ -39,6 +39,8 @@ /** * Simple Class to load the example data from files straight into Matrices. + * + * @author jdramsey */ public class CsvtoMatrix { @@ -46,8 +48,8 @@ public class CsvtoMatrix { * Load data * * @param filename data file - * @param sizeofInputs - * @param sizeofOutputs + * @param sizeofInputs number of input variables + * @param sizeofOutputs number of output variables * @return [X, Y] */ public static Matrix[] load(String filename, int sizeofInputs, int sizeofOutputs) { @@ -124,7 +126,7 @@ public static Matrix[] load(String filename, int sizeofInputs, int sizeofOutputs /** * Simple example of how to use this class. * - * @param args + * @param args ignored */ public static void main(String[] args) { diff --git a/tetrad-lib/src/main/java/jgpml/GaussianProcess.java b/tetrad-lib/src/main/java/jgpml/GaussianProcess.java index ff6557f362..7321feaec5 100644 --- a/tetrad-lib/src/main/java/jgpml/GaussianProcess.java +++ b/tetrad-lib/src/main/java/jgpml/GaussianProcess.java @@ -38,6 +38,8 @@ /** * Main class of the package, contains the objects that constitutes a Gaussian Process as well as the algorithm to train * the Hyperparameters and to do predictions. + * + * @author jdramsey */ public class GaussianProcess { @@ -167,7 +169,7 @@ private static boolean hasInvalidNumbers(double[] array) { /** * A simple test * - * @param args + * @param args ignored */ public static void main(String[] args) { @@ -188,17 +190,8 @@ public static void main(String[] args) { gp.train(X, Y, params0, -20); - -// int size = 100; -// Matrix Xtrain = new Matrix(size, 1); -// Matrix Ytrain = new Matrix(size, 1); -// -// Matrix Xtest = new Matrix(size, 1); -// Matrix Ytest = new Matrix(size, 1); - // half of the sinusoid uses points very close to each other and the other half uses // more sparse data - Matrix[] datastar = CsvtoMatrix.load("../armdatastar.csv", 6, 1); Matrix Xstar = datastar[0]; Matrix Ystar = datastar[1]; @@ -260,15 +253,6 @@ public double negativeLogLikelihood(Matrix logtheta, Matrix x, Matrix y, Matrix // alpha = L'\(L\y); this.alpha = GaussianProcess.bSubstitutionWithTranspose(this.L, GaussianProcess.fSubstitution(this.L, y)); -// double[][] yarr = y.getArray(); -// double[][] alphaarr = alpha.getArray(); -// double lml =0; -// for(int i=0; iCovLINone CovarianceFunction + */ public CovLINone() { } + /** + * Main method for testing purposes + */ public static void main(String[] args) { CovLINone cf = new CovLINone(); diff --git a/tetrad-lib/src/main/java/jgpml/covariancefunctions/CovNNone.java b/tetrad-lib/src/main/java/jgpml/covariancefunctions/CovNNone.java index 96919159f4..3b28b8f82e 100644 --- a/tetrad-lib/src/main/java/jgpml/covariancefunctions/CovNNone.java +++ b/tetrad-lib/src/main/java/jgpml/covariancefunctions/CovNNone.java @@ -47,26 +47,24 @@ public class CovNNone implements CovarianceFunction { double[][] k; double[][] q; + /** + * Creates a new CovNNone CovarianceFunction + */ public CovNNone() { } + /** + * Main method for testing purposes + * @param args command line arguments + */ public static void main(String[] args) { CovNNone cf = new CovNNone(); Matrix X = Matrix.identity(6, 6); Matrix logtheta = new Matrix(new double[][]{{0.1}, {0.2}}); - - Matrix z = new Matrix(new double[][]{{1, 2, 3, 4, 5, 6}, {1, 2, 3, 4, 5, 6}}); - -// System.out.println("") -// -// long start = edu.cmu.tetrad.util.Timer.currentThreadCpuTimeMilliseconds() - Matrix d = cf.computeDerivatives(logtheta, X, 1); - d.print(d.getColumnDimension(), 8); - } /** diff --git a/tetrad-lib/src/main/java/jgpml/covariancefunctions/CovNNoneNoise.java b/tetrad-lib/src/main/java/jgpml/covariancefunctions/CovNNoneNoise.java index 947762534c..0f15e1cc31 100644 --- a/tetrad-lib/src/main/java/jgpml/covariancefunctions/CovNNoneNoise.java +++ b/tetrad-lib/src/main/java/jgpml/covariancefunctions/CovNNoneNoise.java @@ -50,9 +50,17 @@ public class CovNNoneNoise implements CovarianceFunction { double[][] k; double[][] q; + /** + * Creates a new CovNNoneNoise CovarianceFunction + */ public CovNNoneNoise() { } + /** + * Main method for testing purposes + * + * @param args command line arguments + */ public static void main(String[] args) { CovarianceFunction cf = new CovNNoneNoise(); diff --git a/tetrad-lib/src/main/java/jgpml/covariancefunctions/CovSEiso.java b/tetrad-lib/src/main/java/jgpml/covariancefunctions/CovSEiso.java index e0131512c4..58d2813987 100644 --- a/tetrad-lib/src/main/java/jgpml/covariancefunctions/CovSEiso.java +++ b/tetrad-lib/src/main/java/jgpml/covariancefunctions/CovSEiso.java @@ -47,6 +47,9 @@ public class CovSEiso implements CovarianceFunction { + /** + * Creates a new CovSEiso CovarianceFunction + */ public CovSEiso() { } @@ -74,6 +77,10 @@ private static Matrix squareDist(Matrix a, Matrix b) { return C; } + /** + * Main method for testing purposes + * @param args ignored + */ public static void main(String[] args) { CovSEiso cf = new CovSEiso(); @@ -168,25 +175,3 @@ public Matrix computeDerivatives(Matrix loghyper, Matrix X, int index) { return A; } } - -// private static Matrix squareDist(Matrix a, Matrix b, Matrix Q){ -// -// if(a.getColumnDimension()!=Q.getRowDimension() || b.getColumnDimension()!=Q.getColumnDimension()) -// throw new IllegalArgumentException("Wrong size of for Q "+Q.getRowDimension()+"x"+Q.getColumnDimension()+" instead of "+a.getColumnDimension()+"x"+b.getColumnDimension()); -// -// Matrix C = new Matrix(D,1); -// -// for (int i=0; iCovarianceFunction as sum of the @@ -126,6 +126,4 @@ public Matrix computeDerivatives(Matrix loghyper, Matrix X, int index) { index -= this.idx[whichf]; return this.f[whichf].computeDerivatives(loghyperi, X, index); } - - } diff --git a/tetrad-lib/src/main/java/jgpml/covariancefunctions/CovarianceFunction.java b/tetrad-lib/src/main/java/jgpml/covariancefunctions/CovarianceFunction.java index b0703d911b..48b2e60260 100644 --- a/tetrad-lib/src/main/java/jgpml/covariancefunctions/CovarianceFunction.java +++ b/tetrad-lib/src/main/java/jgpml/covariancefunctions/CovarianceFunction.java @@ -30,6 +30,9 @@ import Jama.Matrix; +/** + * Interface for covariance functions + */ public interface CovarianceFunction { /** diff --git a/tetrad-lib/src/main/java/jgpml/covariancefunctions/MatrixOperations.java b/tetrad-lib/src/main/java/jgpml/covariancefunctions/MatrixOperations.java index 2457783ebe..5e3e5f51fb 100644 --- a/tetrad-lib/src/main/java/jgpml/covariancefunctions/MatrixOperations.java +++ b/tetrad-lib/src/main/java/jgpml/covariancefunctions/MatrixOperations.java @@ -193,7 +193,5 @@ public static Matrix std(Matrix A) { return M; } } - - } diff --git a/tetrad-gui/src/main/resources/resources/images/AddNodeDown.gif b/tetrad-lib/src/main/resources/docs/images/AddNodeDown.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/AddNodeDown.gif rename to tetrad-lib/src/main/resources/docs/images/AddNodeDown.gif diff --git a/tetrad-gui/src/main/resources/resources/images/AddNodeOff.gif b/tetrad-lib/src/main/resources/docs/images/AddNodeOff.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/AddNodeOff.gif rename to tetrad-lib/src/main/resources/docs/images/AddNodeOff.gif diff --git a/tetrad-gui/src/main/resources/resources/images/AddNodeRoll.gif b/tetrad-lib/src/main/resources/docs/images/AddNodeRoll.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/AddNodeRoll.gif rename to tetrad-lib/src/main/resources/docs/images/AddNodeRoll.gif diff --git a/tetrad-gui/src/main/resources/resources/images/AddNodeUp.gif b/tetrad-lib/src/main/resources/docs/images/AddNodeUp.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/AddNodeUp.gif rename to tetrad-lib/src/main/resources/docs/images/AddNodeUp.gif diff --git a/tetrad-gui/src/main/resources/resources/images/Icon32a.png b/tetrad-lib/src/main/resources/docs/images/Icon32a.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/Icon32a.png rename to tetrad-lib/src/main/resources/docs/images/Icon32a.png diff --git a/tetrad-gui/src/main/resources/resources/images/TETRAD.gif b/tetrad-lib/src/main/resources/docs/images/TETRAD.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/TETRAD.gif rename to tetrad-lib/src/main/resources/docs/images/TETRAD.gif diff --git a/tetrad-gui/src/main/resources/resources/images/arrow-down.gif b/tetrad-lib/src/main/resources/docs/images/arrow-down.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/arrow-down.gif rename to tetrad-lib/src/main/resources/docs/images/arrow-down.gif diff --git a/tetrad-gui/src/main/resources/resources/images/arrow-left.gif b/tetrad-lib/src/main/resources/docs/images/arrow-left.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/arrow-left.gif rename to tetrad-lib/src/main/resources/docs/images/arrow-left.gif diff --git a/tetrad-gui/src/main/resources/resources/images/arrow-up.gif b/tetrad-lib/src/main/resources/docs/images/arrow-up.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/arrow-up.gif rename to tetrad-lib/src/main/resources/docs/images/arrow-up.gif diff --git a/tetrad-gui/src/main/resources/resources/images/bidirected2.gif b/tetrad-lib/src/main/resources/docs/images/bidirected2.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/bidirected2.gif rename to tetrad-lib/src/main/resources/docs/images/bidirected2.gif diff --git a/tetrad-gui/src/main/resources/resources/images/bidirected3.gif b/tetrad-lib/src/main/resources/docs/images/bidirected3.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/bidirected3.gif rename to tetrad-lib/src/main/resources/docs/images/bidirected3.gif diff --git a/tetrad-gui/src/main/resources/resources/images/bidirectedDown.gif b/tetrad-lib/src/main/resources/docs/images/bidirectedDown.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/bidirectedDown.gif rename to tetrad-lib/src/main/resources/docs/images/bidirectedDown.gif diff --git a/tetrad-gui/src/main/resources/resources/images/bidirectedOff.gif b/tetrad-lib/src/main/resources/docs/images/bidirectedOff.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/bidirectedOff.gif rename to tetrad-lib/src/main/resources/docs/images/bidirectedOff.gif diff --git a/tetrad-gui/src/main/resources/resources/images/bidirectedRoll.gif b/tetrad-lib/src/main/resources/docs/images/bidirectedRoll.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/bidirectedRoll.gif rename to tetrad-lib/src/main/resources/docs/images/bidirectedRoll.gif diff --git a/tetrad-gui/src/main/resources/resources/images/bidirectedUp.gif b/tetrad-lib/src/main/resources/docs/images/bidirectedUp.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/bidirectedUp.gif rename to tetrad-lib/src/main/resources/docs/images/bidirectedUp.gif diff --git a/tetrad-gui/src/main/resources/resources/images/circulararrow.gif b/tetrad-lib/src/main/resources/docs/images/circulararrow.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/circulararrow.gif rename to tetrad-lib/src/main/resources/docs/images/circulararrow.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/add.gif b/tetrad-lib/src/main/resources/docs/images/cl/add.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/add.gif rename to tetrad-lib/src/main/resources/docs/images/cl/add.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/add_latent.gif b/tetrad-lib/src/main/resources/docs/images/cl/add_latent.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/add_latent.gif rename to tetrad-lib/src/main/resources/docs/images/cl/add_latent.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/bidirected3.gif b/tetrad-lib/src/main/resources/docs/images/cl/bidirected3.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/bidirected3.gif rename to tetrad-lib/src/main/resources/docs/images/cl/bidirected3.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/blackedge.gif b/tetrad-lib/src/main/resources/docs/images/cl/blackedge.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/blackedge.gif rename to tetrad-lib/src/main/resources/docs/images/cl/blackedge.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/blank.gif b/tetrad-lib/src/main/resources/docs/images/cl/blank.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/blank.gif rename to tetrad-lib/src/main/resources/docs/images/cl/blank.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/blueedge.gif b/tetrad-lib/src/main/resources/docs/images/cl/blueedge.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/blueedge.gif rename to tetrad-lib/src/main/resources/docs/images/cl/blueedge.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/clAbout.gif b/tetrad-lib/src/main/resources/docs/images/cl/clAbout.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/clAbout.gif rename to tetrad-lib/src/main/resources/docs/images/cl/clAbout.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/clsplash.gif b/tetrad-lib/src/main/resources/docs/images/cl/clsplash.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/clsplash.gif rename to tetrad-lib/src/main/resources/docs/images/cl/clsplash.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/clsplashBAK.jpg b/tetrad-lib/src/main/resources/docs/images/cl/clsplashBAK.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/clsplashBAK.jpg rename to tetrad-lib/src/main/resources/docs/images/cl/clsplashBAK.jpg diff --git a/tetrad-gui/src/main/resources/resources/images/cl/clsplashV3_3.gif b/tetrad-lib/src/main/resources/docs/images/cl/clsplashV3_3.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/clsplashV3_3.gif rename to tetrad-lib/src/main/resources/docs/images/cl/clsplashV3_3.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/clsplashV4_0.gif b/tetrad-lib/src/main/resources/docs/images/cl/clsplashV4_0.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/clsplashV4_0.gif rename to tetrad-lib/src/main/resources/docs/images/cl/clsplashV4_0.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/correctGraph.gif b/tetrad-lib/src/main/resources/docs/images/cl/correctGraph.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/correctGraph.gif rename to tetrad-lib/src/main/resources/docs/images/cl/correctGraph.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/directed3.gif b/tetrad-lib/src/main/resources/docs/images/cl/directed3.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/directed3.gif rename to tetrad-lib/src/main/resources/docs/images/cl/directed3.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/eraser.gif b/tetrad-lib/src/main/resources/docs/images/cl/eraser.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/eraser.gif rename to tetrad-lib/src/main/resources/docs/images/cl/eraser.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/essay.gif b/tetrad-lib/src/main/resources/docs/images/cl/essay.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/essay.gif rename to tetrad-lib/src/main/resources/docs/images/cl/essay.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/essay_disabled.gif b/tetrad-lib/src/main/resources/docs/images/cl/essay_disabled.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/essay_disabled.gif rename to tetrad-lib/src/main/resources/docs/images/cl/essay_disabled.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/expt_setup.gif b/tetrad-lib/src/main/resources/docs/images/cl/expt_setup.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/expt_setup.gif rename to tetrad-lib/src/main/resources/docs/images/cl/expt_setup.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/expt_setup_active.gif b/tetrad-lib/src/main/resources/docs/images/cl/expt_setup_active.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/expt_setup_active.gif rename to tetrad-lib/src/main/resources/docs/images/cl/expt_setup_active.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/expt_setup_down.gif b/tetrad-lib/src/main/resources/docs/images/cl/expt_setup_down.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/expt_setup_down.gif rename to tetrad-lib/src/main/resources/docs/images/cl/expt_setup_down.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/expt_setup_over.gif b/tetrad-lib/src/main/resources/docs/images/cl/expt_setup_over.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/expt_setup_over.gif rename to tetrad-lib/src/main/resources/docs/images/cl/expt_setup_over.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/expt_setup_over_active.gif b/tetrad-lib/src/main/resources/docs/images/cl/expt_setup_over_active.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/expt_setup_over_active.gif rename to tetrad-lib/src/main/resources/docs/images/cl/expt_setup_over_active.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/feedback.gif b/tetrad-lib/src/main/resources/docs/images/cl/feedback.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/feedback.gif rename to tetrad-lib/src/main/resources/docs/images/cl/feedback.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/feedback_disabled.gif b/tetrad-lib/src/main/resources/docs/images/cl/feedback_disabled.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/feedback_disabled.gif rename to tetrad-lib/src/main/resources/docs/images/cl/feedback_disabled.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/guessedComboDependentIcon.gif b/tetrad-lib/src/main/resources/docs/images/cl/guessedComboDependentIcon.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/guessedComboDependentIcon.gif rename to tetrad-lib/src/main/resources/docs/images/cl/guessedComboDependentIcon.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/guessedComboIcon.gif b/tetrad-lib/src/main/resources/docs/images/cl/guessedComboIcon.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/guessedComboIcon.gif rename to tetrad-lib/src/main/resources/docs/images/cl/guessedComboIcon.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/guessedComboIndependentIcon.gif b/tetrad-lib/src/main/resources/docs/images/cl/guessedComboIndependentIcon.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/guessedComboIndependentIcon.gif rename to tetrad-lib/src/main/resources/docs/images/cl/guessedComboIndependentIcon.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/hiddenSign.gif b/tetrad-lib/src/main/resources/docs/images/cl/hiddenSign.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/hiddenSign.gif rename to tetrad-lib/src/main/resources/docs/images/cl/hiddenSign.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/hyp_graph.gif b/tetrad-lib/src/main/resources/docs/images/cl/hyp_graph.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/hyp_graph.gif rename to tetrad-lib/src/main/resources/docs/images/cl/hyp_graph.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/hyp_graph_active.gif b/tetrad-lib/src/main/resources/docs/images/cl/hyp_graph_active.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/hyp_graph_active.gif rename to tetrad-lib/src/main/resources/docs/images/cl/hyp_graph_active.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/hyp_graph_down.gif b/tetrad-lib/src/main/resources/docs/images/cl/hyp_graph_down.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/hyp_graph_down.gif rename to tetrad-lib/src/main/resources/docs/images/cl/hyp_graph_down.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/hyp_graph_over.gif b/tetrad-lib/src/main/resources/docs/images/cl/hyp_graph_over.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/hyp_graph_over.gif rename to tetrad-lib/src/main/resources/docs/images/cl/hyp_graph_over.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/hyp_manip_graph.gif b/tetrad-lib/src/main/resources/docs/images/cl/hyp_manip_graph.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/hyp_manip_graph.gif rename to tetrad-lib/src/main/resources/docs/images/cl/hyp_manip_graph.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/hyp_manip_graph_active.gif b/tetrad-lib/src/main/resources/docs/images/cl/hyp_manip_graph_active.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/hyp_manip_graph_active.gif rename to tetrad-lib/src/main/resources/docs/images/cl/hyp_manip_graph_active.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/hyp_manip_graph_down.gif b/tetrad-lib/src/main/resources/docs/images/cl/hyp_manip_graph_down.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/hyp_manip_graph_down.gif rename to tetrad-lib/src/main/resources/docs/images/cl/hyp_manip_graph_down.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/hyp_manip_graph_guess.gif b/tetrad-lib/src/main/resources/docs/images/cl/hyp_manip_graph_guess.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/hyp_manip_graph_guess.gif rename to tetrad-lib/src/main/resources/docs/images/cl/hyp_manip_graph_guess.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/hyp_manip_graph_over.gif b/tetrad-lib/src/main/resources/docs/images/cl/hyp_manip_graph_over.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/hyp_manip_graph_over.gif rename to tetrad-lib/src/main/resources/docs/images/cl/hyp_manip_graph_over.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/icon.gif b/tetrad-lib/src/main/resources/docs/images/cl/icon.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/icon.gif rename to tetrad-lib/src/main/resources/docs/images/cl/icon.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/ignored.gif b/tetrad-lib/src/main/resources/docs/images/cl/ignored.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/ignored.gif rename to tetrad-lib/src/main/resources/docs/images/cl/ignored.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/ignored_gray.gif b/tetrad-lib/src/main/resources/docs/images/cl/ignored_gray.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/ignored_gray.gif rename to tetrad-lib/src/main/resources/docs/images/cl/ignored_gray.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/independent.gif b/tetrad-lib/src/main/resources/docs/images/cl/independent.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/independent.gif rename to tetrad-lib/src/main/resources/docs/images/cl/independent.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/invisible.gif b/tetrad-lib/src/main/resources/docs/images/cl/invisible.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/invisible.gif rename to tetrad-lib/src/main/resources/docs/images/cl/invisible.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/latent3.gif b/tetrad-lib/src/main/resources/docs/images/cl/latent3.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/latent3.gif rename to tetrad-lib/src/main/resources/docs/images/cl/latent3.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/lock.gif b/tetrad-lib/src/main/resources/docs/images/cl/lock.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/lock.gif rename to tetrad-lib/src/main/resources/docs/images/cl/lock.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/lock_new.gif b/tetrad-lib/src/main/resources/docs/images/cl/lock_new.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/lock_new.gif rename to tetrad-lib/src/main/resources/docs/images/cl/lock_new.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/lock_new2.gif b/tetrad-lib/src/main/resources/docs/images/cl/lock_new2.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/lock_new2.gif rename to tetrad-lib/src/main/resources/docs/images/cl/lock_new2.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/move.gif b/tetrad-lib/src/main/resources/docs/images/cl/move.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/move.gif rename to tetrad-lib/src/main/resources/docs/images/cl/move.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/move3.gif b/tetrad-lib/src/main/resources/docs/images/cl/move3.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/move3.gif rename to tetrad-lib/src/main/resources/docs/images/cl/move3.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/notIndependent.gif b/tetrad-lib/src/main/resources/docs/images/cl/notIndependent.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/notIndependent.gif rename to tetrad-lib/src/main/resources/docs/images/cl/notIndependent.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/population.gif b/tetrad-lib/src/main/resources/docs/images/cl/population.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/population.gif rename to tetrad-lib/src/main/resources/docs/images/cl/population.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/population_active.gif b/tetrad-lib/src/main/resources/docs/images/cl/population_active.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/population_active.gif rename to tetrad-lib/src/main/resources/docs/images/cl/population_active.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/population_down.gif b/tetrad-lib/src/main/resources/docs/images/cl/population_down.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/population_down.gif rename to tetrad-lib/src/main/resources/docs/images/cl/population_down.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/population_hidden.gif b/tetrad-lib/src/main/resources/docs/images/cl/population_hidden.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/population_hidden.gif rename to tetrad-lib/src/main/resources/docs/images/cl/population_hidden.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/population_hidden_active.gif b/tetrad-lib/src/main/resources/docs/images/cl/population_hidden_active.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/population_hidden_active.gif rename to tetrad-lib/src/main/resources/docs/images/cl/population_hidden_active.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/population_hidden_down.gif b/tetrad-lib/src/main/resources/docs/images/cl/population_hidden_down.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/population_hidden_down.gif rename to tetrad-lib/src/main/resources/docs/images/cl/population_hidden_down.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/population_hidden_over.gif b/tetrad-lib/src/main/resources/docs/images/cl/population_hidden_over.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/population_hidden_over.gif rename to tetrad-lib/src/main/resources/docs/images/cl/population_hidden_over.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/population_over.gif b/tetrad-lib/src/main/resources/docs/images/cl/population_over.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/population_over.gif rename to tetrad-lib/src/main/resources/docs/images/cl/population_over.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/predict.gif b/tetrad-lib/src/main/resources/docs/images/cl/predict.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/predict.gif rename to tetrad-lib/src/main/resources/docs/images/cl/predict.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/predict_active.gif b/tetrad-lib/src/main/resources/docs/images/cl/predict_active.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/predict_active.gif rename to tetrad-lib/src/main/resources/docs/images/cl/predict_active.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/predict_down.gif b/tetrad-lib/src/main/resources/docs/images/cl/predict_down.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/predict_down.gif rename to tetrad-lib/src/main/resources/docs/images/cl/predict_down.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/predict_over.gif b/tetrad-lib/src/main/resources/docs/images/cl/predict_over.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/predict_over.gif rename to tetrad-lib/src/main/resources/docs/images/cl/predict_over.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/random.gif b/tetrad-lib/src/main/resources/docs/images/cl/random.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/random.gif rename to tetrad-lib/src/main/resources/docs/images/cl/random.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/random_new.gif b/tetrad-lib/src/main/resources/docs/images/cl/random_new.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/random_new.gif rename to tetrad-lib/src/main/resources/docs/images/cl/random_new.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/random_new2.gif b/tetrad-lib/src/main/resources/docs/images/cl/random_new2.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/random_new2.gif rename to tetrad-lib/src/main/resources/docs/images/cl/random_new2.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/rededge.gif b/tetrad-lib/src/main/resources/docs/images/cl/rededge.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/rededge.gif rename to tetrad-lib/src/main/resources/docs/images/cl/rededge.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/sample.gif b/tetrad-lib/src/main/resources/docs/images/cl/sample.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/sample.gif rename to tetrad-lib/src/main/resources/docs/images/cl/sample.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/sample_active.gif b/tetrad-lib/src/main/resources/docs/images/cl/sample_active.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/sample_active.gif rename to tetrad-lib/src/main/resources/docs/images/cl/sample_active.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/sample_down.gif b/tetrad-lib/src/main/resources/docs/images/cl/sample_down.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/sample_down.gif rename to tetrad-lib/src/main/resources/docs/images/cl/sample_down.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/sample_guess.gif b/tetrad-lib/src/main/resources/docs/images/cl/sample_guess.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/sample_guess.gif rename to tetrad-lib/src/main/resources/docs/images/cl/sample_guess.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/sample_over.gif b/tetrad-lib/src/main/resources/docs/images/cl/sample_over.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/sample_over.gif rename to tetrad-lib/src/main/resources/docs/images/cl/sample_over.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/sample_valid.gif b/tetrad-lib/src/main/resources/docs/images/cl/sample_valid.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/sample_valid.gif rename to tetrad-lib/src/main/resources/docs/images/cl/sample_valid.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/toolbar_checkans.gif b/tetrad-lib/src/main/resources/docs/images/cl/toolbar_checkans.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/toolbar_checkans.gif rename to tetrad-lib/src/main/resources/docs/images/cl/toolbar_checkans.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/toolbar_checkans_disabled.gif b/tetrad-lib/src/main/resources/docs/images/cl/toolbar_checkans_disabled.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/toolbar_checkans_disabled.gif rename to tetrad-lib/src/main/resources/docs/images/cl/toolbar_checkans_disabled.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/toolbar_finances.gif b/tetrad-lib/src/main/resources/docs/images/cl/toolbar_finances.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/toolbar_finances.gif rename to tetrad-lib/src/main/resources/docs/images/cl/toolbar_finances.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/toolbar_finances_disabled.gif b/tetrad-lib/src/main/resources/docs/images/cl/toolbar_finances_disabled.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/toolbar_finances_disabled.gif rename to tetrad-lib/src/main/resources/docs/images/cl/toolbar_finances_disabled.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/toolbar_instruction.gif b/tetrad-lib/src/main/resources/docs/images/cl/toolbar_instruction.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/toolbar_instruction.gif rename to tetrad-lib/src/main/resources/docs/images/cl/toolbar_instruction.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/toolbar_instruction_disabled.gif b/tetrad-lib/src/main/resources/docs/images/cl/toolbar_instruction_disabled.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/toolbar_instruction_disabled.gif rename to tetrad-lib/src/main/resources/docs/images/cl/toolbar_instruction_disabled.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/toolbar_save.gif b/tetrad-lib/src/main/resources/docs/images/cl/toolbar_save.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/toolbar_save.gif rename to tetrad-lib/src/main/resources/docs/images/cl/toolbar_save.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/toolbar_save_disabled.gif b/tetrad-lib/src/main/resources/docs/images/cl/toolbar_save_disabled.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/toolbar_save_disabled.gif rename to tetrad-lib/src/main/resources/docs/images/cl/toolbar_save_disabled.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/toolbar_showans.gif b/tetrad-lib/src/main/resources/docs/images/cl/toolbar_showans.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/toolbar_showans.gif rename to tetrad-lib/src/main/resources/docs/images/cl/toolbar_showans.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/toolbar_showans_disabled.gif b/tetrad-lib/src/main/resources/docs/images/cl/toolbar_showans_disabled.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/toolbar_showans_disabled.gif rename to tetrad-lib/src/main/resources/docs/images/cl/toolbar_showans_disabled.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/toolbar_submit.gif b/tetrad-lib/src/main/resources/docs/images/cl/toolbar_submit.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/toolbar_submit.gif rename to tetrad-lib/src/main/resources/docs/images/cl/toolbar_submit.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/toolbar_submit_disabled.gif b/tetrad-lib/src/main/resources/docs/images/cl/toolbar_submit_disabled.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/toolbar_submit_disabled.gif rename to tetrad-lib/src/main/resources/docs/images/cl/toolbar_submit_disabled.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/true_graph.gif b/tetrad-lib/src/main/resources/docs/images/cl/true_graph.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/true_graph.gif rename to tetrad-lib/src/main/resources/docs/images/cl/true_graph.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/true_graph_active.gif b/tetrad-lib/src/main/resources/docs/images/cl/true_graph_active.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/true_graph_active.gif rename to tetrad-lib/src/main/resources/docs/images/cl/true_graph_active.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/true_graph_down.gif b/tetrad-lib/src/main/resources/docs/images/cl/true_graph_down.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/true_graph_down.gif rename to tetrad-lib/src/main/resources/docs/images/cl/true_graph_down.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/true_graph_hidden.gif b/tetrad-lib/src/main/resources/docs/images/cl/true_graph_hidden.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/true_graph_hidden.gif rename to tetrad-lib/src/main/resources/docs/images/cl/true_graph_hidden.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/true_graph_hidden_active.gif b/tetrad-lib/src/main/resources/docs/images/cl/true_graph_hidden_active.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/true_graph_hidden_active.gif rename to tetrad-lib/src/main/resources/docs/images/cl/true_graph_hidden_active.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/true_graph_hidden_down.gif b/tetrad-lib/src/main/resources/docs/images/cl/true_graph_hidden_down.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/true_graph_hidden_down.gif rename to tetrad-lib/src/main/resources/docs/images/cl/true_graph_hidden_down.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/true_graph_hidden_over.gif b/tetrad-lib/src/main/resources/docs/images/cl/true_graph_hidden_over.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/true_graph_hidden_over.gif rename to tetrad-lib/src/main/resources/docs/images/cl/true_graph_hidden_over.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/true_graph_over.gif b/tetrad-lib/src/main/resources/docs/images/cl/true_graph_over.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/true_graph_over.gif rename to tetrad-lib/src/main/resources/docs/images/cl/true_graph_over.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/true_manip_graph.gif b/tetrad-lib/src/main/resources/docs/images/cl/true_manip_graph.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/true_manip_graph.gif rename to tetrad-lib/src/main/resources/docs/images/cl/true_manip_graph.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/true_manip_graph_active.gif b/tetrad-lib/src/main/resources/docs/images/cl/true_manip_graph_active.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/true_manip_graph_active.gif rename to tetrad-lib/src/main/resources/docs/images/cl/true_manip_graph_active.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/true_manip_graph_down.gif b/tetrad-lib/src/main/resources/docs/images/cl/true_manip_graph_down.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/true_manip_graph_down.gif rename to tetrad-lib/src/main/resources/docs/images/cl/true_manip_graph_down.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/true_manip_graph_hidden.gif b/tetrad-lib/src/main/resources/docs/images/cl/true_manip_graph_hidden.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/true_manip_graph_hidden.gif rename to tetrad-lib/src/main/resources/docs/images/cl/true_manip_graph_hidden.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/true_manip_graph_hidden_active.gif b/tetrad-lib/src/main/resources/docs/images/cl/true_manip_graph_hidden_active.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/true_manip_graph_hidden_active.gif rename to tetrad-lib/src/main/resources/docs/images/cl/true_manip_graph_hidden_active.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/true_manip_graph_hidden_down.gif b/tetrad-lib/src/main/resources/docs/images/cl/true_manip_graph_hidden_down.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/true_manip_graph_hidden_down.gif rename to tetrad-lib/src/main/resources/docs/images/cl/true_manip_graph_hidden_down.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/true_manip_graph_hidden_over.gif b/tetrad-lib/src/main/resources/docs/images/cl/true_manip_graph_hidden_over.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/true_manip_graph_hidden_over.gif rename to tetrad-lib/src/main/resources/docs/images/cl/true_manip_graph_hidden_over.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/true_manip_graph_over.gif b/tetrad-lib/src/main/resources/docs/images/cl/true_manip_graph_over.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/true_manip_graph_over.gif rename to tetrad-lib/src/main/resources/docs/images/cl/true_manip_graph_over.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/variable3.gif b/tetrad-lib/src/main/resources/docs/images/cl/variable3.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/variable3.gif rename to tetrad-lib/src/main/resources/docs/images/cl/variable3.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cl/visible.gif b/tetrad-lib/src/main/resources/docs/images/cl/visible.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cl/visible.gif rename to tetrad-lib/src/main/resources/docs/images/cl/visible.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cleanupDown.gif b/tetrad-lib/src/main/resources/docs/images/cleanupDown.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cleanupDown.gif rename to tetrad-lib/src/main/resources/docs/images/cleanupDown.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cleanupOff.gif b/tetrad-lib/src/main/resources/docs/images/cleanupOff.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cleanupOff.gif rename to tetrad-lib/src/main/resources/docs/images/cleanupOff.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cleanupRoll.gif b/tetrad-lib/src/main/resources/docs/images/cleanupRoll.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cleanupRoll.gif rename to tetrad-lib/src/main/resources/docs/images/cleanupRoll.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cleanupUp.gif b/tetrad-lib/src/main/resources/docs/images/cleanupUp.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cleanupUp.gif rename to tetrad-lib/src/main/resources/docs/images/cleanupUp.gif diff --git a/tetrad-gui/src/main/resources/resources/images/clear.png b/tetrad-lib/src/main/resources/docs/images/clear.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/clear.png rename to tetrad-lib/src/main/resources/docs/images/clear.png diff --git a/tetrad-gui/src/main/resources/resources/images/clearVariableDown.gif b/tetrad-lib/src/main/resources/docs/images/clearVariableDown.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/clearVariableDown.gif rename to tetrad-lib/src/main/resources/docs/images/clearVariableDown.gif diff --git a/tetrad-gui/src/main/resources/resources/images/clearVariableOff.gif b/tetrad-lib/src/main/resources/docs/images/clearVariableOff.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/clearVariableOff.gif rename to tetrad-lib/src/main/resources/docs/images/clearVariableOff.gif diff --git a/tetrad-gui/src/main/resources/resources/images/clearVariableRoll.gif b/tetrad-lib/src/main/resources/docs/images/clearVariableRoll.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/clearVariableRoll.gif rename to tetrad-lib/src/main/resources/docs/images/clearVariableRoll.gif diff --git a/tetrad-gui/src/main/resources/resources/images/clearVariableUp.gif b/tetrad-lib/src/main/resources/docs/images/clearVariableUp.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/clearVariableUp.gif rename to tetrad-lib/src/main/resources/docs/images/clearVariableUp.gif diff --git a/tetrad-gui/src/main/resources/resources/images/clearedgesDown.gif b/tetrad-lib/src/main/resources/docs/images/clearedgesDown.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/clearedgesDown.gif rename to tetrad-lib/src/main/resources/docs/images/clearedgesDown.gif diff --git a/tetrad-gui/src/main/resources/resources/images/clearedgesOff.gif b/tetrad-lib/src/main/resources/docs/images/clearedgesOff.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/clearedgesOff.gif rename to tetrad-lib/src/main/resources/docs/images/clearedgesOff.gif diff --git a/tetrad-gui/src/main/resources/resources/images/clearedgesRoll.gif b/tetrad-lib/src/main/resources/docs/images/clearedgesRoll.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/clearedgesRoll.gif rename to tetrad-lib/src/main/resources/docs/images/clearedgesRoll.gif diff --git a/tetrad-gui/src/main/resources/resources/images/clearedgesUp.gif b/tetrad-lib/src/main/resources/docs/images/clearedgesUp.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/clearedgesUp.gif rename to tetrad-lib/src/main/resources/docs/images/clearedgesUp.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cleargraphDown.gif b/tetrad-lib/src/main/resources/docs/images/cleargraphDown.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cleargraphDown.gif rename to tetrad-lib/src/main/resources/docs/images/cleargraphDown.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cleargraphOff.gif b/tetrad-lib/src/main/resources/docs/images/cleargraphOff.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cleargraphOff.gif rename to tetrad-lib/src/main/resources/docs/images/cleargraphOff.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cleargraphRoll.gif b/tetrad-lib/src/main/resources/docs/images/cleargraphRoll.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cleargraphRoll.gif rename to tetrad-lib/src/main/resources/docs/images/cleargraphRoll.gif diff --git a/tetrad-gui/src/main/resources/resources/images/cleargraphUp.gif b/tetrad-lib/src/main/resources/docs/images/cleargraphUp.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/cleargraphUp.gif rename to tetrad-lib/src/main/resources/docs/images/cleargraphUp.gif diff --git a/tetrad-gui/src/main/resources/resources/images/close.png b/tetrad-lib/src/main/resources/docs/images/close.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/close.png rename to tetrad-lib/src/main/resources/docs/images/close.png diff --git a/tetrad-gui/src/main/resources/resources/images/compareDown.gif b/tetrad-lib/src/main/resources/docs/images/compareDown.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/compareDown.gif rename to tetrad-lib/src/main/resources/docs/images/compareDown.gif diff --git a/tetrad-gui/src/main/resources/resources/images/compareIcon.gif b/tetrad-lib/src/main/resources/docs/images/compareIcon.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/compareIcon.gif rename to tetrad-lib/src/main/resources/docs/images/compareIcon.gif diff --git a/tetrad-gui/src/main/resources/resources/images/compareOff.gif b/tetrad-lib/src/main/resources/docs/images/compareOff.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/compareOff.gif rename to tetrad-lib/src/main/resources/docs/images/compareOff.gif diff --git a/tetrad-gui/src/main/resources/resources/images/compareRoll.gif b/tetrad-lib/src/main/resources/docs/images/compareRoll.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/compareRoll.gif rename to tetrad-lib/src/main/resources/docs/images/compareRoll.gif diff --git a/tetrad-gui/src/main/resources/resources/images/compareUp.gif b/tetrad-lib/src/main/resources/docs/images/compareUp.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/compareUp.gif rename to tetrad-lib/src/main/resources/docs/images/compareUp.gif diff --git a/tetrad-gui/src/main/resources/resources/images/dataDown.gif b/tetrad-lib/src/main/resources/docs/images/dataDown.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/dataDown.gif rename to tetrad-lib/src/main/resources/docs/images/dataDown.gif diff --git a/tetrad-gui/src/main/resources/resources/images/dataIcon.gif b/tetrad-lib/src/main/resources/docs/images/dataIcon.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/dataIcon.gif rename to tetrad-lib/src/main/resources/docs/images/dataIcon.gif diff --git a/tetrad-gui/src/main/resources/resources/images/dataOff.gif b/tetrad-lib/src/main/resources/docs/images/dataOff.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/dataOff.gif rename to tetrad-lib/src/main/resources/docs/images/dataOff.gif diff --git a/tetrad-gui/src/main/resources/resources/images/dataRoll.gif b/tetrad-lib/src/main/resources/docs/images/dataRoll.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/dataRoll.gif rename to tetrad-lib/src/main/resources/docs/images/dataRoll.gif diff --git a/tetrad-gui/src/main/resources/resources/images/dataUp.gif b/tetrad-lib/src/main/resources/docs/images/dataUp.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/dataUp.gif rename to tetrad-lib/src/main/resources/docs/images/dataUp.gif diff --git a/tetrad-gui/src/main/resources/resources/images/directDown.gif b/tetrad-lib/src/main/resources/docs/images/directDown.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/directDown.gif rename to tetrad-lib/src/main/resources/docs/images/directDown.gif diff --git a/tetrad-gui/src/main/resources/resources/images/directOff.gif b/tetrad-lib/src/main/resources/docs/images/directOff.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/directOff.gif rename to tetrad-lib/src/main/resources/docs/images/directOff.gif diff --git a/tetrad-gui/src/main/resources/resources/images/directRoll.gif b/tetrad-lib/src/main/resources/docs/images/directRoll.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/directRoll.gif rename to tetrad-lib/src/main/resources/docs/images/directRoll.gif diff --git a/tetrad-gui/src/main/resources/resources/images/directUp.gif b/tetrad-lib/src/main/resources/docs/images/directUp.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/directUp.gif rename to tetrad-lib/src/main/resources/docs/images/directUp.gif diff --git a/tetrad-gui/src/main/resources/resources/images/directed2.gif b/tetrad-lib/src/main/resources/docs/images/directed2.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/directed2.gif rename to tetrad-lib/src/main/resources/docs/images/directed2.gif diff --git a/tetrad-gui/src/main/resources/resources/images/directed3.gif b/tetrad-lib/src/main/resources/docs/images/directed3.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/directed3.gif rename to tetrad-lib/src/main/resources/docs/images/directed3.gif diff --git a/tetrad-gui/src/main/resources/resources/images/directedDown.gif b/tetrad-lib/src/main/resources/docs/images/directedDown.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/directedDown.gif rename to tetrad-lib/src/main/resources/docs/images/directedDown.gif diff --git a/tetrad-gui/src/main/resources/resources/images/directedOff.gif b/tetrad-lib/src/main/resources/docs/images/directedOff.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/directedOff.gif rename to tetrad-lib/src/main/resources/docs/images/directedOff.gif diff --git a/tetrad-gui/src/main/resources/resources/images/directedRoll.gif b/tetrad-lib/src/main/resources/docs/images/directedRoll.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/directedRoll.gif rename to tetrad-lib/src/main/resources/docs/images/directedRoll.gif diff --git a/tetrad-gui/src/main/resources/resources/images/directedUp.gif b/tetrad-lib/src/main/resources/docs/images/directedUp.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/directedUp.gif rename to tetrad-lib/src/main/resources/docs/images/directedUp.gif diff --git a/tetrad-gui/src/main/resources/resources/images/estimatorDown.gif b/tetrad-lib/src/main/resources/docs/images/estimatorDown.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/estimatorDown.gif rename to tetrad-lib/src/main/resources/docs/images/estimatorDown.gif diff --git a/tetrad-gui/src/main/resources/resources/images/estimatorIcon.gif b/tetrad-lib/src/main/resources/docs/images/estimatorIcon.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/estimatorIcon.gif rename to tetrad-lib/src/main/resources/docs/images/estimatorIcon.gif diff --git a/tetrad-gui/src/main/resources/resources/images/estimatorOff.gif b/tetrad-lib/src/main/resources/docs/images/estimatorOff.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/estimatorOff.gif rename to tetrad-lib/src/main/resources/docs/images/estimatorOff.gif diff --git a/tetrad-gui/src/main/resources/resources/images/estimatorRoll.gif b/tetrad-lib/src/main/resources/docs/images/estimatorRoll.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/estimatorRoll.gif rename to tetrad-lib/src/main/resources/docs/images/estimatorRoll.gif diff --git a/tetrad-gui/src/main/resources/resources/images/estimatorUp.gif b/tetrad-lib/src/main/resources/docs/images/estimatorUp.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/estimatorUp.gif rename to tetrad-lib/src/main/resources/docs/images/estimatorUp.gif diff --git a/tetrad-gui/src/main/resources/resources/images/fileDown.gif b/tetrad-lib/src/main/resources/docs/images/fileDown.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/fileDown.gif rename to tetrad-lib/src/main/resources/docs/images/fileDown.gif diff --git a/tetrad-gui/src/main/resources/resources/images/fileOff.gif b/tetrad-lib/src/main/resources/docs/images/fileOff.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/fileOff.gif rename to tetrad-lib/src/main/resources/docs/images/fileOff.gif diff --git a/tetrad-gui/src/main/resources/resources/images/fileRoll.gif b/tetrad-lib/src/main/resources/docs/images/fileRoll.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/fileRoll.gif rename to tetrad-lib/src/main/resources/docs/images/fileRoll.gif diff --git a/tetrad-gui/src/main/resources/resources/images/fileUp.gif b/tetrad-lib/src/main/resources/docs/images/fileUp.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/fileUp.gif rename to tetrad-lib/src/main/resources/docs/images/fileUp.gif diff --git a/tetrad-gui/src/main/resources/resources/images/flow.gif b/tetrad-lib/src/main/resources/docs/images/flow.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/flow.gif rename to tetrad-lib/src/main/resources/docs/images/flow.gif diff --git a/tetrad-gui/src/main/resources/resources/images/flowDown.gif b/tetrad-lib/src/main/resources/docs/images/flowDown.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/flowDown.gif rename to tetrad-lib/src/main/resources/docs/images/flowDown.gif diff --git a/tetrad-gui/src/main/resources/resources/images/flowOff.gif b/tetrad-lib/src/main/resources/docs/images/flowOff.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/flowOff.gif rename to tetrad-lib/src/main/resources/docs/images/flowOff.gif diff --git a/tetrad-gui/src/main/resources/resources/images/flowRoll.gif b/tetrad-lib/src/main/resources/docs/images/flowRoll.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/flowRoll.gif rename to tetrad-lib/src/main/resources/docs/images/flowRoll.gif diff --git a/tetrad-gui/src/main/resources/resources/images/flowUp.gif b/tetrad-lib/src/main/resources/docs/images/flowUp.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/flowUp.gif rename to tetrad-lib/src/main/resources/docs/images/flowUp.gif diff --git a/tetrad-gui/src/main/resources/resources/images/graduation_hat1.png b/tetrad-lib/src/main/resources/docs/images/graduation_hat1.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/graduation_hat1.png rename to tetrad-lib/src/main/resources/docs/images/graduation_hat1.png diff --git a/tetrad-gui/src/main/resources/resources/images/graphDown.gif b/tetrad-lib/src/main/resources/docs/images/graphDown.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/graphDown.gif rename to tetrad-lib/src/main/resources/docs/images/graphDown.gif diff --git a/tetrad-gui/src/main/resources/resources/images/graphIcon.gif b/tetrad-lib/src/main/resources/docs/images/graphIcon.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/graphIcon.gif rename to tetrad-lib/src/main/resources/docs/images/graphIcon.gif diff --git a/tetrad-gui/src/main/resources/resources/images/graphOff.gif b/tetrad-lib/src/main/resources/docs/images/graphOff.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/graphOff.gif rename to tetrad-lib/src/main/resources/docs/images/graphOff.gif diff --git a/tetrad-gui/src/main/resources/resources/images/graphRoll.gif b/tetrad-lib/src/main/resources/docs/images/graphRoll.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/graphRoll.gif rename to tetrad-lib/src/main/resources/docs/images/graphRoll.gif diff --git a/tetrad-gui/src/main/resources/resources/images/graphUp.gif b/tetrad-lib/src/main/resources/docs/images/graphUp.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/graphUp.gif rename to tetrad-lib/src/main/resources/docs/images/graphUp.gif diff --git a/tetrad-gui/src/main/resources/resources/images/ico1.gif b/tetrad-lib/src/main/resources/docs/images/ico1.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/ico1.gif rename to tetrad-lib/src/main/resources/docs/images/ico1.gif diff --git a/tetrad-gui/src/main/resources/resources/images/icontry2.gif b/tetrad-lib/src/main/resources/docs/images/icontry2.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/icontry2.gif rename to tetrad-lib/src/main/resources/docs/images/icontry2.gif diff --git a/tetrad-gui/src/main/resources/resources/images/imDown.gif b/tetrad-lib/src/main/resources/docs/images/imDown.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/imDown.gif rename to tetrad-lib/src/main/resources/docs/images/imDown.gif diff --git a/tetrad-gui/src/main/resources/resources/images/imIcon.gif b/tetrad-lib/src/main/resources/docs/images/imIcon.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/imIcon.gif rename to tetrad-lib/src/main/resources/docs/images/imIcon.gif diff --git a/tetrad-gui/src/main/resources/resources/images/imOff.gif b/tetrad-lib/src/main/resources/docs/images/imOff.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/imOff.gif rename to tetrad-lib/src/main/resources/docs/images/imOff.gif diff --git a/tetrad-gui/src/main/resources/resources/images/imRoll.gif b/tetrad-lib/src/main/resources/docs/images/imRoll.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/imRoll.gif rename to tetrad-lib/src/main/resources/docs/images/imRoll.gif diff --git a/tetrad-gui/src/main/resources/resources/images/imUp.gif b/tetrad-lib/src/main/resources/docs/images/imUp.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/imUp.gif rename to tetrad-lib/src/main/resources/docs/images/imUp.gif diff --git a/tetrad-gui/src/main/resources/resources/images/info.png b/tetrad-lib/src/main/resources/docs/images/info.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/info.png rename to tetrad-lib/src/main/resources/docs/images/info.png diff --git a/tetrad-gui/src/main/resources/resources/images/information-icon.png b/tetrad-lib/src/main/resources/docs/images/information-icon.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/information-icon.png rename to tetrad-lib/src/main/resources/docs/images/information-icon.png diff --git a/tetrad-gui/src/main/resources/resources/images/information_small.png b/tetrad-lib/src/main/resources/docs/images/information_small.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/information_small.png rename to tetrad-lib/src/main/resources/docs/images/information_small.png diff --git a/tetrad-gui/src/main/resources/resources/images/information_small_white.png b/tetrad-lib/src/main/resources/docs/images/information_small_white.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/information_small_white.png rename to tetrad-lib/src/main/resources/docs/images/information_small_white.png diff --git a/tetrad-gui/src/main/resources/resources/images/knowDown.gif b/tetrad-lib/src/main/resources/docs/images/knowDown.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/knowDown.gif rename to tetrad-lib/src/main/resources/docs/images/knowDown.gif diff --git a/tetrad-gui/src/main/resources/resources/images/knowIcon.gif b/tetrad-lib/src/main/resources/docs/images/knowIcon.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/knowIcon.gif rename to tetrad-lib/src/main/resources/docs/images/knowIcon.gif diff --git a/tetrad-gui/src/main/resources/resources/images/knowOff.gif b/tetrad-lib/src/main/resources/docs/images/knowOff.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/knowOff.gif rename to tetrad-lib/src/main/resources/docs/images/knowOff.gif diff --git a/tetrad-gui/src/main/resources/resources/images/knowRoll.gif b/tetrad-lib/src/main/resources/docs/images/knowRoll.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/knowRoll.gif rename to tetrad-lib/src/main/resources/docs/images/knowRoll.gif diff --git a/tetrad-gui/src/main/resources/resources/images/knowUp.gif b/tetrad-lib/src/main/resources/docs/images/knowUp.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/knowUp.gif rename to tetrad-lib/src/main/resources/docs/images/knowUp.gif diff --git a/tetrad-gui/src/main/resources/resources/images/latent2.gif b/tetrad-lib/src/main/resources/docs/images/latent2.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/latent2.gif rename to tetrad-lib/src/main/resources/docs/images/latent2.gif diff --git a/tetrad-gui/src/main/resources/resources/images/latent3.gif b/tetrad-lib/src/main/resources/docs/images/latent3.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/latent3.gif rename to tetrad-lib/src/main/resources/docs/images/latent3.gif diff --git a/tetrad-gui/src/main/resources/resources/images/latentDown.gif b/tetrad-lib/src/main/resources/docs/images/latentDown.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/latentDown.gif rename to tetrad-lib/src/main/resources/docs/images/latentDown.gif diff --git a/tetrad-gui/src/main/resources/resources/images/latentOff.gif b/tetrad-lib/src/main/resources/docs/images/latentOff.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/latentOff.gif rename to tetrad-lib/src/main/resources/docs/images/latentOff.gif diff --git a/tetrad-gui/src/main/resources/resources/images/latentRoll.gif b/tetrad-lib/src/main/resources/docs/images/latentRoll.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/latentRoll.gif rename to tetrad-lib/src/main/resources/docs/images/latentRoll.gif diff --git a/tetrad-gui/src/main/resources/resources/images/latentUp.gif b/tetrad-lib/src/main/resources/docs/images/latentUp.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/latentUp.gif rename to tetrad-lib/src/main/resources/docs/images/latentUp.gif diff --git a/tetrad-gui/src/main/resources/resources/images/miscB62.gif b/tetrad-lib/src/main/resources/docs/images/miscB62.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/miscB62.gif rename to tetrad-lib/src/main/resources/docs/images/miscB62.gif diff --git a/tetrad-gui/src/main/resources/resources/images/move.gif b/tetrad-lib/src/main/resources/docs/images/move.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/move.gif rename to tetrad-lib/src/main/resources/docs/images/move.gif diff --git a/tetrad-gui/src/main/resources/resources/images/move2.gif b/tetrad-lib/src/main/resources/docs/images/move2.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/move2.gif rename to tetrad-lib/src/main/resources/docs/images/move2.gif diff --git a/tetrad-gui/src/main/resources/resources/images/move3.gif b/tetrad-lib/src/main/resources/docs/images/move3.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/move3.gif rename to tetrad-lib/src/main/resources/docs/images/move3.gif diff --git a/tetrad-gui/src/main/resources/resources/images/moveDown.gif b/tetrad-lib/src/main/resources/docs/images/moveDown.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/moveDown.gif rename to tetrad-lib/src/main/resources/docs/images/moveDown.gif diff --git a/tetrad-gui/src/main/resources/resources/images/moveOff.gif b/tetrad-lib/src/main/resources/docs/images/moveOff.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/moveOff.gif rename to tetrad-lib/src/main/resources/docs/images/moveOff.gif diff --git a/tetrad-gui/src/main/resources/resources/images/moveRoll.gif b/tetrad-lib/src/main/resources/docs/images/moveRoll.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/moveRoll.gif rename to tetrad-lib/src/main/resources/docs/images/moveRoll.gif diff --git a/tetrad-gui/src/main/resources/resources/images/moveUp.gif b/tetrad-lib/src/main/resources/docs/images/moveUp.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/moveUp.gif rename to tetrad-lib/src/main/resources/docs/images/moveUp.gif diff --git a/tetrad-gui/src/main/resources/resources/images/nondirected2.gif b/tetrad-lib/src/main/resources/docs/images/nondirected2.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/nondirected2.gif rename to tetrad-lib/src/main/resources/docs/images/nondirected2.gif diff --git a/tetrad-gui/src/main/resources/resources/images/nondirected3.gif b/tetrad-lib/src/main/resources/docs/images/nondirected3.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/nondirected3.gif rename to tetrad-lib/src/main/resources/docs/images/nondirected3.gif diff --git a/tetrad-gui/src/main/resources/resources/images/nondirectedDown.gif b/tetrad-lib/src/main/resources/docs/images/nondirectedDown.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/nondirectedDown.gif rename to tetrad-lib/src/main/resources/docs/images/nondirectedDown.gif diff --git a/tetrad-gui/src/main/resources/resources/images/nondirectedOff.gif b/tetrad-lib/src/main/resources/docs/images/nondirectedOff.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/nondirectedOff.gif rename to tetrad-lib/src/main/resources/docs/images/nondirectedOff.gif diff --git a/tetrad-gui/src/main/resources/resources/images/nondirectedRoll.gif b/tetrad-lib/src/main/resources/docs/images/nondirectedRoll.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/nondirectedRoll.gif rename to tetrad-lib/src/main/resources/docs/images/nondirectedRoll.gif diff --git a/tetrad-gui/src/main/resources/resources/images/nondirectedUp.gif b/tetrad-lib/src/main/resources/docs/images/nondirectedUp.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/nondirectedUp.gif rename to tetrad-lib/src/main/resources/docs/images/nondirectedUp.gif diff --git a/tetrad-gui/src/main/resources/resources/images/note.png b/tetrad-lib/src/main/resources/docs/images/note.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/note.png rename to tetrad-lib/src/main/resources/docs/images/note.png diff --git a/tetrad-gui/src/main/resources/resources/images/partiallyoriented2.gif b/tetrad-lib/src/main/resources/docs/images/partiallyoriented2.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/partiallyoriented2.gif rename to tetrad-lib/src/main/resources/docs/images/partiallyoriented2.gif diff --git a/tetrad-gui/src/main/resources/resources/images/partiallyoriented3.gif b/tetrad-lib/src/main/resources/docs/images/partiallyoriented3.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/partiallyoriented3.gif rename to tetrad-lib/src/main/resources/docs/images/partiallyoriented3.gif diff --git a/tetrad-gui/src/main/resources/resources/images/partiallyorientedDown.gif b/tetrad-lib/src/main/resources/docs/images/partiallyorientedDown.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/partiallyorientedDown.gif rename to tetrad-lib/src/main/resources/docs/images/partiallyorientedDown.gif diff --git a/tetrad-gui/src/main/resources/resources/images/partiallyorientedOff.gif b/tetrad-lib/src/main/resources/docs/images/partiallyorientedOff.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/partiallyorientedOff.gif rename to tetrad-lib/src/main/resources/docs/images/partiallyorientedOff.gif diff --git a/tetrad-gui/src/main/resources/resources/images/partiallyorientedRoll.gif b/tetrad-lib/src/main/resources/docs/images/partiallyorientedRoll.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/partiallyorientedRoll.gif rename to tetrad-lib/src/main/resources/docs/images/partiallyorientedRoll.gif diff --git a/tetrad-gui/src/main/resources/resources/images/partiallyorientedUp.gif b/tetrad-lib/src/main/resources/docs/images/partiallyorientedUp.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/partiallyorientedUp.gif rename to tetrad-lib/src/main/resources/docs/images/partiallyorientedUp.gif diff --git a/tetrad-gui/src/main/resources/resources/images/pmDown.gif b/tetrad-lib/src/main/resources/docs/images/pmDown.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/pmDown.gif rename to tetrad-lib/src/main/resources/docs/images/pmDown.gif diff --git a/tetrad-gui/src/main/resources/resources/images/pmIcon.gif b/tetrad-lib/src/main/resources/docs/images/pmIcon.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/pmIcon.gif rename to tetrad-lib/src/main/resources/docs/images/pmIcon.gif diff --git a/tetrad-gui/src/main/resources/resources/images/pmOff.gif b/tetrad-lib/src/main/resources/docs/images/pmOff.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/pmOff.gif rename to tetrad-lib/src/main/resources/docs/images/pmOff.gif diff --git a/tetrad-gui/src/main/resources/resources/images/pmRoll.gif b/tetrad-lib/src/main/resources/docs/images/pmRoll.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/pmRoll.gif rename to tetrad-lib/src/main/resources/docs/images/pmRoll.gif diff --git a/tetrad-gui/src/main/resources/resources/images/pmUp.gif b/tetrad-lib/src/main/resources/docs/images/pmUp.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/pmUp.gif rename to tetrad-lib/src/main/resources/docs/images/pmUp.gif diff --git a/tetrad-gui/src/main/resources/resources/images/randomDown.gif b/tetrad-lib/src/main/resources/docs/images/randomDown.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/randomDown.gif rename to tetrad-lib/src/main/resources/docs/images/randomDown.gif diff --git a/tetrad-gui/src/main/resources/resources/images/randomIcon.gif b/tetrad-lib/src/main/resources/docs/images/randomIcon.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/randomIcon.gif rename to tetrad-lib/src/main/resources/docs/images/randomIcon.gif diff --git a/tetrad-gui/src/main/resources/resources/images/randomOff.gif b/tetrad-lib/src/main/resources/docs/images/randomOff.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/randomOff.gif rename to tetrad-lib/src/main/resources/docs/images/randomOff.gif diff --git a/tetrad-gui/src/main/resources/resources/images/randomRoll.gif b/tetrad-lib/src/main/resources/docs/images/randomRoll.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/randomRoll.gif rename to tetrad-lib/src/main/resources/docs/images/randomRoll.gif diff --git a/tetrad-gui/src/main/resources/resources/images/randomUp.gif b/tetrad-lib/src/main/resources/docs/images/randomUp.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/randomUp.gif rename to tetrad-lib/src/main/resources/docs/images/randomUp.gif diff --git a/tetrad-gui/src/main/resources/resources/images/repeatDown.gif b/tetrad-lib/src/main/resources/docs/images/repeatDown.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/repeatDown.gif rename to tetrad-lib/src/main/resources/docs/images/repeatDown.gif diff --git a/tetrad-gui/src/main/resources/resources/images/repeatOff.gif b/tetrad-lib/src/main/resources/docs/images/repeatOff.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/repeatOff.gif rename to tetrad-lib/src/main/resources/docs/images/repeatOff.gif diff --git a/tetrad-gui/src/main/resources/resources/images/repeatRoll.gif b/tetrad-lib/src/main/resources/docs/images/repeatRoll.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/repeatRoll.gif rename to tetrad-lib/src/main/resources/docs/images/repeatRoll.gif diff --git a/tetrad-gui/src/main/resources/resources/images/repeatUp.gif b/tetrad-lib/src/main/resources/docs/images/repeatUp.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/repeatUp.gif rename to tetrad-lib/src/main/resources/docs/images/repeatUp.gif diff --git a/tetrad-gui/src/main/resources/resources/images/save.png b/tetrad-lib/src/main/resources/docs/images/save.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/save.png rename to tetrad-lib/src/main/resources/docs/images/save.png diff --git a/tetrad-gui/src/main/resources/resources/images/searchDown.gif b/tetrad-lib/src/main/resources/docs/images/searchDown.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/searchDown.gif rename to tetrad-lib/src/main/resources/docs/images/searchDown.gif diff --git a/tetrad-gui/src/main/resources/resources/images/searchIcon.gif b/tetrad-lib/src/main/resources/docs/images/searchIcon.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/searchIcon.gif rename to tetrad-lib/src/main/resources/docs/images/searchIcon.gif diff --git a/tetrad-gui/src/main/resources/resources/images/searchOff.gif b/tetrad-lib/src/main/resources/docs/images/searchOff.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/searchOff.gif rename to tetrad-lib/src/main/resources/docs/images/searchOff.gif diff --git a/tetrad-gui/src/main/resources/resources/images/searchRoll.gif b/tetrad-lib/src/main/resources/docs/images/searchRoll.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/searchRoll.gif rename to tetrad-lib/src/main/resources/docs/images/searchRoll.gif diff --git a/tetrad-gui/src/main/resources/resources/images/searchUp.gif b/tetrad-lib/src/main/resources/docs/images/searchUp.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/searchUp.gif rename to tetrad-lib/src/main/resources/docs/images/searchUp.gif diff --git a/tetrad-gui/src/main/resources/resources/images/smallbidirectedDown.gif b/tetrad-lib/src/main/resources/docs/images/smallbidirectedDown.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/smallbidirectedDown.gif rename to tetrad-lib/src/main/resources/docs/images/smallbidirectedDown.gif diff --git a/tetrad-gui/src/main/resources/resources/images/smallbidirectedOff.gif b/tetrad-lib/src/main/resources/docs/images/smallbidirectedOff.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/smallbidirectedOff.gif rename to tetrad-lib/src/main/resources/docs/images/smallbidirectedOff.gif diff --git a/tetrad-gui/src/main/resources/resources/images/smallbidirectedRoll.gif b/tetrad-lib/src/main/resources/docs/images/smallbidirectedRoll.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/smallbidirectedRoll.gif rename to tetrad-lib/src/main/resources/docs/images/smallbidirectedRoll.gif diff --git a/tetrad-gui/src/main/resources/resources/images/smallbidirectedUp.gif b/tetrad-lib/src/main/resources/docs/images/smallbidirectedUp.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/smallbidirectedUp.gif rename to tetrad-lib/src/main/resources/docs/images/smallbidirectedUp.gif diff --git a/tetrad-gui/src/main/resources/resources/images/smalldirectedDown.gif b/tetrad-lib/src/main/resources/docs/images/smalldirectedDown.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/smalldirectedDown.gif rename to tetrad-lib/src/main/resources/docs/images/smalldirectedDown.gif diff --git a/tetrad-gui/src/main/resources/resources/images/smalldirectedOff.gif b/tetrad-lib/src/main/resources/docs/images/smalldirectedOff.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/smalldirectedOff.gif rename to tetrad-lib/src/main/resources/docs/images/smalldirectedOff.gif diff --git a/tetrad-gui/src/main/resources/resources/images/smalldirectedRoll.gif b/tetrad-lib/src/main/resources/docs/images/smalldirectedRoll.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/smalldirectedRoll.gif rename to tetrad-lib/src/main/resources/docs/images/smalldirectedRoll.gif diff --git a/tetrad-gui/src/main/resources/resources/images/smalldirectedUp.gif b/tetrad-lib/src/main/resources/docs/images/smalldirectedUp.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/smalldirectedUp.gif rename to tetrad-lib/src/main/resources/docs/images/smalldirectedUp.gif diff --git a/tetrad-gui/src/main/resources/resources/images/smallhalfdirectedDown.gif b/tetrad-lib/src/main/resources/docs/images/smallhalfdirectedDown.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/smallhalfdirectedDown.gif rename to tetrad-lib/src/main/resources/docs/images/smallhalfdirectedDown.gif diff --git a/tetrad-gui/src/main/resources/resources/images/smallhalfdirectedOff.gif b/tetrad-lib/src/main/resources/docs/images/smallhalfdirectedOff.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/smallhalfdirectedOff.gif rename to tetrad-lib/src/main/resources/docs/images/smallhalfdirectedOff.gif diff --git a/tetrad-gui/src/main/resources/resources/images/smallhalfdirectedRoll.gif b/tetrad-lib/src/main/resources/docs/images/smallhalfdirectedRoll.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/smallhalfdirectedRoll.gif rename to tetrad-lib/src/main/resources/docs/images/smallhalfdirectedRoll.gif diff --git a/tetrad-gui/src/main/resources/resources/images/smallhalfdirectedUp.gif b/tetrad-lib/src/main/resources/docs/images/smallhalfdirectedUp.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/smallhalfdirectedUp.gif rename to tetrad-lib/src/main/resources/docs/images/smallhalfdirectedUp.gif diff --git a/tetrad-gui/src/main/resources/resources/images/smallundirectedDown.gif b/tetrad-lib/src/main/resources/docs/images/smallundirectedDown.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/smallundirectedDown.gif rename to tetrad-lib/src/main/resources/docs/images/smallundirectedDown.gif diff --git a/tetrad-gui/src/main/resources/resources/images/smallundirectedOff.gif b/tetrad-lib/src/main/resources/docs/images/smallundirectedOff.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/smallundirectedOff.gif rename to tetrad-lib/src/main/resources/docs/images/smallundirectedOff.gif diff --git a/tetrad-gui/src/main/resources/resources/images/smallundirectedRoll.gif b/tetrad-lib/src/main/resources/docs/images/smallundirectedRoll.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/smallundirectedRoll.gif rename to tetrad-lib/src/main/resources/docs/images/smallundirectedRoll.gif diff --git a/tetrad-gui/src/main/resources/resources/images/smallundirectedUp.gif b/tetrad-lib/src/main/resources/docs/images/smallundirectedUp.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/smallundirectedUp.gif rename to tetrad-lib/src/main/resources/docs/images/smallundirectedUp.gif diff --git a/tetrad-gui/src/main/resources/resources/images/smallunorientedDown.gif b/tetrad-lib/src/main/resources/docs/images/smallunorientedDown.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/smallunorientedDown.gif rename to tetrad-lib/src/main/resources/docs/images/smallunorientedDown.gif diff --git a/tetrad-gui/src/main/resources/resources/images/smallunorientedOff.gif b/tetrad-lib/src/main/resources/docs/images/smallunorientedOff.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/smallunorientedOff.gif rename to tetrad-lib/src/main/resources/docs/images/smallunorientedOff.gif diff --git a/tetrad-gui/src/main/resources/resources/images/smallunorientedRoll.gif b/tetrad-lib/src/main/resources/docs/images/smallunorientedRoll.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/smallunorientedRoll.gif rename to tetrad-lib/src/main/resources/docs/images/smallunorientedRoll.gif diff --git a/tetrad-gui/src/main/resources/resources/images/smallunorientedUp.gif b/tetrad-lib/src/main/resources/docs/images/smallunorientedUp.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/smallunorientedUp.gif rename to tetrad-lib/src/main/resources/docs/images/smallunorientedUp.gif diff --git a/tetrad-gui/src/main/resources/resources/images/system_info.html b/tetrad-lib/src/main/resources/docs/images/system_info.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/system_info.html rename to tetrad-lib/src/main/resources/docs/images/system_info.html diff --git a/tetrad-gui/src/main/resources/resources/images/system_info_alt.png b/tetrad-lib/src/main/resources/docs/images/system_info_alt.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/system_info_alt.png rename to tetrad-lib/src/main/resources/docs/images/system_info_alt.png diff --git a/tetrad-gui/src/main/resources/resources/images/tableDown.gif b/tetrad-lib/src/main/resources/docs/images/tableDown.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/tableDown.gif rename to tetrad-lib/src/main/resources/docs/images/tableDown.gif diff --git a/tetrad-gui/src/main/resources/resources/images/tableOff.gif b/tetrad-lib/src/main/resources/docs/images/tableOff.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/tableOff.gif rename to tetrad-lib/src/main/resources/docs/images/tableOff.gif diff --git a/tetrad-gui/src/main/resources/resources/images/tableRoll.gif b/tetrad-lib/src/main/resources/docs/images/tableRoll.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/tableRoll.gif rename to tetrad-lib/src/main/resources/docs/images/tableRoll.gif diff --git a/tetrad-gui/src/main/resources/resources/images/tableUp.gif b/tetrad-lib/src/main/resources/docs/images/tableUp.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/tableUp.gif rename to tetrad-lib/src/main/resources/docs/images/tableUp.gif diff --git a/tetrad-gui/src/main/resources/resources/images/tetradicon.gif b/tetrad-lib/src/main/resources/docs/images/tetradicon.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/tetradicon.gif rename to tetrad-lib/src/main/resources/docs/images/tetradicon.gif diff --git a/tetrad-gui/src/main/resources/resources/images/three_arrows.gif b/tetrad-lib/src/main/resources/docs/images/three_arrows.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/three_arrows.gif rename to tetrad-lib/src/main/resources/docs/images/three_arrows.gif diff --git a/tetrad-gui/src/main/resources/resources/images/three_circles.gif b/tetrad-lib/src/main/resources/docs/images/three_circles.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/three_circles.gif rename to tetrad-lib/src/main/resources/docs/images/three_circles.gif diff --git a/tetrad-gui/src/main/resources/resources/images/toolbar_get_info.png b/tetrad-lib/src/main/resources/docs/images/toolbar_get_info.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/toolbar_get_info.png rename to tetrad-lib/src/main/resources/docs/images/toolbar_get_info.png diff --git a/tetrad-gui/src/main/resources/resources/images/tyler16.png b/tetrad-lib/src/main/resources/docs/images/tyler16.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/tyler16.png rename to tetrad-lib/src/main/resources/docs/images/tyler16.png diff --git a/tetrad-gui/src/main/resources/resources/images/tyler32.png b/tetrad-lib/src/main/resources/docs/images/tyler32.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/tyler32.png rename to tetrad-lib/src/main/resources/docs/images/tyler32.png diff --git a/tetrad-gui/src/main/resources/resources/images/undirected3.gif b/tetrad-lib/src/main/resources/docs/images/undirected3.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/undirected3.gif rename to tetrad-lib/src/main/resources/docs/images/undirected3.gif diff --git a/tetrad-gui/src/main/resources/resources/images/undirectedDown.gif b/tetrad-lib/src/main/resources/docs/images/undirectedDown.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/undirectedDown.gif rename to tetrad-lib/src/main/resources/docs/images/undirectedDown.gif diff --git a/tetrad-gui/src/main/resources/resources/images/undirectedOff.gif b/tetrad-lib/src/main/resources/docs/images/undirectedOff.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/undirectedOff.gif rename to tetrad-lib/src/main/resources/docs/images/undirectedOff.gif diff --git a/tetrad-gui/src/main/resources/resources/images/undirectedRoll.gif b/tetrad-lib/src/main/resources/docs/images/undirectedRoll.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/undirectedRoll.gif rename to tetrad-lib/src/main/resources/docs/images/undirectedRoll.gif diff --git a/tetrad-gui/src/main/resources/resources/images/undirectedUp.gif b/tetrad-lib/src/main/resources/docs/images/undirectedUp.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/undirectedUp.gif rename to tetrad-lib/src/main/resources/docs/images/undirectedUp.gif diff --git a/tetrad-gui/src/main/resources/resources/images/unorientedUp.gif b/tetrad-lib/src/main/resources/docs/images/unorientedUp.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/unorientedUp.gif rename to tetrad-lib/src/main/resources/docs/images/unorientedUp.gif diff --git a/tetrad-gui/src/main/resources/resources/images/updaterDown.gif b/tetrad-lib/src/main/resources/docs/images/updaterDown.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/updaterDown.gif rename to tetrad-lib/src/main/resources/docs/images/updaterDown.gif diff --git a/tetrad-gui/src/main/resources/resources/images/updaterIcon.gif b/tetrad-lib/src/main/resources/docs/images/updaterIcon.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/updaterIcon.gif rename to tetrad-lib/src/main/resources/docs/images/updaterIcon.gif diff --git a/tetrad-gui/src/main/resources/resources/images/updaterOff.gif b/tetrad-lib/src/main/resources/docs/images/updaterOff.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/updaterOff.gif rename to tetrad-lib/src/main/resources/docs/images/updaterOff.gif diff --git a/tetrad-gui/src/main/resources/resources/images/updaterRoll.gif b/tetrad-lib/src/main/resources/docs/images/updaterRoll.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/updaterRoll.gif rename to tetrad-lib/src/main/resources/docs/images/updaterRoll.gif diff --git a/tetrad-gui/src/main/resources/resources/images/updaterUp.gif b/tetrad-lib/src/main/resources/docs/images/updaterUp.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/updaterUp.gif rename to tetrad-lib/src/main/resources/docs/images/updaterUp.gif diff --git a/tetrad-gui/src/main/resources/resources/images/variable2.gif b/tetrad-lib/src/main/resources/docs/images/variable2.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/variable2.gif rename to tetrad-lib/src/main/resources/docs/images/variable2.gif diff --git a/tetrad-gui/src/main/resources/resources/images/variable3.gif b/tetrad-lib/src/main/resources/docs/images/variable3.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/variable3.gif rename to tetrad-lib/src/main/resources/docs/images/variable3.gif diff --git a/tetrad-gui/src/main/resources/resources/images/variableDown.gif b/tetrad-lib/src/main/resources/docs/images/variableDown.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/variableDown.gif rename to tetrad-lib/src/main/resources/docs/images/variableDown.gif diff --git a/tetrad-gui/src/main/resources/resources/images/variableOff.gif b/tetrad-lib/src/main/resources/docs/images/variableOff.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/variableOff.gif rename to tetrad-lib/src/main/resources/docs/images/variableOff.gif diff --git a/tetrad-gui/src/main/resources/resources/images/variableRoll.gif b/tetrad-lib/src/main/resources/docs/images/variableRoll.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/variableRoll.gif rename to tetrad-lib/src/main/resources/docs/images/variableRoll.gif diff --git a/tetrad-gui/src/main/resources/resources/images/variableUp.gif b/tetrad-lib/src/main/resources/docs/images/variableUp.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/variableUp.gif rename to tetrad-lib/src/main/resources/docs/images/variableUp.gif diff --git a/tetrad-gui/src/main/resources/resources/images/zoomDown.gif b/tetrad-lib/src/main/resources/docs/images/zoomDown.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/zoomDown.gif rename to tetrad-lib/src/main/resources/docs/images/zoomDown.gif diff --git a/tetrad-gui/src/main/resources/resources/images/zoomOff.gif b/tetrad-lib/src/main/resources/docs/images/zoomOff.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/zoomOff.gif rename to tetrad-lib/src/main/resources/docs/images/zoomOff.gif diff --git a/tetrad-gui/src/main/resources/resources/images/zoomRoll.gif b/tetrad-lib/src/main/resources/docs/images/zoomRoll.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/zoomRoll.gif rename to tetrad-lib/src/main/resources/docs/images/zoomRoll.gif diff --git a/tetrad-gui/src/main/resources/resources/images/zoomUp.gif b/tetrad-lib/src/main/resources/docs/images/zoomUp.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/images/zoomUp.gif rename to tetrad-lib/src/main/resources/docs/images/zoomUp.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/Map.jhm b/tetrad-lib/src/main/resources/docs/javahelp/Map.jhm similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/Map.jhm rename to tetrad-lib/src/main/resources/docs/javahelp/Map.jhm diff --git a/tetrad-gui/src/main/resources/resources/javahelp/TetradHelp.hs b/tetrad-lib/src/main/resources/docs/javahelp/TetradHelp.hs similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/TetradHelp.hs rename to tetrad-lib/src/main/resources/docs/javahelp/TetradHelp.hs diff --git a/tetrad-gui/src/main/resources/resources/javahelp/TetradHelpIndex.xml b/tetrad-lib/src/main/resources/docs/javahelp/TetradHelpIndex.xml similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/TetradHelpIndex.xml rename to tetrad-lib/src/main/resources/docs/javahelp/TetradHelpIndex.xml diff --git a/tetrad-gui/src/main/resources/resources/javahelp/TetradHelpTOC.xml b/tetrad-lib/src/main/resources/docs/javahelp/TetradHelpTOC.xml similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/TetradHelpTOC.xml rename to tetrad-lib/src/main/resources/docs/javahelp/TetradHelpTOC.xml diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/classify/classify_box.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/classify/classify_box.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/classify/classify_box.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/classify/classify_box.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/compare/compare_box.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/compare/compare_box.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/compare/compare_box.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/compare/compare_box.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/data/data_box.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/data/data_box.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/data/data_box.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/data/data_box.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/data/data_loader.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/data/data_loader.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/data/data_loader.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/data/data_loader.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/data/data_set_list.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/data/data_set_list.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/data/data_set_list.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/data/data_set_list.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/each_box_explained.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/each_box_explained.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/each_box_explained.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/each_box_explained.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/each_module_explained.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/each_module_explained.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/each_module_explained.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/each_module_explained.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/estimate/dirichlet_estimator.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/estimate/dirichlet_estimator.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/estimate/dirichlet_estimator.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/estimate/dirichlet_estimator.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/estimate/estimate_box.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/estimate/estimate_box.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/estimate/estimate_box.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/estimate/estimate_box.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/estimate/ml_bayes_estimator.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/estimate/ml_bayes_estimator.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/estimate/ml_bayes_estimator.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/estimate/ml_bayes_estimator.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/estimate/sem_estimator.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/estimate/sem_estimator.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/estimate/sem_estimator.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/estimate/sem_estimator.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/graph/dag.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/graph/dag.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/graph/dag.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/graph/dag.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/graph/general_graph.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/graph/general_graph.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/graph/general_graph.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/graph/general_graph.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/graph/graph_box.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/graph/graph_box.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/graph/graph_box.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/graph/graph_box.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/graph/sem_graph.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/graph/sem_graph.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/graph/sem_graph.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/graph/sem_graph.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/graph/time_graph.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/graph/time_graph.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/graph/time_graph.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/graph/time_graph.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/im/bayes_im.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/im/bayes_im.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/im/bayes_im.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/im/bayes_im.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/im/dirichlet_bayes_im.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/im/dirichlet_bayes_im.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/im/dirichlet_bayes_im.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/im/dirichlet_bayes_im.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/im/im_box.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/im/im_box.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/im/im_box.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/im/im_box.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/im/sem_im.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/im/sem_im.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/im/sem_im.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/im/sem_im.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/manipulated_data/manipulated2.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/manipulated_data/manipulated2.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/manipulated_data/manipulated2.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/manipulated_data/manipulated2.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/manipulated_data/manipulated3.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/manipulated_data/manipulated3.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/manipulated_data/manipulated3.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/manipulated_data/manipulated3.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/manipulated_data/manipulated_data_box.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/manipulated_data/manipulated_data_box.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/manipulated_data/manipulated_data_box.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/manipulated_data/manipulated_data_box.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/pm/bayes_pm.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/pm/bayes_pm.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/pm/bayes_pm.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/pm/bayes_pm.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/pm/pm_box.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/pm/pm_box.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/pm/pm_box.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/pm/pm_box.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/pm/sem_pm.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/pm/sem_pm.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/pm/sem_pm.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/pm/sem_pm.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/regression/logistic_regression.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/regression/logistic_regression.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/regression/logistic_regression.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/regression/logistic_regression.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/regression/multiple_linear_regression.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/regression/multiple_linear_regression.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/regression/multiple_linear_regression.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/regression/multiple_linear_regression.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/regression/regression_box.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/regression/regression_box.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/regression/regression_box.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/regression/regression_box.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/bdeu.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/bdeu.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/bdeu.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/bdeu.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/bpc.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/bpc.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/bpc.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/bpc.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/ccd.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/ccd.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/ccd.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/ccd.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/cfci.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/cfci.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/cfci.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/cfci.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/chisquare.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/chisquare.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/chisquare.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/chisquare.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/conditional_correlation.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/conditional_correlation.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/conditional_correlation.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/conditional_correlation.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/conditional_gaussian_bic.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/conditional_gaussian_bic.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/conditional_gaussian_bic.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/conditional_gaussian_bic.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/conditional_gaussian_lrt.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/conditional_gaussian_lrt.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/conditional_gaussian_lrt.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/conditional_gaussian_lrt.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/cpc.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/cpc.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/cpc.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/cpc.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/cpcs.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/cpcs.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/cpcs.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/cpcs.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/d_separation.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/d_separation.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/d_separation.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/d_separation.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/discrete_bic.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/discrete_bic.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/discrete_bic.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/discrete_bic.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/eb.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/eb.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/eb.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/eb.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/fas.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/fas.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/fas.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/fas.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/fci.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/fci.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/fci.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/fci.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/fisher_z.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/fisher_z.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/fisher_z.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/fisher_z.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/gccd.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/gccd.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/gccd.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/gccd.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/gfci.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/gfci.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/gfci.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/gfci.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/glasso.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/glasso.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/glasso.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/glasso.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/gsquare.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/gsquare.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/gsquare.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/gsquare.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/images.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/images.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/images.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/images.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/lingam.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/lingam.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/lingam.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/lingam.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/mbfs.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/mbfs.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/mbfs.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/mbfs.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/mgm.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/mgm.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/mgm.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/mgm.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/mimbuild.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/mimbuild.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/mimbuild.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/mimbuild.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/pc.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/pc.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/pc.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/pc.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/pcd.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/pcd.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/pcd.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/pcd.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/pclocal.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/pclocal.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/pclocal.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/pclocal.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/pcmax.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/pcmax.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/pcmax.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/pcmax.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/pcmaxlocal.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/pcmaxlocal.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/pcmaxlocal.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/pcmaxlocal.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/pcs.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/pcs.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/pcs.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/pcs.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/purify.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/purify.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/purify.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/purify.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/r1.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/r1.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/r1.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/r1.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/r2.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/r2.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/r2.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/r2.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/r3.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/r3.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/r3.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/r3.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/r4.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/r4.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/r4.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/r4.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/rfci.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/rfci.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/rfci.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/rfci.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/rskew.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/rskew.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/rskew.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/rskew.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/rskewe.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/rskewe.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/rskewe.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/rskewe.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/search_box.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/search_box.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/search_box.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/search_box.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/sem_bic.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/sem_bic.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/sem_bic.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/sem_bic.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/skew.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/skew.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/skew.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/skew.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/skewe.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/skewe.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/skewe.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/skewe.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/svarfci.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/svarfci.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/svarfci.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/svarfci.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/tsgfci.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/tsgfci.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/tsgfci.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/tsgfci.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/tsimages.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/tsimages.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/tsimages.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/tsimages.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/types_of_algorithms.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/types_of_algorithms.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/types_of_algorithms.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/types_of_algorithms.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/wfges.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/wfges.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/search/wfges.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/search/wfges.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/update/approximate_updater.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/update/approximate_updater.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/update/approximate_updater.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/update/approximate_updater.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/update/cpt_invariant_updater.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/update/cpt_invariant_updater.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/update/cpt_invariant_updater.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/update/cpt_invariant_updater.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/update/row_summing_updater.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/update/row_summing_updater.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/update/row_summing_updater.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/update/row_summing_updater.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/update/update_box.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/update/update_box.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/boxes/update/update_box.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/boxes/update/update_box.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/common_tasks.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/common_tasks.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/common_tasks.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/common_tasks.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/continuous_and_discrete_variables.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/continuous_and_discrete_variables.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/continuous_and_discrete_variables.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/continuous_and_discrete_variables.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/copying_and_pasting.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/copying_and_pasting.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/copying_and_pasting.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/copying_and_pasting.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/creating_data_from_scratch.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/creating_data_from_scratch.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/creating_data_from_scratch.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/creating_data_from_scratch.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/defining_discrete_variables.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/defining_discrete_variables.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/defining_discrete_variables.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/defining_discrete_variables.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/destroying_models.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/destroying_models.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/destroying_models.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/destroying_models.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/discretizing_data.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/discretizing_data.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/discretizing_data.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/discretizing_data.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/edge_orientation_shortcuts.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/edge_orientation_shortcuts.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/edge_orientation_shortcuts.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/edge_orientation_shortcuts.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/editing_covariance_matrices.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/editing_covariance_matrices.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/editing_covariance_matrices.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/editing_covariance_matrices.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/editing_knowledge.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/editing_knowledge.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/editing_knowledge.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/editing_knowledge.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/editing_node_properties.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/editing_node_properties.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/editing_node_properties.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/editing_node_properties.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/editing_tabular_data.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/editing_tabular_data.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/editing_tabular_data.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/editing_tabular_data.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/exiting_tetrad.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/exiting_tetrad.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/exiting_tetrad.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/exiting_tetrad.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/generating_random_dags.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/generating_random_dags.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/generating_random_dags.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/generating_random_dags.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/handling_missing_data.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/handling_missing_data.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/handling_missing_data.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/handling_missing_data.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/loading_covariance_matrices.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/loading_covariance_matrices.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/loading_covariance_matrices.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/loading_covariance_matrices.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/loading_data.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/loading_data.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/loading_data.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/loading_data.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/loading_tabular_data.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/loading_tabular_data.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/loading_tabular_data.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/loading_tabular_data.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/manipulating_data.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/manipulating_data.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/manipulating_data.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/manipulating_data.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/opening_sessions.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/opening_sessions.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/opening_sessions.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/opening_sessions.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/saving_screenshots.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/saving_screenshots.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/saving_screenshots.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/saving_screenshots.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/saving_sessions.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/saving_sessions.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/saving_sessions.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/saving_sessions.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/selecting_groups_of_nodes.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/selecting_groups_of_nodes.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/selecting_groups_of_nodes.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/selecting_groups_of_nodes.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/simulating_data.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/simulating_data.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/simulating_data.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/simulating_data.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/simulating_data_bayes.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/simulating_data_bayes.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/simulating_data_bayes.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/simulating_data_bayes.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/simulating_data_glass.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/simulating_data_glass.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/simulating_data_glass.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/simulating_data_glass.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/simulating_data_sem.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/simulating_data_sem.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/simulating_data_sem.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/simulating_data_sem.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/tabular_data_sets.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/tabular_data_sets.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/tabular_data_sets.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/tabular_data_sets.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/taking_screenshots.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/taking_screenshots.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/taking_screenshots.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/taking_screenshots.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/transferring_data_from_other_programs.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/transferring_data_from_other_programs.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/transferring_data_from_other_programs.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/transferring_data_from_other_programs.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/transferring_from_excel.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/transferring_from_excel.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/transferring_from_excel.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/transferring_from_excel.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/transferring_from_minitab.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/transferring_from_minitab.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/transferring_from_minitab.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/transferring_from_minitab.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/using_popup_menus.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/using_popup_menus.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/using_popup_menus.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/using_popup_menus.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/using_templates.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/using_templates.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/common_tasks/using_templates.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/common_tasks/using_templates.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/definitions/definitions.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/definitions/definitions.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/definitions/definitions.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/definitions/definitions.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/definitions/measured_latent_variables.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/definitions/measured_latent_variables.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/definitions/measured_latent_variables.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/definitions/measured_latent_variables.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/definitions/measurement_structural_graph.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/definitions/measurement_structural_graph.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/definitions/measurement_structural_graph.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/definitions/measurement_structural_graph.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/definitions/tetrad_graph_types.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/definitions/tetrad_graph_types.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/definitions/tetrad_graph_types.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/definitions/tetrad_graph_types.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/for_further_help.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/for_further_help.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/for_further_help.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/for_further_help.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/genetics/genetics.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/genetics/genetics.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/genetics/genetics.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/genetics/genetics.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/genetics/genetics_old.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/genetics/genetics_old.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/genetics/genetics_old.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/genetics/genetics_old.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/graph_edge_types.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/graph_edge_types.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/graph_edge_types.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/graph_edge_types.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/PMimage.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/PMimage.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/PMimage.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/PMimage.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/Thumbs.db b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/Thumbs.db similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/Thumbs.db rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/Thumbs.db diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/UBayescsopy.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/UBayescsopy.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/UBayescsopy.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/UBayescsopy.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/UBaysesIMcopy.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/UBaysesIMcopy.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/UBaysesIMcopy.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/UBaysesIMcopy.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/UComparseimage.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/UComparseimage.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/UComparseimage.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/UComparseimage.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/UIMSEM.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/UIMSEM.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/UIMSEM.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/UIMSEM.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/UIMedcopy.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/UIMedcopy.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/UIMedcopy.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/UIMedcopy.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/UIMimagecopy.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/UIMimagecopy.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/UIMimagecopy.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/UIMimagecopy.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/UPM.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/UPM.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/UPM.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/UPM.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/UcompsarePCcopy.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/UcompsarePCcopy.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/UcompsarePCcopy.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/UcompsarePCcopy.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/Ucompsaresheet.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/Ucompsaresheet.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/Ucompsaresheet.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/Ucompsaresheet.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/Ucontsdata.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/Ucontsdata.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/Ucontsdata.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/Ucontsdata.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/Udastasingle.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/Udastasingle.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/Udastasingle.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/Udastasingle.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/Udatsa.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/Udatsa.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/Udatsa.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/Udatsa.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/Uestimsate.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/Uestimsate.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/Uestimsate.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/Uestimsate.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/Uexpsanded.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/Uexpsanded.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/Uexpsanded.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/Uexpsanded.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/Uimportcopy.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/Uimportcopy.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/Uimportcopy.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/Uimportcopy.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/Uimtablecopy.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/Uimtablecopy.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/Uimtablecopy.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/Uimtablecopy.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/UntitiledsROC.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/UntitiledsROC.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/UntitiledsROC.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/UntitiledsROC.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/Untitled2Cslassify.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/Untitled2Cslassify.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/Untitled2Cslassify.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/Untitled2Cslassify.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/UntitledClasssifyResult.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/UntitledClasssifyResult.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/UntitledClasssifyResult.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/UntitledClasssifyResult.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/UntitledClsassifyWindow.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/UntitledClsassifyWindow.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/UntitledClsassifyWindow.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/UntitledClsassifyWindow.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/UntitledPsseudocount.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/UntitledPsseudocount.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/UntitledPsseudocount.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/UntitledPsseudocount.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/UntitledSsearchImagecopy.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/UntitledSsearchImagecopy.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/UntitledSsearchImagecopy.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/UntitledSsearchImagecopy.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/UntitledsGraphSearch.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/UntitledsGraphSearch.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/UntitledsGraphSearch.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/UntitledsGraphSearch.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/Untitledupdaterbox.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/Untitledupdaterbox.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/Untitledupdaterbox.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/Untitledupdaterbox.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/Uran.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/Uran.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/Uran.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/Uran.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/Utime.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/Utime.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/Utime.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/Utime.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/arrow_button.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/arrow_button.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/arrow_button.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/arrow_button.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/arrow_tool.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/arrow_tool.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/arrow_tool.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/arrow_tool.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/bayes_im_schema.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/bayes_im_schema.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/bayes_im_schema.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/bayes_im_schema.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/bayes_pm_schema.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/bayes_pm_schema.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/bayes_pm_schema.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/bayes_pm_schema.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/bayesim1.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/bayesim1.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/bayesim1.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/bayesim1.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/bayesim2.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/bayesim2.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/bayesim2.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/bayesim2.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/bayesim3.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/bayesim3.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/bayesim3.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/bayesim3.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/bayesim4.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/bayesim4.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/bayesim4.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/bayesim4.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/bayesim5.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/bayesim5.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/bayesim5.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/bayesim5.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/bayesim6.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/bayesim6.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/bayesim6.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/bayesim6.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/bayesim7.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/bayesim7.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/bayesim7.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/bayesim7.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/bayespm1.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/bayespm1.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/bayespm1.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/bayespm1.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/bayespm2.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/bayespm2.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/bayespm2.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/bayespm2.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/bayespm3.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/bayespm3.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/bayespm3.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/bayespm3.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/bayespm4.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/bayespm4.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/bayespm4.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/bayespm4.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/bayespm5.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/bayespm5.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/bayespm5.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/bayespm5.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/bidirectedEdge.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/bidirectedEdge.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/bidirectedEdge.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/bidirectedEdge.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/calvin_hobbes_instructions.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/calvin_hobbes_instructions.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/calvin_hobbes_instructions.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/calvin_hobbes_instructions.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/choose_data.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/choose_data.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/choose_data.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/choose_data.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/choose_load_data.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/choose_load_data.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/choose_load_data.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/choose_load_data.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/classify_button.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/classify_button.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/classify_button.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/classify_button.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/classify_highlight.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/classify_highlight.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/classify_highlight.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/classify_highlight.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/click_done_data.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/click_done_data.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/click_done_data.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/click_done_data.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/click_load.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/click_load.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/click_load.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/click_load.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/cluster1.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/cluster1.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/cluster1.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/cluster1.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/cluster2.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/cluster2.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/cluster2.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/cluster2.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/compare_button.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/compare_button.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/compare_button.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/compare_button.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/consructing_sessions1.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/consructing_sessions1.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/consructing_sessions1.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/consructing_sessions1.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/consructing_sessions2.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/consructing_sessions2.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/consructing_sessions2.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/consructing_sessions2.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/consructing_sessions3.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/consructing_sessions3.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/consructing_sessions3.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/consructing_sessions3.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/consructing_sessions4.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/consructing_sessions4.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/consructing_sessions4.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/consructing_sessions4.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/consructing_sessions5.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/consructing_sessions5.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/consructing_sessions5.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/consructing_sessions5.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/consructing_sessions6.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/consructing_sessions6.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/consructing_sessions6.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/consructing_sessions6.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/consructing_sessions7.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/consructing_sessions7.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/consructing_sessions7.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/consructing_sessions7.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/copying1.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/copying1.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/copying1.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/copying1.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/copying2.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/copying2.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/copying2.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/copying2.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/copying3.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/copying3.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/copying3.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/copying3.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/copying4.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/copying4.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/copying4.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/copying4.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/createBayesNet.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/createBayesNet.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/createBayesNet.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/createBayesNet.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/dag_editor.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/dag_editor.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/dag_editor.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/dag_editor.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/dag_from_data.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/dag_from_data.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/dag_from_data.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/dag_from_data.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/dag_from_data2.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/dag_from_data2.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/dag_from_data2.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/dag_from_data2.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/dag_graph_image.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/dag_graph_image.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/dag_graph_image.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/dag_graph_image.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/dageditorwindow.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/dageditorwindow.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/dageditorwindow.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/dageditorwindow.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/data_button.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/data_button.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/data_button.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/data_button.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/data_highlight.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/data_highlight.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/data_highlight.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/data_highlight.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/data_loader_1.PNG b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/data_loader_1.PNG similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/data_loader_1.PNG rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/data_loader_1.PNG diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/data_loader_2.PNG b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/data_loader_2.PNG similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/data_loader_2.PNG rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/data_loader_2.PNG diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/data_loader_3.PNG b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/data_loader_3.PNG similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/data_loader_3.PNG rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/data_loader_3.PNG diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/data_loader_4.PNG b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/data_loader_4.PNG similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/data_loader_4.PNG rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/data_loader_4.PNG diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/data_loader_5.PNG b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/data_loader_5.PNG similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/data_loader_5.PNG rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/data_loader_5.PNG diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/data_loader_6.PNG b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/data_loader_6.PNG similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/data_loader_6.PNG rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/data_loader_6.PNG diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/data_standatalone_highlight.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/data_standatalone_highlight.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/data_standatalone_highlight.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/data_standatalone_highlight.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/databox1.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/databox1.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/databox1.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/databox1.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/databox2.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/databox2.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/databox2.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/databox2.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/databox3.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/databox3.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/databox3.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/databox3.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/databox4.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/databox4.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/databox4.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/databox4.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/dataloader1.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/dataloader1.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/dataloader1.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/dataloader1.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/dataloader2.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/dataloader2.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/dataloader2.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/dataloader2.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/dataloader3.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/dataloader3.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/dataloader3.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/dataloader3.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/dataloader4.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/dataloader4.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/dataloader4.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/dataloader4.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/dataloader4.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/dataloader4.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/dataloader4.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/dataloader4.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/dataset_schema.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/dataset_schema.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/dataset_schema.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/dataset_schema.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/defineSampleSize.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/defineSampleSize.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/defineSampleSize.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/defineSampleSize.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/directedEdge.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/directedEdge.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/directedEdge.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/directedEdge.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/dirichletbayesim1.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/dirichletbayesim1.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/dirichletbayesim1.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/dirichletbayesim1.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/dirichletbayesim2.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/dirichletbayesim2.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/dirichletbayesim2.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/dirichletbayesim2.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/dirichletbayesim3.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/dirichletbayesim3.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/dirichletbayesim3.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/dirichletbayesim3.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/dirichletbayesim4.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/dirichletbayesim4.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/dirichletbayesim4.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/dirichletbayesim4.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/dirichletbayesim5.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/dirichletbayesim5.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/dirichletbayesim5.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/dirichletbayesim5.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/dirichletbayesim6.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/dirichletbayesim6.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/dirichletbayesim6.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/dirichletbayesim6.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/dirichletbayesim7.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/dirichletbayesim7.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/dirichletbayesim7.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/dirichletbayesim7.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/discretization1.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/discretization1.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/discretization1.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/discretization1.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/discretization2.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/discretization2.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/discretization2.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/discretization2.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/discretization3.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/discretization3.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/discretization3.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/discretization3.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/discretization4.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/discretization4.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/discretization4.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/discretization4.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/discretization5.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/discretization5.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/discretization5.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/discretization5.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/discretization6.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/discretization6.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/discretization6.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/discretization6.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/edge_orientation_shortcuts1.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/edge_orientation_shortcuts1.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/edge_orientation_shortcuts1.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/edge_orientation_shortcuts1.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/edge_orientation_shortcuts2.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/edge_orientation_shortcuts2.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/edge_orientation_shortcuts2.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/edge_orientation_shortcuts2.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/edge_orientation_shortcuts3.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/edge_orientation_shortcuts3.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/edge_orientation_shortcuts3.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/edge_orientation_shortcuts3.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/edge_orientation_shortcuts4.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/edge_orientation_shortcuts4.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/edge_orientation_shortcuts4.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/edge_orientation_shortcuts4.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/edit_menu.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/edit_menu.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/edit_menu.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/edit_menu.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/editing_data1.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/editing_data1.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/editing_data1.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/editing_data1.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/editing_data2.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/editing_data2.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/editing_data2.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/editing_data2.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/editing_data3.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/editing_data3.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/editing_data3.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/editing_data3.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/editing_data4.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/editing_data4.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/editing_data4.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/editing_data4.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/editing_knowledge1.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/editing_knowledge1.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/editing_knowledge1.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/editing_knowledge1.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/editing_knowledge2.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/editing_knowledge2.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/editing_knowledge2.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/editing_knowledge2.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/editing_knowledge3.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/editing_knowledge3.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/editing_knowledge3.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/editing_knowledge3.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/editing_knowledge4.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/editing_knowledge4.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/editing_knowledge4.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/editing_knowledge4.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/editing_knowledge5.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/editing_knowledge5.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/editing_knowledge5.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/editing_knowledge5.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/editing_knowledge6.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/editing_knowledge6.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/editing_knowledge6.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/editing_knowledge6.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/editing_nodes1.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/editing_nodes1.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/editing_nodes1.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/editing_nodes1.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/editing_nodes2.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/editing_nodes2.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/editing_nodes2.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/editing_nodes2.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/editing_nodes3.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/editing_nodes3.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/editing_nodes3.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/editing_nodes3.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/estimator_button.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/estimator_button.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/estimator_button.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/estimator_button.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/example_workflow_schema.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/example_workflow_schema.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/example_workflow_schema.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/example_workflow_schema.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/file_menu.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/file_menu.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/file_menu.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/file_menu.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/flowchart_dependencies1.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/flowchart_dependencies1.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/flowchart_dependencies1.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/flowchart_dependencies1.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/flowchart_dependencies2.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/flowchart_dependencies2.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/flowchart_dependencies2.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/flowchart_dependencies2.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/flowcharterButton.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/flowcharterButton.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/flowcharterButton.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/flowcharterButton.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/generalgrapheditorwindow.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/generalgrapheditorwindow.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/generalgrapheditorwindow.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/generalgrapheditorwindow.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/generateData.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/generateData.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/generateData.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/generateData.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/ges1.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/ges1.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/ges1.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/ges1.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/graph1.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/graph1.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/graph1.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/graph1.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/graph1_to_pm1.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/graph1_to_pm1.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/graph1_to_pm1.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/graph1_to_pm1.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/graph1choices.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/graph1choices.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/graph1choices.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/graph1choices.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/graph1editorwindow.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/graph1editorwindow.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/graph1editorwindow.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/graph1editorwindow.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/graph1structureeditor.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/graph1structureeditor.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/graph1structureeditor.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/graph1structureeditor.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/graph2editorwindow.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/graph2editorwindow.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/graph2editorwindow.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/graph2editorwindow.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/graph2structureeditor.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/graph2structureeditor.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/graph2structureeditor.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/graph2structureeditor.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/graphButton.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/graphButton.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/graphButton.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/graphButton.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/graphEditor.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/graphEditor.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/graphEditor.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/graphEditor.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/graphWindow.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/graphWindow.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/graphWindow.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/graphWindow.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/graph_button.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/graph_button.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/graph_button.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/graph_button.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/graph_gen_schema.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/graph_gen_schema.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/graph_gen_schema.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/graph_gen_schema.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/graph_highlight.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/graph_highlight.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/graph_highlight.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/graph_highlight.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/graph_schema.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/graph_schema.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/graph_schema.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/graph_schema.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/help_menu.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/help_menu.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/help_menu.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/help_menu.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/im_button.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/im_button.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/im_button.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/im_button.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/im_highlight.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/im_highlight.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/im_highlight.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/im_highlight.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/images.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/images.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/images.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/images.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/instantiatedModelButton.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/instantiatedModelButton.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/instantiatedModelButton.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/instantiatedModelButton.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/instantiatedWindow.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/instantiatedWindow.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/instantiatedWindow.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/instantiatedWindow.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/knowledge1.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/knowledge1.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/knowledge1.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/knowledge1.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/knowledge2.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/knowledge2.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/knowledge2.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/knowledge2.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/knowledge3.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/knowledge3.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/knowledge3.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/knowledge3.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/knowledge4.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/knowledge4.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/knowledge4.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/knowledge4.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/knowledge_button.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/knowledge_button.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/knowledge_button.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/knowledge_button.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/knowledge_schema.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/knowledge_schema.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/knowledge_schema.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/knowledge_schema.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/loading_data1.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/loading_data1.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/loading_data1.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/loading_data1.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/loading_data2.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/loading_data2.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/loading_data2.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/loading_data2.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/loading_data3.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/loading_data3.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/loading_data3.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/loading_data3.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/logging_menu.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/logging_menu.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/logging_menu.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/logging_menu.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/main_menu.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/main_menu.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/main_menu.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/main_menu.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/main_workbench.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/main_workbench.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/main_workbench.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/main_workbench.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/main_workbench2.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/main_workbench2.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/main_workbench2.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/main_workbench2.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/main_workbench2.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/main_workbench2.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/main_workbench2.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/main_workbench2.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/main_workbench3.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/main_workbench3.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/main_workbench3.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/main_workbench3.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/main_workbench3.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/main_workbench3.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/main_workbench3.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/main_workbench3.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/main_workbench4.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/main_workbench4.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/main_workbench4.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/main_workbench4.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/main_workspace.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/main_workspace.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/main_workspace.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/main_workspace.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/manipulatedButton.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/manipulatedButton.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/manipulatedButton.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/manipulatedButton.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/manipulatedData.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/manipulatedData.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/manipulatedData.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/manipulatedData.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/manipulated_data_button.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/manipulated_data_button.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/manipulated_data_button.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/manipulated_data_button.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/manipulated_highlight.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/manipulated_highlight.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/manipulated_highlight.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/manipulated_highlight.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/measured_vs_latent1.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/measured_vs_latent1.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/measured_vs_latent1.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/measured_vs_latent1.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/measured_vs_latent2.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/measured_vs_latent2.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/measured_vs_latent2.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/measured_vs_latent2.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/menubar.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/menubar.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/menubar.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/menubar.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/mimbuild1.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/mimbuild1.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/mimbuild1.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/mimbuild1.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/mimbuild3.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/mimbuild3.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/mimbuild3.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/mimbuild3.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/mimbuild4.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/mimbuild4.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/mimbuild4.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/mimbuild4.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/objects.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/objects.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/objects.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/objects.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/parametric_model_button.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/parametric_model_button.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/parametric_model_button.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/parametric_model_button.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/pc_output.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/pc_output.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/pc_output.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/pc_output.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/pcsearch1.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/pcsearch1.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/pcsearch1.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/pcsearch1.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/pcsearch2.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/pcsearch2.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/pcsearch2.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/pcsearch2.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/pcsearch3.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/pcsearch3.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/pcsearch3.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/pcsearch3.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/pcsearch_dialog.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/pcsearch_dialog.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/pcsearch_dialog.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/pcsearch_dialog.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/place_data_box.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/place_data_box.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/place_data_box.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/place_data_box.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/pm_button.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/pm_button.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/pm_button.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/pm_button.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/pm_highlight.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/pm_highlight.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/pm_highlight.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/pm_highlight.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/pm_image.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/pm_image.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/pm_image.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/pm_image.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/purify1.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/purify1.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/purify1.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/purify1.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/purify2.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/purify2.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/purify2.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/purify2.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/purify3.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/purify3.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/purify3.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/purify3.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/purify4.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/purify4.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/purify4.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/purify4.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/red_x.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/red_x.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/red_x.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/red_x.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/regression_button.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/regression_button.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/regression_button.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/regression_button.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/regression_highlight.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/regression_highlight.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/regression_highlight.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/regression_highlight.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/rubberband1.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/rubberband1.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/rubberband1.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/rubberband1.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/rubberband2.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/rubberband2.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/rubberband2.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/rubberband2.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/save_data.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/save_data.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/save_data.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/save_data.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/searchCsreation.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/searchCsreation.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/searchCsreation.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/searchCsreation.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/search_box.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/search_box.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/search_box.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/search_box.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/search_button.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/search_button.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/search_button.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/search_button.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/search_done.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/search_done.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/search_done.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/search_done.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/search_from_data_highlight.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/search_from_data_highlight.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/search_from_data_highlight.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/search_from_data_highlight.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/search_from_graph_highlight.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/search_from_graph_highlight.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/search_from_graph_highlight.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/search_from_graph_highlight.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/search_params.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/search_params.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/search_params.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/search_params.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/search_schema.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/search_schema.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/search_schema.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/search_schema.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/searcsreation.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/searcsreation.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/searcsreation.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/searcsreation.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/select_move_button.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/select_move_button.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/select_move_button.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/select_move_button.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/sem_graph1.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/sem_graph1.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/sem_graph1.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/sem_graph1.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/sem_graph2.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/sem_graph2.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/sem_graph2.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/sem_graph2.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/sem_graph3.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/sem_graph3.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/sem_graph3.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/sem_graph3.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/sem_im_schema.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/sem_im_schema.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/sem_im_schema.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/sem_im_schema.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/sem_pm_schema.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/sem_pm_schema.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/sem_pm_schema.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/sem_pm_schema.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/semim1.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/semim1.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/semim1.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/semim1.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/semim2.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/semim2.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/semim2.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/semim2.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/semim3.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/semim3.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/semim3.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/semim3.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/semim4.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/semim4.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/semim4.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/semim4.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/semim5.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/semim5.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/semim5.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/semim5.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/semim6.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/semim6.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/semim6.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/semim6.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/semim7.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/semim7.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/semim7.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/semim7.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/semim8.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/semim8.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/semim8.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/semim8.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/sempm1.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/sempm1.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/sempm1.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/sempm1.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/sempm2.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/sempm2.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/sempm2.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/sempm2.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/sempm3.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/sempm3.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/sempm3.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/sempm3.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/sempm4.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/sempm4.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/sempm4.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/sempm4.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/sempm5.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/sempm5.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/sempm5.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/sempm5.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/sempm6.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/sempm6.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/sempm6.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/sempm6.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/templates_estimatedatabayes.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/templates_estimatedatabayes.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/templates_estimatedatabayes.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/templates_estimatedatabayes.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/templates_estimatedatasem.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/templates_estimatedatasem.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/templates_estimatedatasem.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/templates_estimatedatasem.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/templates_estimatesimulated.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/templates_estimatesimulated.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/templates_estimatesimulated.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/templates_estimatesimulated.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/templates_estsearchresult.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/templates_estsearchresult.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/templates_estsearchresult.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/templates_estsearchresult.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/templates_estsearchresultbayes.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/templates_estsearchresultbayes.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/templates_estsearchresultbayes.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/templates_estsearchresultbayes.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/templates_estsearchresultsem.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/templates_estsearchresultsem.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/templates_estsearchresultsem.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/templates_estsearchresultsem.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/templates_searchfromdata.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/templates_searchfromdata.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/templates_searchfromdata.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/templates_searchfromdata.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/templates_searchsimcomp.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/templates_searchsimcomp.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/templates_searchsimcomp.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/templates_searchsimcomp.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/templates_searchsimulated.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/templates_searchsimulated.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/templates_searchsimulated.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/templates_searchsimulated.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/templates_simulatedata.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/templates_simulatedata.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/templates_simulatedata.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/templates_simulatedata.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/templates_updatebayesim.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/templates_updatebayesim.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/templates_updatebayesim.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/templates_updatebayesim.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/tetrad_menu1.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/tetrad_menu1.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/tetrad_menu1.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/tetrad_menu1.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/tetrad_menu1.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/tetrad_menu1.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/tetrad_menu1.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/tetrad_menu1.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/tetrad_menu2.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/tetrad_menu2.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/tetrad_menu2.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/tetrad_menu2.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/tetrad_menu3.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/tetrad_menu3.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/tetrad_menu3.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/tetrad_menu3.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/tetrad_menu4.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/tetrad_menu4.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/tetrad_menu4.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/tetrad_menu4.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/tetrad_menu5.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/tetrad_menu5.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/tetrad_menu5.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/tetrad_menu5.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/ucomsparesearchcopy.jpg b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/ucomsparesearchcopy.jpg similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/ucomsparesearchcopy.jpg rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/ucomsparesearchcopy.jpg diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/undirected_edge.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/undirected_edge.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/undirected_edge.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/undirected_edge.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/updater_button.gif b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/updater_button.gif similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/updater_button.gif rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/updater_button.gif diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/variables_schema.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/variables_schema.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/variables_schema.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/variables_schema.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/images/window_menu.png b/tetrad-lib/src/main/resources/docs/javahelp/manual/images/window_menu.png similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/images/window_menu.png rename to tetrad-lib/src/main/resources/docs/javahelp/manual/images/window_menu.png diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/main_workspace/how_to_build_a_session.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/main_workspace/how_to_build_a_session.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/main_workspace/how_to_build_a_session.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/main_workspace/how_to_build_a_session.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/main_workspace/main_workspace_explained.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/main_workspace/main_workspace_explained.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/main_workspace/main_workspace_explained.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/main_workspace/main_workspace_explained.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/main_workspace/tetrad_menubar.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/main_workspace/tetrad_menubar.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/main_workspace/tetrad_menubar.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/main_workspace/tetrad_menubar.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/main_workspace/tetrad_toolbar.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/main_workspace/tetrad_toolbar.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/main_workspace/tetrad_toolbar.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/main_workspace/tetrad_toolbar.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/main_workspace/tetrad_versioning.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/main_workspace/tetrad_versioning.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/main_workspace/tetrad_versioning.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/main_workspace/tetrad_versioning.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/manual.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/manual.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/manual.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/manual.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/references.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/references.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/references.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/references.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/tetrad_overview.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/tetrad_overview.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/tetrad_overview.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/tetrad_overview.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/tetrad_tutorial.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/tetrad_tutorial.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/tetrad_tutorial.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/tetrad_tutorial.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/under_construction.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/under_construction.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/under_construction.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/under_construction.html diff --git a/tetrad-gui/src/main/resources/resources/javahelp/manual/why_doesnt_tetrad.html b/tetrad-lib/src/main/resources/docs/javahelp/manual/why_doesnt_tetrad.html similarity index 100% rename from tetrad-gui/src/main/resources/resources/javahelp/manual/why_doesnt_tetrad.html rename to tetrad-lib/src/main/resources/docs/javahelp/manual/why_doesnt_tetrad.html diff --git a/docs/manual/README.md b/tetrad-lib/src/main/resources/docs/manual/README.md similarity index 98% rename from docs/manual/README.md rename to tetrad-lib/src/main/resources/docs/manual/README.md index 838958ff87..e985d9550e 100644 --- a/docs/manual/README.md +++ b/tetrad-lib/src/main/resources/docs/manual/README.md @@ -1,9 +1,9 @@ -# Tetrad Single-Page HTML Manual - -This `/docs/manual` folder is the home of the Tetrad HTML manual. The live version is published via the Github pages. -And the live URL is: http://cmu-phil.github.io/tetrad/manual/ - -## How to Edit - -If you are a team member and want to edit this HTML manual, just open the `index.html` with your favorite text editor +# Tetrad Single-Page HTML Manual + +This `/docs/manual` folder is the home of the Tetrad HTML manual. The live version is published via the Github pages. +And the live URL is: http://cmu-phil.github.io/tetrad/manual/ + +## How to Edit + +If you are a team member and want to edit this HTML manual, just open the `index.html` with your favorite text editor and search for the corresponding sections to make changes. All the embeded images are stored in the `/images` folder. \ No newline at end of file diff --git a/docs/manual/css/normalize.css b/tetrad-lib/src/main/resources/docs/manual/css/normalize.css similarity index 100% rename from docs/manual/css/normalize.css rename to tetrad-lib/src/main/resources/docs/manual/css/normalize.css diff --git a/docs/manual/css/tetrad.css b/tetrad-lib/src/main/resources/docs/manual/css/tetrad.css similarity index 100% rename from docs/manual/css/tetrad.css rename to tetrad-lib/src/main/resources/docs/manual/css/tetrad.css diff --git a/docs/manual/flowchart.html b/tetrad-lib/src/main/resources/docs/manual/flowchart.html similarity index 100% rename from docs/manual/flowchart.html rename to tetrad-lib/src/main/resources/docs/manual/flowchart.html diff --git a/docs/manual/images/appendix_figure_1a.png b/tetrad-lib/src/main/resources/docs/manual/images/appendix_figure_1a.png similarity index 100% rename from docs/manual/images/appendix_figure_1a.png rename to tetrad-lib/src/main/resources/docs/manual/images/appendix_figure_1a.png diff --git a/docs/manual/images/appendix_figure_1b.png b/tetrad-lib/src/main/resources/docs/manual/images/appendix_figure_1b.png similarity index 100% rename from docs/manual/images/appendix_figure_1b.png rename to tetrad-lib/src/main/resources/docs/manual/images/appendix_figure_1b.png diff --git a/docs/manual/images/appendix_figure_2.png b/tetrad-lib/src/main/resources/docs/manual/images/appendix_figure_2.png similarity index 100% rename from docs/manual/images/appendix_figure_2.png rename to tetrad-lib/src/main/resources/docs/manual/images/appendix_figure_2.png diff --git a/docs/manual/images/arc_specialization_1.png b/tetrad-lib/src/main/resources/docs/manual/images/arc_specialization_1.png similarity index 100% rename from docs/manual/images/arc_specialization_1.png rename to tetrad-lib/src/main/resources/docs/manual/images/arc_specialization_1.png diff --git a/docs/manual/images/arc_specialization_2.png b/tetrad-lib/src/main/resources/docs/manual/images/arc_specialization_2.png similarity index 100% rename from docs/manual/images/arc_specialization_2.png rename to tetrad-lib/src/main/resources/docs/manual/images/arc_specialization_2.png diff --git a/docs/manual/images/arc_specialization_3.png b/tetrad-lib/src/main/resources/docs/manual/images/arc_specialization_3.png similarity index 100% rename from docs/manual/images/arc_specialization_3.png rename to tetrad-lib/src/main/resources/docs/manual/images/arc_specialization_3.png diff --git a/docs/manual/images/classify_box_1.png b/tetrad-lib/src/main/resources/docs/manual/images/classify_box_1.png similarity index 100% rename from docs/manual/images/classify_box_1.png rename to tetrad-lib/src/main/resources/docs/manual/images/classify_box_1.png diff --git a/docs/manual/images/classify_box_2.png b/tetrad-lib/src/main/resources/docs/manual/images/classify_box_2.png similarity index 100% rename from docs/manual/images/classify_box_2.png rename to tetrad-lib/src/main/resources/docs/manual/images/classify_box_2.png diff --git a/docs/manual/images/classify_box_3.png b/tetrad-lib/src/main/resources/docs/manual/images/classify_box_3.png similarity index 100% rename from docs/manual/images/classify_box_3.png rename to tetrad-lib/src/main/resources/docs/manual/images/classify_box_3.png diff --git a/docs/manual/images/compare_box_1.png b/tetrad-lib/src/main/resources/docs/manual/images/compare_box_1.png similarity index 100% rename from docs/manual/images/compare_box_1.png rename to tetrad-lib/src/main/resources/docs/manual/images/compare_box_1.png diff --git a/docs/manual/images/compare_box_10.png b/tetrad-lib/src/main/resources/docs/manual/images/compare_box_10.png similarity index 100% rename from docs/manual/images/compare_box_10.png rename to tetrad-lib/src/main/resources/docs/manual/images/compare_box_10.png diff --git a/docs/manual/images/compare_box_11.png b/tetrad-lib/src/main/resources/docs/manual/images/compare_box_11.png similarity index 100% rename from docs/manual/images/compare_box_11.png rename to tetrad-lib/src/main/resources/docs/manual/images/compare_box_11.png diff --git a/docs/manual/images/compare_box_12.png b/tetrad-lib/src/main/resources/docs/manual/images/compare_box_12.png similarity index 100% rename from docs/manual/images/compare_box_12.png rename to tetrad-lib/src/main/resources/docs/manual/images/compare_box_12.png diff --git a/docs/manual/images/compare_box_13.png b/tetrad-lib/src/main/resources/docs/manual/images/compare_box_13.png similarity index 100% rename from docs/manual/images/compare_box_13.png rename to tetrad-lib/src/main/resources/docs/manual/images/compare_box_13.png diff --git a/docs/manual/images/compare_box_3.png b/tetrad-lib/src/main/resources/docs/manual/images/compare_box_3.png similarity index 100% rename from docs/manual/images/compare_box_3.png rename to tetrad-lib/src/main/resources/docs/manual/images/compare_box_3.png diff --git a/docs/manual/images/compare_box_4.png b/tetrad-lib/src/main/resources/docs/manual/images/compare_box_4.png similarity index 100% rename from docs/manual/images/compare_box_4.png rename to tetrad-lib/src/main/resources/docs/manual/images/compare_box_4.png diff --git a/docs/manual/images/compare_box_5.png b/tetrad-lib/src/main/resources/docs/manual/images/compare_box_5.png similarity index 100% rename from docs/manual/images/compare_box_5.png rename to tetrad-lib/src/main/resources/docs/manual/images/compare_box_5.png diff --git a/docs/manual/images/compare_box_6.png b/tetrad-lib/src/main/resources/docs/manual/images/compare_box_6.png similarity index 100% rename from docs/manual/images/compare_box_6.png rename to tetrad-lib/src/main/resources/docs/manual/images/compare_box_6.png diff --git a/docs/manual/images/compare_box_7.png b/tetrad-lib/src/main/resources/docs/manual/images/compare_box_7.png similarity index 100% rename from docs/manual/images/compare_box_7.png rename to tetrad-lib/src/main/resources/docs/manual/images/compare_box_7.png diff --git a/docs/manual/images/compare_box_8.png b/tetrad-lib/src/main/resources/docs/manual/images/compare_box_8.png similarity index 100% rename from docs/manual/images/compare_box_8.png rename to tetrad-lib/src/main/resources/docs/manual/images/compare_box_8.png diff --git a/docs/manual/images/compare_box_9.png b/tetrad-lib/src/main/resources/docs/manual/images/compare_box_9.png similarity index 100% rename from docs/manual/images/compare_box_9.png rename to tetrad-lib/src/main/resources/docs/manual/images/compare_box_9.png diff --git a/docs/manual/images/data_box_1.png b/tetrad-lib/src/main/resources/docs/manual/images/data_box_1.png similarity index 100% rename from docs/manual/images/data_box_1.png rename to tetrad-lib/src/main/resources/docs/manual/images/data_box_1.png diff --git a/docs/manual/images/data_box_10.png b/tetrad-lib/src/main/resources/docs/manual/images/data_box_10.png similarity index 100% rename from docs/manual/images/data_box_10.png rename to tetrad-lib/src/main/resources/docs/manual/images/data_box_10.png diff --git a/docs/manual/images/data_box_2.png b/tetrad-lib/src/main/resources/docs/manual/images/data_box_2.png similarity index 100% rename from docs/manual/images/data_box_2.png rename to tetrad-lib/src/main/resources/docs/manual/images/data_box_2.png diff --git a/docs/manual/images/data_box_3.png b/tetrad-lib/src/main/resources/docs/manual/images/data_box_3.png similarity index 100% rename from docs/manual/images/data_box_3.png rename to tetrad-lib/src/main/resources/docs/manual/images/data_box_3.png diff --git a/docs/manual/images/data_box_4.png b/tetrad-lib/src/main/resources/docs/manual/images/data_box_4.png similarity index 100% rename from docs/manual/images/data_box_4.png rename to tetrad-lib/src/main/resources/docs/manual/images/data_box_4.png diff --git a/docs/manual/images/data_box_5.png b/tetrad-lib/src/main/resources/docs/manual/images/data_box_5.png similarity index 100% rename from docs/manual/images/data_box_5.png rename to tetrad-lib/src/main/resources/docs/manual/images/data_box_5.png diff --git a/docs/manual/images/data_box_6.png b/tetrad-lib/src/main/resources/docs/manual/images/data_box_6.png similarity index 100% rename from docs/manual/images/data_box_6.png rename to tetrad-lib/src/main/resources/docs/manual/images/data_box_6.png diff --git a/docs/manual/images/data_box_7.png b/tetrad-lib/src/main/resources/docs/manual/images/data_box_7.png similarity index 100% rename from docs/manual/images/data_box_7.png rename to tetrad-lib/src/main/resources/docs/manual/images/data_box_7.png diff --git a/docs/manual/images/data_box_8.png b/tetrad-lib/src/main/resources/docs/manual/images/data_box_8.png similarity index 100% rename from docs/manual/images/data_box_8.png rename to tetrad-lib/src/main/resources/docs/manual/images/data_box_8.png diff --git a/docs/manual/images/data_box_8a.png b/tetrad-lib/src/main/resources/docs/manual/images/data_box_8a.png similarity index 100% rename from docs/manual/images/data_box_8a.png rename to tetrad-lib/src/main/resources/docs/manual/images/data_box_8a.png diff --git a/docs/manual/images/data_box_8b.png b/tetrad-lib/src/main/resources/docs/manual/images/data_box_8b.png similarity index 100% rename from docs/manual/images/data_box_8b.png rename to tetrad-lib/src/main/resources/docs/manual/images/data_box_8b.png diff --git a/docs/manual/images/data_box_9.png b/tetrad-lib/src/main/resources/docs/manual/images/data_box_9.png similarity index 100% rename from docs/manual/images/data_box_9.png rename to tetrad-lib/src/main/resources/docs/manual/images/data_box_9.png diff --git a/docs/manual/images/estimator_box_1.png b/tetrad-lib/src/main/resources/docs/manual/images/estimator_box_1.png similarity index 100% rename from docs/manual/images/estimator_box_1.png rename to tetrad-lib/src/main/resources/docs/manual/images/estimator_box_1.png diff --git a/docs/manual/images/estimator_box_2.png b/tetrad-lib/src/main/resources/docs/manual/images/estimator_box_2.png similarity index 100% rename from docs/manual/images/estimator_box_2.png rename to tetrad-lib/src/main/resources/docs/manual/images/estimator_box_2.png diff --git a/docs/manual/images/flowchart.pdf b/tetrad-lib/src/main/resources/docs/manual/images/flowchart.pdf similarity index 100% rename from docs/manual/images/flowchart.pdf rename to tetrad-lib/src/main/resources/docs/manual/images/flowchart.pdf diff --git a/docs/manual/images/flowchart.pptx b/tetrad-lib/src/main/resources/docs/manual/images/flowchart.pptx similarity index 100% rename from docs/manual/images/flowchart.pptx rename to tetrad-lib/src/main/resources/docs/manual/images/flowchart.pptx diff --git a/docs/manual/images/flowchart/Slide1.png b/tetrad-lib/src/main/resources/docs/manual/images/flowchart/Slide1.png similarity index 100% rename from docs/manual/images/flowchart/Slide1.png rename to tetrad-lib/src/main/resources/docs/manual/images/flowchart/Slide1.png diff --git a/docs/manual/images/flowchart/Slide2.png b/tetrad-lib/src/main/resources/docs/manual/images/flowchart/Slide2.png similarity index 100% rename from docs/manual/images/flowchart/Slide2.png rename to tetrad-lib/src/main/resources/docs/manual/images/flowchart/Slide2.png diff --git a/docs/manual/images/instantiated_model_box_1.png b/tetrad-lib/src/main/resources/docs/manual/images/instantiated_model_box_1.png similarity index 100% rename from docs/manual/images/instantiated_model_box_1.png rename to tetrad-lib/src/main/resources/docs/manual/images/instantiated_model_box_1.png diff --git a/docs/manual/images/instantiated_model_box_10.png b/tetrad-lib/src/main/resources/docs/manual/images/instantiated_model_box_10.png similarity index 100% rename from docs/manual/images/instantiated_model_box_10.png rename to tetrad-lib/src/main/resources/docs/manual/images/instantiated_model_box_10.png diff --git a/docs/manual/images/instantiated_model_box_11.png b/tetrad-lib/src/main/resources/docs/manual/images/instantiated_model_box_11.png similarity index 100% rename from docs/manual/images/instantiated_model_box_11.png rename to tetrad-lib/src/main/resources/docs/manual/images/instantiated_model_box_11.png diff --git a/docs/manual/images/instantiated_model_box_12.png b/tetrad-lib/src/main/resources/docs/manual/images/instantiated_model_box_12.png similarity index 100% rename from docs/manual/images/instantiated_model_box_12.png rename to tetrad-lib/src/main/resources/docs/manual/images/instantiated_model_box_12.png diff --git a/docs/manual/images/instantiated_model_box_13.png b/tetrad-lib/src/main/resources/docs/manual/images/instantiated_model_box_13.png similarity index 100% rename from docs/manual/images/instantiated_model_box_13.png rename to tetrad-lib/src/main/resources/docs/manual/images/instantiated_model_box_13.png diff --git a/docs/manual/images/instantiated_model_box_14.png b/tetrad-lib/src/main/resources/docs/manual/images/instantiated_model_box_14.png similarity index 100% rename from docs/manual/images/instantiated_model_box_14.png rename to tetrad-lib/src/main/resources/docs/manual/images/instantiated_model_box_14.png diff --git a/docs/manual/images/instantiated_model_box_2.png b/tetrad-lib/src/main/resources/docs/manual/images/instantiated_model_box_2.png similarity index 100% rename from docs/manual/images/instantiated_model_box_2.png rename to tetrad-lib/src/main/resources/docs/manual/images/instantiated_model_box_2.png diff --git a/docs/manual/images/instantiated_model_box_3.png b/tetrad-lib/src/main/resources/docs/manual/images/instantiated_model_box_3.png similarity index 100% rename from docs/manual/images/instantiated_model_box_3.png rename to tetrad-lib/src/main/resources/docs/manual/images/instantiated_model_box_3.png diff --git a/docs/manual/images/instantiated_model_box_4.png b/tetrad-lib/src/main/resources/docs/manual/images/instantiated_model_box_4.png similarity index 100% rename from docs/manual/images/instantiated_model_box_4.png rename to tetrad-lib/src/main/resources/docs/manual/images/instantiated_model_box_4.png diff --git a/docs/manual/images/instantiated_model_box_5.png b/tetrad-lib/src/main/resources/docs/manual/images/instantiated_model_box_5.png similarity index 100% rename from docs/manual/images/instantiated_model_box_5.png rename to tetrad-lib/src/main/resources/docs/manual/images/instantiated_model_box_5.png diff --git a/docs/manual/images/instantiated_model_box_6.png b/tetrad-lib/src/main/resources/docs/manual/images/instantiated_model_box_6.png similarity index 100% rename from docs/manual/images/instantiated_model_box_6.png rename to tetrad-lib/src/main/resources/docs/manual/images/instantiated_model_box_6.png diff --git a/docs/manual/images/instantiated_model_box_7.png b/tetrad-lib/src/main/resources/docs/manual/images/instantiated_model_box_7.png similarity index 100% rename from docs/manual/images/instantiated_model_box_7.png rename to tetrad-lib/src/main/resources/docs/manual/images/instantiated_model_box_7.png diff --git a/docs/manual/images/instantiated_model_box_8.png b/tetrad-lib/src/main/resources/docs/manual/images/instantiated_model_box_8.png similarity index 100% rename from docs/manual/images/instantiated_model_box_8.png rename to tetrad-lib/src/main/resources/docs/manual/images/instantiated_model_box_8.png diff --git a/docs/manual/images/instantiated_model_box_9.png b/tetrad-lib/src/main/resources/docs/manual/images/instantiated_model_box_9.png similarity index 100% rename from docs/manual/images/instantiated_model_box_9.png rename to tetrad-lib/src/main/resources/docs/manual/images/instantiated_model_box_9.png diff --git a/docs/manual/images/knowledge_box_1.png b/tetrad-lib/src/main/resources/docs/manual/images/knowledge_box_1.png similarity index 100% rename from docs/manual/images/knowledge_box_1.png rename to tetrad-lib/src/main/resources/docs/manual/images/knowledge_box_1.png diff --git a/docs/manual/images/knowledge_box_2.png b/tetrad-lib/src/main/resources/docs/manual/images/knowledge_box_2.png similarity index 100% rename from docs/manual/images/knowledge_box_2.png rename to tetrad-lib/src/main/resources/docs/manual/images/knowledge_box_2.png diff --git a/docs/manual/images/knowledge_box_3.png b/tetrad-lib/src/main/resources/docs/manual/images/knowledge_box_3.png similarity index 100% rename from docs/manual/images/knowledge_box_3.png rename to tetrad-lib/src/main/resources/docs/manual/images/knowledge_box_3.png diff --git a/docs/manual/images/knowledge_box_4.png b/tetrad-lib/src/main/resources/docs/manual/images/knowledge_box_4.png similarity index 100% rename from docs/manual/images/knowledge_box_4.png rename to tetrad-lib/src/main/resources/docs/manual/images/knowledge_box_4.png diff --git a/docs/manual/images/parametric_model_box_1.png b/tetrad-lib/src/main/resources/docs/manual/images/parametric_model_box_1.png similarity index 100% rename from docs/manual/images/parametric_model_box_1.png rename to tetrad-lib/src/main/resources/docs/manual/images/parametric_model_box_1.png diff --git a/docs/manual/images/parametric_model_box_2.png b/tetrad-lib/src/main/resources/docs/manual/images/parametric_model_box_2.png similarity index 100% rename from docs/manual/images/parametric_model_box_2.png rename to tetrad-lib/src/main/resources/docs/manual/images/parametric_model_box_2.png diff --git a/docs/manual/images/parametric_model_box_3.png b/tetrad-lib/src/main/resources/docs/manual/images/parametric_model_box_3.png similarity index 100% rename from docs/manual/images/parametric_model_box_3.png rename to tetrad-lib/src/main/resources/docs/manual/images/parametric_model_box_3.png diff --git a/docs/manual/images/parametric_model_box_4.png b/tetrad-lib/src/main/resources/docs/manual/images/parametric_model_box_4.png similarity index 100% rename from docs/manual/images/parametric_model_box_4.png rename to tetrad-lib/src/main/resources/docs/manual/images/parametric_model_box_4.png diff --git a/docs/manual/images/parametric_model_box_5.png b/tetrad-lib/src/main/resources/docs/manual/images/parametric_model_box_5.png similarity index 100% rename from docs/manual/images/parametric_model_box_5.png rename to tetrad-lib/src/main/resources/docs/manual/images/parametric_model_box_5.png diff --git a/docs/manual/images/parametric_model_box_6.png b/tetrad-lib/src/main/resources/docs/manual/images/parametric_model_box_6.png similarity index 100% rename from docs/manual/images/parametric_model_box_6.png rename to tetrad-lib/src/main/resources/docs/manual/images/parametric_model_box_6.png diff --git a/docs/manual/images/parametric_model_box_7.png b/tetrad-lib/src/main/resources/docs/manual/images/parametric_model_box_7.png similarity index 100% rename from docs/manual/images/parametric_model_box_7.png rename to tetrad-lib/src/main/resources/docs/manual/images/parametric_model_box_7.png diff --git a/docs/manual/images/parametric_model_box_8.png b/tetrad-lib/src/main/resources/docs/manual/images/parametric_model_box_8.png similarity index 100% rename from docs/manual/images/parametric_model_box_8.png rename to tetrad-lib/src/main/resources/docs/manual/images/parametric_model_box_8.png diff --git a/docs/manual/images/regression_box_1.png b/tetrad-lib/src/main/resources/docs/manual/images/regression_box_1.png similarity index 100% rename from docs/manual/images/regression_box_1.png rename to tetrad-lib/src/main/resources/docs/manual/images/regression_box_1.png diff --git a/docs/manual/images/regression_box_2.png b/tetrad-lib/src/main/resources/docs/manual/images/regression_box_2.png similarity index 100% rename from docs/manual/images/regression_box_2.png rename to tetrad-lib/src/main/resources/docs/manual/images/regression_box_2.png diff --git a/docs/manual/images/regression_box_3.png b/tetrad-lib/src/main/resources/docs/manual/images/regression_box_3.png similarity index 100% rename from docs/manual/images/regression_box_3.png rename to tetrad-lib/src/main/resources/docs/manual/images/regression_box_3.png diff --git a/docs/manual/images/search_box_1.png b/tetrad-lib/src/main/resources/docs/manual/images/search_box_1.png similarity index 100% rename from docs/manual/images/search_box_1.png rename to tetrad-lib/src/main/resources/docs/manual/images/search_box_1.png diff --git a/docs/manual/images/simulation_box_1.png b/tetrad-lib/src/main/resources/docs/manual/images/simulation_box_1.png similarity index 100% rename from docs/manual/images/simulation_box_1.png rename to tetrad-lib/src/main/resources/docs/manual/images/simulation_box_1.png diff --git a/docs/manual/images/updater_box_1.png b/tetrad-lib/src/main/resources/docs/manual/images/updater_box_1.png similarity index 100% rename from docs/manual/images/updater_box_1.png rename to tetrad-lib/src/main/resources/docs/manual/images/updater_box_1.png diff --git a/docs/manual/images/updater_box_10.png b/tetrad-lib/src/main/resources/docs/manual/images/updater_box_10.png similarity index 100% rename from docs/manual/images/updater_box_10.png rename to tetrad-lib/src/main/resources/docs/manual/images/updater_box_10.png diff --git a/docs/manual/images/updater_box_2.png b/tetrad-lib/src/main/resources/docs/manual/images/updater_box_2.png similarity index 100% rename from docs/manual/images/updater_box_2.png rename to tetrad-lib/src/main/resources/docs/manual/images/updater_box_2.png diff --git a/docs/manual/images/updater_box_3.png b/tetrad-lib/src/main/resources/docs/manual/images/updater_box_3.png similarity index 100% rename from docs/manual/images/updater_box_3.png rename to tetrad-lib/src/main/resources/docs/manual/images/updater_box_3.png diff --git a/docs/manual/images/updater_box_4.png b/tetrad-lib/src/main/resources/docs/manual/images/updater_box_4.png similarity index 100% rename from docs/manual/images/updater_box_4.png rename to tetrad-lib/src/main/resources/docs/manual/images/updater_box_4.png diff --git a/docs/manual/images/updater_box_5.png b/tetrad-lib/src/main/resources/docs/manual/images/updater_box_5.png similarity index 100% rename from docs/manual/images/updater_box_5.png rename to tetrad-lib/src/main/resources/docs/manual/images/updater_box_5.png diff --git a/docs/manual/images/updater_box_6.png b/tetrad-lib/src/main/resources/docs/manual/images/updater_box_6.png similarity index 100% rename from docs/manual/images/updater_box_6.png rename to tetrad-lib/src/main/resources/docs/manual/images/updater_box_6.png diff --git a/docs/manual/images/updater_box_7.png b/tetrad-lib/src/main/resources/docs/manual/images/updater_box_7.png similarity index 100% rename from docs/manual/images/updater_box_7.png rename to tetrad-lib/src/main/resources/docs/manual/images/updater_box_7.png diff --git a/docs/manual/images/updater_box_8.png b/tetrad-lib/src/main/resources/docs/manual/images/updater_box_8.png similarity index 100% rename from docs/manual/images/updater_box_8.png rename to tetrad-lib/src/main/resources/docs/manual/images/updater_box_8.png diff --git a/docs/manual/images/updater_box_9.png b/tetrad-lib/src/main/resources/docs/manual/images/updater_box_9.png similarity index 100% rename from docs/manual/images/updater_box_9.png rename to tetrad-lib/src/main/resources/docs/manual/images/updater_box_9.png diff --git a/docs/manual/index.html b/tetrad-lib/src/main/resources/docs/manual/index.html similarity index 95% rename from docs/manual/index.html rename to tetrad-lib/src/main/resources/docs/manual/index.html index 4521501ef5..45e483602a 100755 --- a/docs/manual/index.html +++ b/tetrad-lib/src/main/resources/docs/manual/index.html @@ -1,26 +1,21 @@ - + Tetrad Single HTML Manual - + - +

Tetrad Manual

-

Last updated: 02/09/2023

+

Last updated: 1/14/2024

@@ -69,7 +50,7 @@
  • Loading an existing data set, restricting - potential models using your a priori causal knowledge, and searching for + potential models using your a-priori causal knowledge, and searching for a model that explains it using one of Tetrad’s causal search algorithms
  • Loading an existing causal graph and existing data set, and @@ -98,7 +79,7 @@

    In order to use a box, click on it in the sidebar, then click inside the workspace. This creates an empty box, which you can - instantiated by double-clicking. Most boxes have multiple options + be instantiated by double-clicking. Most boxes have multiple options available on instantiation, which will be explained in further detail in this manual.

    @@ -106,6 +87,8 @@ them by clicking on the arrow tool in the sidebar, and clicking and dragging from the first box to the second in the workspace.

    +

    Starting 1/14/2024, we will compile Tetrad under JDK 17 and use language level 17.

    +

    Tetrad may be cited using the following reference: Ramsey, J. D., Zhang, K., Glymour, M., Romero, R. S., Huang, B., Ebert-Uphoff, I., ... & Glymour, C. (2018). TETRAD—A toolbox for causal discovery. In 8th @@ -117,10 +100,8 @@

    Graph

    The graph box can be used to create a new graph, or to copy or edit a graph from another box.

    -

    Possible - Parent Boxes of the Graph Box

    +

    Possible Parent Boxes of the Graph Box

    -
    • Another graph box
    • A parametric model box
    • @@ -131,10 +112,10 @@

      Graph
    • A search box
    • An updater box
    • A regression box
    • -

    Possible Child Boxes of the Graph Box

    +

+ +

Possible Child Boxes of the Graph Box

-
  • Another graph box
  • A compare box
  • @@ -206,7 +187,6 @@

    Creating a Random Graph

    Random graph generation is not available for time lag graphs.

    -

    Loading a Saved Graph

    If you have previously saved a graph from Tetrad, you can load it @@ -231,20 +211,7 @@

    Copying a Graph

    new graph box in the workspace, and draw an arrow from the box whose graph you want to copy to the new graph box. When opened, the new graph box will automatically contain a direct copy of the graph its parent box - contains.

    - - - - + contains.

    Manipulating a Graph

    @@ -400,13 +367,13 @@

    Edges and Edge Type Frequencies

    At the bottom of the graph box, the Edges and Edge Type Frequencies section provides an accounting of every edge in the graph, and how certain Tetrad is of its type. The first three columns contain a - list, in text form, of all of the edges in the graph. The columns to the + list, in text form, of all the edges in the graph. The columns to the right are all blank in manually constructed graphs, user-loaded graphs, and graphs output by searches with default settings. They are only filled in for graphs that are output by searches performed with bootstrapping. In those cases, the fourth column will contain the percentage of bootstrap outputs in which the edge type between these two variables - matches the edge type in the final graph. All of the columns to the right + matches the edge type in the final graph. All the columns to the right contain the percentages of the bootstrap outputs that output each possible edge type.

    @@ -672,7 +639,7 @@

    Possible Child Boxes of the Parametric Model Box:

    Bayes Parametric Models

    A Bayes parametric model takes as input a DAG. Bayes PMs represent - causal structures in which all of the variables are categorical.

    + causal structures in which all the variables are categorical.

    Bayes PMs consist of three components: the graphical representation of the causal structure of the model; for each named @@ -711,7 +678,7 @@

    Bayes Parametric Models

    provided under the “Presets” tab on the right. If you choose one of these configurations, the number of categories associated with the current variable will automatically be changed to agree with the configuration - you have chosen. If you want all of the categories associated with a + you have chosen. If you want all the categories associated with a variable to have the same name with a number appended (e.g., x1, x2, x3), choose the “x1, x2, x3…” option under Presets.

    @@ -746,7 +713,7 @@

    SEM Parametric Models

    terms.

    To change a parameter’s name or starting value for estimation, - double click on the parameter in the window.

    + double-click on the parameter in the window.

    Generalized SEM Parametric Models

    @@ -785,11 +752,11 @@

    Generalized SEM Parametric Models

    in the IM box, a fixed value of each parameter will be selected according to the specified distribution.

    -

    To edit an expression or parameter, double click on it (in any +

    To edit an expression or parameter, double-click on it (in any tab). This will open up a window allowing you to change the function that defines the variable or distribution of the parameter.

    -

    For instance, if you double click on the expression next to X1 +

    For instance, if you double-click on the expression next to X1 (b1*X5+E_X1), the following window opens:

    @@ -834,7 +801,7 @@

    Generalized SEM Parametric Models

    product, with the dollar sign ($) functioning as a wild card. For example, in the image above, TSUM(NEW(b)*$) means that, for each parent variable of the variable in question, a new “b” will be created and - multiplied by the parent variable’s value, and then all of the products + multiplied by the parent variable’s value, and then all the products will be added together.

    @@ -909,15 +876,15 @@

    Bayes Instantiated Models

    on the variable in the graph or choose it from the drop-down menu on the right. You can manually set a given probability value by overwriting the text box. Be warned that changing the value in one cell will delete the - values in all of the other cells in the row. Since the values in any row - must sum to one, if all of the cells in a row but one are set, Tetrad + values in all the other cells in the row. Since the values in any row + must sum to one, if all the cells in a row but one are set, Tetrad will automatically change the value in the last cell to make the sum correct. For instance, in the above model, if you change the first row such that the probability that X5 = 0 is 0.5000 and the probability that X5 = 1 is 0.4000, the probability that X5 = 2 will automatically be set to 0.1000.

    -

    If you right click on a cell in the table (or two-finger click on +

    If you right-click on a cell in the table (or two-finger click on Macs), you can choose to randomize the probabilities in the row containing that cell, randomize the values in all incomplete rows in the table, randomize the entire table, or randomize the table of every @@ -952,7 +919,7 @@

    Dirichlet Instantiated Models

    three total (pseudo) data points in which X2=0 and X6=0. You can view the pseudocounts of any variable by clicking on it in the graph or choosing it from the drop-down menu at the top of the window. To edit the value of - a pseudocount, double click on it and overwrite it. The total count of a + a pseudocount, double-click on it and overwrite it. The total count of a row cannot be directly edited.

    From the pseudocounts, Tetrad determines the conditional @@ -997,9 +964,9 @@

    SEM Instantiated Models

    You can now manually edit the values of parameters in one of two - ways. Double clicking on the parameter in the graph will open up a small + ways. Double-clicking on the parameter in the graph will open up a small text box for you to overwrite. Or you can click on the Tabular Editor - tab, which will show all of the parameters in a table which you can edit. + tab, which will show all the parameters in a table which you can edit. The Tabular Editor tab of our SEM IM looks like this:

    @@ -1043,7 +1010,7 @@

    Standardized SEM Instantiated Models

    -

    To edit a parameter, double click on it. A slider will open at the +

    To edit a parameter, double-click on it. A slider will open at the bottom of the window (shown above for the edge parameter between X1 and X2). Click and drag the slider to change the value of the parameter, or enter the specific value you wish into the box. The value must stay @@ -1059,10 +1026,10 @@

    Standardized SEM Instantiated Models

    It is possible to make a SEM IM with a time lag graph, even with latent variables. This does not work for other types of models, such as - Bayes IM's or for mixed data (for which no IM is currently available-- + Bayes IMs or for mixed data (for which no IM is currently available-- though mixed data can be simulated in the Simulate box with an appropriate choice of simulation model). Standardization for time lag model - is not currently avialable.

    + is not currently available.

    The Implied Matrices tab works in the same way that it does in a normal SEM IM.

    @@ -1090,7 +1057,7 @@

    Generalized SEM Instantiated Models

    all variables and their formulae. You can change the cutoff point for long formulae by clicking Tools: Formula Cutoff.

    -

    If you double click on a formula in either the graph or the +

    If you double-click on a formula in either the graph or the Variables tab, you can change the value of the parameters in that formula.

    @@ -1144,8 +1111,8 @@

    Loading Data

    General Tabular Data

    -

    To load data, create a data box with no parent. When you double - click it, an empty data window will appear:

    +

    To load data, create a data box with no parent. When you double-click + it, an empty data window will appear:

    @@ -1185,7 +1152,7 @@

    General Tabular Data

    Metadata JSON File

    Metadata is optional in general data handling. But it can be very helpful if you want to overwrite the data - type of a given variable column. And the metadata MUST be a JSON file + type of given variable column. And the metadata MUST be a JSON file like the following example.

    @@ -1327,7 +1294,7 @@ 

    Handling Tabular Data with Interventional Variables

    `null`. The data type of each variable can either be discrete or continuous. We use a boolean flag to indicate the data type. From the above example, we only specified two domain variables in the metadata - JSON, any variables not specifed in the metadata will be treated as + JSON, any variables not specified in the metadata will be treated as domain variables.

    @@ -1401,10 +1368,10 @@

    Merge Deterministic Interventional Variables

    This option looks for pairs of interventional variables (currently only discrete variables) that are deterministic and merges them into one - combined variable. For domain variables that are fully determinised, + combined variable. For domain variables that are fully determined, we'll add an attribute to them. Later in the knowledge box (Edges and Tiers), all the interventional variables (both status and value - variables) and the fully-determinised domain variables will be + variables) and the fully-determined domain variables will be automatically put to top tier. And all other domain variables will be placed in the second tier.

    @@ -1488,7 +1455,7 @@

    Nonparanormal Transform

    Takes a continuous tabular data set and increases its Gaussianity, using a nonparanormal transformation to smooth the variables. (Note: This - operation increases only marginal Gaussanity, not the joint, and in + operation increases only marginal Gaussianity, not the joint, and in linear systems may eliminate information about higher moments that can aid in non-Gaussian orientation procedures.)

    @@ -1496,7 +1463,7 @@

    Convert to Residuals

    The input for this operation is a directed acyclic graph (DAG) and a data set. Tetrad performs a linear regression on each variable in the - data set with respect to all of the variables that the graph shows to be + data set with respect to all the variables that the graph shows to be its parents, and derives the error terms. The output data set contains only the error terms.

    @@ -1518,7 +1485,7 @@

    Replace Missing Values with Column Mode

    Replace Missing Values with Column Mean

    If you choose this operation, Tetrad will replace any missing - value markers with the average of all of the values in the column. + value markers with the average of all the values in the column. Replace Missing Values with Regression Predictions: If you choose this operation, Tetrad will perform a linear regression on the data in order to estimate the most likely value of any missing value.

    @@ -1633,7 +1600,7 @@

    Manually Editing Data

    cell contains the number 2) Tetrad will set every cell to the missing data marker.

    -

    Under the Tools tab, the Calculator tool allows you add and edit +

    Under the Tools tab, the Calculator tool allows you to add or edit relationships between variables in the graph. For more information on how the Calculator tool works, see “Manipulating Data” section above.

    @@ -1642,7 +1609,7 @@

    Data Information

    Under the Tools tab, there are options to view information about your data in several formats.

    -

    The Plot Matrix tool shows a grid of scatterplots and histograms for selected variables. +

    The Plot Matrix tool shows a grid of scatter plots and histograms for selected variables. This may be used for continuous, discrete, or mixtures of continuous and discrete data. To select which variables to include in the rows and columns of the grid, click the variable lists to the right of the tool. To select multiple variables in these lists, use the shift @@ -1662,7 +1629,7 @@

    Data Information

    Double-click on the magnified plot to return to the grid.

    The “Settings” menu contains some tools to control the output. One may add regression lines - to the scatterplots or select the number of bins to include in the histograms.

    + to the scatter plots or select the number of bins to include in the histograms.

    Finally, one may condition on ranges of variables or particular discrete values by selecting “Edit Conditioning Variables and Ranges.” This brings up a dialog that lets one @@ -1695,9 +1662,9 @@

    Estimator

    The estimator box takes as input a data box (or simulation box) and a parametric model box and estimates, tests, and outputs an - instantiated model for the data. With the exception of the EM Bayes + instantiated model for the data. Except for the EM Bayes estimator, Tetrad estimators do not accept missing values. If your data - set contains missing values, the missing values can interpolated or + set contains missing values, the missing values can be interpolated or removed using the data box. (Note that missing values are allowed in various Tetrad search procedures; see the section on the search box.)

    @@ -1739,7 +1706,8 @@

    ML Bayes Estimations

    The Model tab works exactly as it does in a Bayes instantiated model. The Model Statistics tab provides the p-value for a chi square test of the model, degrees of freedom, the chi square value, and the - Bayes Information Criterion (BIC) score of the model.

    + Bayes Information Criterion (BIC) score of the model. Note that BIC + is calculated as 2L -

    Dirichlet Estimations

    @@ -1784,13 +1752,13 @@

    SEM Estimates

    latent variables.

    Tetrad also provides two scores that can be used in estimation: - feasible generalized least squares (FGLS) and Full Information Maximum + feasible generalized the least squares (FGLS) and Full Information Maximum Likelihood (FML).

    If the graph for the SEM is a DAG, and we may assume that the SEM is linear with Gaussian error terms, we use multilinear regression to estimate coefficients and residual variances. Otherwise, we use a - standard maximum likelihoood fitting function (see Bollen, Structural + standard maximum likelihood fitting function (see Bollen, Structural Equations with Latent Variables, Wiley, 1989, pg. 107) to minimize the distance between (a) the covariance over the variables as implied by the coefficient and error covariance parameter values of the model and (b) @@ -1799,7 +1767,7 @@

    SEM Estimates

    minimized, yields the maximum likelihood estimation point in parameter space.

    -

    In either case, an Fml value may be obtained for the maximum +

    In either case, a Fml value may be obtained for the maximum likelihood point in parameter space, either by regression or by direct minimization of the Fml function itself. The value of Fml at this minimum (maximum likelihood) point, multiplied by N - 1 (where N is the sample @@ -1811,7 +1779,7 @@

    SEM Estimates

    coefficient parameters plus the number of covariance parameters. (Note that the degrees of freedom many be negative, in which case estimation should not be done.) The BIC score is calculated as ch^2 - dof * - log(N).

    + log(N), so "higher is better.".

    You can change which score optimizer Tetrad uses by choosing them from the drop-down menus at the bottom of the window and clicking @@ -1824,27 +1792,18 @@

    SEM Estimates

    values of the estimation.

    The Model Statistics tab provides the degrees of freedom, chi - square, p value, comparative fit index (CFI), root mean square error of + square, p value, comparative fit index (CFI), root-mean-square error of approximation (RMSEA) and BIC score of a test of the model. It should be noted that while these test statistics are standard, they are not in general correct. See Mathias Drton, 2009, Likelihood ratio tests and singularities. Annals of Statistics 37(2):979-1012. - arXiv:math.ST/0703360.

    + arXiv:math.ST/0703360. Note also that BIC is calculated as 2L - k ln N, + so "higher is better."

    When the EM algorithm is used with latent variable models, we recommend multiple random restarts. The number of restarts can be set in the lower right hand corner of the Estimator Box. -

    - - - -

    Generalized Estimator

    A generalized graphical model may have non-linear relations and @@ -2003,18 +1962,10 @@

    Row Summing Exact Updater

    see conditional as well as marginal probabilities, and in “Single Variable” mode, you can see joint values.

    - - - - - - - -

    Junction Tree Exact Updater

    -

    The Junction Tree exact updater is a another exact learning - algroithm. Its window functions exactly as the approximate updater down, +

    The Junction Tree exact updater is another exact learning + algorithm. Its window functions exactly as the approximate updater down, with one exception: in “Multiple Variables” mode, you can see conditional as well as marginal probabilities.

    @@ -2043,66 +1994,6 @@

    SEM Updater

    The rest of the window has the same functionality as a SEM instantiated model window, except as noted above.

    - - - -

    Knowledge Box

    @@ -2142,7 +2033,7 @@

    Tiers

    -

    Tiers separate your variables into a time line. Variables in +

    Tiers separate your variables into a timeline. Variables in higher-numbered tiers occur later than variables in lower-numbered tiers, which gives Tetrad information about causation. For example, a variable in Tier 3 could not possibly be a cause of a variable in Tier 1.

    @@ -2159,7 +2050,7 @@

    Tiers

    would find and select variables X1 and X10.

    You can also limit the search such that edges from one tier only - are added to the next immediate tier e.g,. if Tier 1 "Can cause only next + are added to the next immediate tier e.g., if Tier 1 "Can cause only next tier" is checked then edges from variables in Tier 1 to variables in Tier 3 are forbidden.

    @@ -2314,7 +2205,7 @@
    Random Forward DAG
    Erdos Renyi DAG
    -

    This option creates a DAG by randomly adding edgew with a given edge +

    This option creates a DAG by randomly adding edges with a given edge probability. The graph is then oriented as a DAG by choosing a causal order.

    @@ -2555,7 +2446,7 @@

    Using the Search Box

    Choosing the correct algorithm for your needs is an important consideration. Tetrad provides over 30 search algorithms (and more are - added all of the time) each of which makes different assumptions about + added all the time) each of which makes different assumptions about the input data, uses different parameters, and produces different kinds of output. For instance, some algorithms produce Markov blankets or CPDAGs, and some produce full graphs; some algorithms work best with @@ -2600,10 +2491,10 @@

    Description

    sample should ideally be i.i.d.. Simulations show that PC and several of the other algorithms described here often succeed when these assumptions, needed to prove their correctness, do not strictly hold. - The PC algorithm will sometimes output double headed edges. In the - large sample limit, double headed edges in the output indicate that + The PC algorithm will sometimes output double-headed edges. In the + large sample limit, double-headed edges in the output indicate that the adjacent variables have an unrecorded common cause, but PC tends - to produce false positive double headed edges on small samples.

    + to produce false positive double-headed edges on small samples.

    The PC algorithm is correct whenever decision procedures for independence and conditional independence are available. The @@ -2621,7 +2512,7 @@

    Description

    and Search for details on tests). In either case, the tests require an alpha value for rejecting the null hypothesis, which can be adjusted by the user. The procedures make no adjustment for multiple - testing. (For PC, CPC, JPC, JCPC, FCI, all testing searches.)

    + testing. (For PC, CPC, FCI, all testing searches.)

    The PC algorithm as given in Causation, Prediction and Search (Spirtes, Glymour, and Scheines, 2000) comes with three heuristics designed @@ -2633,7 +2524,7 @@

    Description

    Causation, Prediction, and Search for more details for these heuristics.

    -

    Note: If one wants to analyze time series data using this algorithms, +

    Note: If one wants to analyze time series data using this algorithm, one may set the time lag parameter to a value greater than 0, which will automatically apply the time lag transform. The same goes for any algorithm that has this parameter available in the interface.

    @@ -2643,7 +2534,7 @@

    Description

    Input Assumptions

    The algorithm effectively takes conditional independence facts as - input. Thus it will work for any type of data for which a conditional + input. Thus, it will work for any type of data for which a conditional independence facts are known. In the interface, it will work for linear, Gaussian data (the Fisher Z test), discrete multinomial data the Chi Square test) and mixed multinomial/Gaussian data (the Conditional @@ -2653,12 +2544,12 @@

    Output Format

    The graph outputs a CPDAG. This is an equivalence class of directed acyclic graphs (DAGs). Each DAG in the equivalence class has all - of the adjacencies (and no more) of the CPDAG. Each oriented edge in the + the adjacencies (and no more) of the CPDAG. Each oriented edge in the CPDAG is so oriented in each of the DAG in the equivalence class. Unoriented edges in the equivalence class cannot be oriented by conditional independence facts. For example, if the model is X->Y->Z, the - output will be X—Y—Z. There are not collider in this model, so the - algorithm will not detect one. Since there are not colliders, the Meek + output will be X—Y—Z. There are no collider in this model, so the + algorithm will not detect one. Since there are no colliders, the Meek cannot orient additional edges. If the model were X<-Y<-Z, the output would also be X—Y—Z; this model is in the same equivalence class as X->Y->Z. The model X->Y<-Z would be its own equivalence class, since the @@ -2708,9 +2599,9 @@

    Description

    and Search for details on tests). In either case, the tests require an alpha value for rejecting the null hypothesis, which can be adjusted by the user. The procedures make no adjustment for multiple - testing. (For PC, CPC, JPC, JCPC, FCI, all testing searches.)

    + testing. (For PC, CPC, FCI, all testing searches.)

    -

    Note: If one wants to analyze time series data using this algorithms, +

    Note: If one wants to analyze time series data using this algorithm, one may set the time lag parameter to a value greater than 0, which will automatically apply the time lag transform. The same goes for any algorithm that has this parameter available in the interface.

    @@ -2756,7 +2647,7 @@

    Description

    or orient as a collider, arbitrarily. This guarantees that the resulting graph will be a CPDAG.

    -

    Note: If one wants to analyze time series data using this algorithms, +

    Note: If one wants to analyze time series data using this algorithm, one may set the time lag parameter to a value greater than 0, which will automatically apply the time lag transform. The same goes for any algorithm that has this parameter available in the interface.

    @@ -2788,7 +2679,7 @@

    Description

    developed by Meek [Meek, 1997] called the Greedy Equivalence Search (GES). The algorithm was further developed and studied by Chickering [Chickering, 2002]. GES is a Bayesian algorithm that heuristically - searches the space of CBNs and returns the model with highest + searches the space of CBNs and returns the model with the highest Bayesian score it finds. In particular, GES starts its search with the empty graph. It then performs a forward stepping search in which edges are added between nodes in order to increase the Bayesian @@ -2802,15 +2693,17 @@

    Description

    user-documentation-7_20_2016-sample-size.pdf">here. The reference is Ramsey et al., 2017.

    -

    The algorithms requires a decomposable score—that is, a score +

    The algorithm requires a decomposable score—that is, a score that for the entire DAG model is a sum of logged scores of each variables given its parents in the model. The algorithms can take all continuous data (using the SEM BIC score), all discrete data (using the BDeu score) or a mixture of continuous and discrete data (using the Conditional Gaussian score); these are all decomposable scores. + Note that in all case, BIC is calculated as 2L - k ln N, so "higher + is better."

    -

    Note: If one wants to analyze time series data using this algorithms, +

    Note: If one wants to analyze time series data using this algorithm, one may set the time lag parameter to a value greater than 0, which will automatically apply the time lag transform. The same goes for any algorithm that has this parameter available in the interface.

    @@ -2837,62 +2730,15 @@

    Output Format

    A CPDAG, same as PC.

    - -

    Parameters

    - -

    samplePrior, structurePrior, penaltyDiscount, symmetricFirstStep, faithfulnessAssumed, maxDegree, parallelized, - verbose meekVerbose

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    The IMaGES Algorithm

    - -

    Description

    -
    -

    Adjusts the selected score for FGES so +

    + Adjusts the selected score for FGES to allow for multiple datasets as input. The linear, Gaussian BIC scores for each data set are averaged at each step of the algorithm, producing a model for all data sets that assumes they have the same - graphical structure across dataset.

    + graphical structure across dataset. Note that BIC is calculated + as 2L - k ln N, so "higher is better."

    @@ -2907,7 +2753,7 @@

    Output Format

    Parameters

    -

    All of the parameters from FGES are available for IMaGES. +

    All the parameters from FGES are available for IMaGES. Additionally:

    numRuns, Description

    subset of the observed variables; any conditioning set that leads to the removal of an adjacency is stored. After the adjacency phase, the resulting undirected graph has the correct set of adjacencies, but - all of the edges are unoriented. FCI then enters an orientation phase + all the edges are unoriented. FCI then enters an orientation phase that uses the stored conditioning sets that led to the removal of adjacencies to orient as many of the edges as possible. See [Spirtes, 1993].

    -

    Note: If one wants to analyze time series data using this algorithms, +

    Note: If one wants to analyze time series data using this algorithm, one may set the time lag parameter to a value greater than 0, which will automatically apply the time lag transform. The same goes for any algorithm that has this parameter available in the interface.

    @@ -2957,7 +2803,7 @@

    Output Format

    Parameters

    -

    All of the parameters from FCI are below.

    +

    All the parameters from FCI are below.

    depth, maxPathLength, Description

    The FCI-Max algorithm simply changes the first collider orientation rule in FCI to use the PC-Max orientation.

    -

    Note: If one wants to analyze time series data using this algorithms, +

    Note: If one wants to analyze time series data using this algorithm, one may set the time lag parameter to a value greater than 0, which will automatically apply the time lag transform. The same goes for any algorithm that has this parameter available in the interface.

    @@ -2990,7 +2836,7 @@

    Output Format

    Parameters

    -

    All of the parameters from FCI are below.

    +

    All the parameters from FCI are below.

    depth, maxPathLength, Description slow in some steps) and is almost as informative. See Colombo et al., 2012.

    -

    Note: If one wants to analyze time series data using this algorithms, +

    Note: If one wants to analyze time series data using this algorithm, one may set the time lag parameter to a value greater than 0, which will automatically apply the time lag transform. The same goes for any algorithm that has this parameter available in the interface.

    @@ -3027,7 +2873,7 @@

    Output Format

    Parameters

    -

    All of the parameters from FCI are available for RFCI. +

    All the parameters from FCI are available for RFCI. Additionally:

    depth, Description

    A modification of the RFCI algorithm which does probabilistic bootstrap sampling with respect to the RFCI PAG output.For discrete data only. Parameters are: (a) Number of search probabilistic models, (b) boostrap - ensemble method to use (see bootstrapping), (c) maximimum size of + ensemble method to use (see bootstrapping), (c) maximum size of conditioning set (depth), (d) maximum length of any discriminating path (a property for RFCI). This must use the probabilistic test, which must be selected. Parameters for the probabilistic test are (d) independence cutoff threshold, default 0.5, (e) prior equivalent sample size, and (f) whether the cutoff in (d) is used in the independence test calculation; - if not, then a coin flip is used (probaility 0.5). + if not, then a coin flip is used (probability 0.5).

    @@ -3089,7 +2935,7 @@

    Description

    href="https://www.ccd.pitt.edu//wp-content/uploads/2018/10/GFCIc- overview-11_22_2016.pdf">here (continuous variables)
    .

    -

    Note: If one wants to analyze time series data using this algorithms, +

    Note: If one wants to analyze time series data using this algorithm, one may set the time lag parameter to a value greater than 0, which will automatically apply the time lag transform. The same goes for any algorithm that has this parameter available in the interface.

    @@ -3118,16 +2964,16 @@

    Description

    GRaSP-FCI is wrapper around the GRaSP algorithm that replaces - the FGES step in GFCI with the more accurate GRaSP algrorithm, which + the FGES step in GFCI with the more accurate GRaSP algorithm, which reasons by considering permutations of variables. The second collider - orienatation step in GFCI is also done using permutation reasoning, + orientation step in GFCI is also done using permutation reasoning, leaving the discriminating path rule as the only rule that requires a "raw" conditional independence judgment. Ultimately this independence judgment can be decided using the same scoring apparatus as the other - permutation steps, so ultimatly GRaSP-FCI can be treated as a scoring + permutation steps, so ultimately GRaSP-FCI can be treated as a scoring algorithm.

    -

    Note: If one wants to analyze time series data using this algorithms, +

    Note: If one wants to analyze time series data using this algorithm, one may set the time lag parameter to a value greater than 0, which will automatically apply the time lag transform. The same goes for any algorithm that has this parameter available in the interface.

    @@ -3154,7 +3000,7 @@

    Description

    SP-FCI is wrapper around the SP algorithm that replaces - the FGES step in GFCI with the more accurate SP algrorithm, which + the FGES step in GFCI with the more accurate SP algorithm, which reasons by considering permutations of variables. This uses the same method for wrapping SP with an FCI method similar to GFCI as GRaSP-FCI. The difference is that SP considers every permutation @@ -3162,7 +3008,7 @@

    Description

    can only be used for very small models, of up to about 8 or 9 variables, because of the super-exponential step of considering every permutation of the variables. The second collider - orienatation step in GFCI is done using permutation reasoning, + orientation step in GFCI is done using permutation reasoning, leaving the discriminating path rule as the only rule that requires a "raw" conditional independence judgment. Ultimately this independence judgment can be decided using the same scoring apparatus as the other @@ -3205,7 +3051,7 @@

    Description

    with the above naming convention. The new sample size will be the old sample size minus n.

    -

    Since this algorithms specifically requires time series data, +

    Since this algorithm specifically requires time series data, one must set the time lag parameter to a value greater than 0, which will automatically apply the time lag transform.

    @@ -3249,9 +3095,10 @@

    Description

    increases the BIC score, then also the edge between X1:1 and X2:1 is removed, and so on for additional lags if they exist. When some edge is removed as the result of a score increase, all similar (or - “homologous”) edges are also removed.

    + “homologous”) edges are also removed. Note that BIC is calculated + as 2L - k ln N, so "higher is better."

    -

    Since this algorithms specifically requires time series data, +

    Since this algorithm specifically requires time series data, one must set the time lag parameter to a value greater than 0, which will automatically apply the time lag transform.

    @@ -3332,7 +3179,7 @@

    Description

    targets. In the interface, just one target may be specified. See Ramsey et al., 2017 for details. In the general case, finding the graph over the Markov blanket variables of a target (including the - target) is far faster than finding the CPDAG for all of the + target) is far faster than finding the CPDAG for all the variables.

    @@ -3478,7 +3325,6 @@

    Parameters

    href="#graspNonSingularDepth">graspNonSingularDepth graspSingularDepth graspOrderedAlg graspUseVermaPearl verbose numStarts

    @@ -3509,7 +3355,7 @@

    Description

    graspNonsingularDepth - This controls the depth at which nonsingular tucks are explored.

    graspSingularDepth - - This controls the depth at which singlular tucks are considered. + - This controls the depth at which singular tucks are considered.

    numRestarts - By default 1; if > 1, additional random restarts are done, and the best of these results is returned. @@ -3517,9 +3363,9 @@

    Description

    to singular depth 0, nonsingular depth 0. ESP corresponds to singular depth > 0, nonsingular depth = 0. GRaSP corresponds to singular depth > 0, nonsingular depth > 0. In each case, an ordering option is available - to find best permutations from lower levels before proceeding to + to find the best permutations from lower levels before proceeding to higher levels. -

    The algorithms works by building DAGs given +

    The algorithm works by building DAGs given permutations in ways similar to those described in Raskutti and Uhler (ref?) and Solus et al. Two ways of building DAGs are considered, one independence-based, due to Raskutti and Uhler and a score-based @@ -3539,7 +3385,6 @@

    Description

    Raskutti, G., & Uhler, C. (2018). Learning directed acyclic graph models based on sparsest permutations. Stat, 7(1), -

    Solus, L., Wang, Y., Matejovicova, L., & Uhler, C. (2017). Consistency guarantees for permutation-based causal inference algorithms. arXiv @@ -3565,7 +3410,6 @@

    Parameters

    href="#graspNonSingularDepth">graspNonSingularDepth graspSingularDepth graspOrderedAlg graspUseVermaPearl verbose numStarts

    @@ -3580,7 +3424,7 @@

    Description

    generalizes and extends the GSP (Greedy Sparsest Permutation) algorithm. It has been tested to 1000 variables with an average degree of 20 and gives near perfect precisions and recalls for N = 10,000 (with - recall that drop to 0.9 for N = 1000). The algorithms works by building DAGs given + recall that drop to 0.9 for N = 1000). The algorithm works by building DAGs given permutations in ways similar to those described in Raskutti and Uhler (ref?) and Solus et al.

    The parameters are as @@ -3588,14 +3432,14 @@

    Description

    useBes - True if the final BES (Backward Equivalence Search) step is used from the GES (Greedy Equivalence Search) algorithm. This step is needed for correctness but for large models, since usually - nearly all edges are oriented in the CPDAG, it is heurically not needed.

    -

    numStarts - The number of times the algroithm should be re-run from different + nearly all edges are oriented in the CPDAG, it is heuristically not needed.

    +

    numStarts - The number of times the algorithm should be re-run from different random starting permutations. The model with the most optimal BIC score will be selected.

    allowInternalRandomness - If true, the algorithm allow the algorithm to use certain heuristic random steps. This can improve performance, but may make the algorithm non-deterministic.

    -

    timeLag - This creates a time-series model autimatically with a certain +

    timeLag - This creates a time-series model automatically with a certain number of lags.

    Knowledge of forbidden edges and required edges may be used with this algorithm. Also, knowledge of tiers may be used. If tiered knowledge is @@ -3632,38 +3476,10 @@

    Parameters

    href="#graspNonSingularDepth">graspNonSingularDepth graspSingularDepth graspOrderedAlg graspUseVermaPearl verbose numStarts

    - - - - - - - - - - - - - - - - - - - - - - -

    The BPC/Mimbuild Algorithm

    Description

    @@ -3686,7 +3502,7 @@

    Description

    matrix over the latent variables that are parents of the measures and use some algorithm such as PC or GES to estimate a CPDAG over the latents. The algorithm to run PC or GES on this covariance matrix is - called MimBuild (“MIM” is the the graph, Multiple Indicator Model; + called MimBuild (“MIM” is the graph, Multiple Indicator Model; “Build” means build). In this way, one may recover causal structure over the latents. The more measures one has for each latent, the better the result is, generally. The larger the sample size the @@ -3754,7 +3570,7 @@

    Description

    relevant tetrad constraints still hold. There are different ways of going about this. One could try to build one cluster up as far as possible, then remove all of those variables from the set, and try to - make a another cluster using the remaining variables (SAG, Seed and + make another cluster using the remaining variables (SAG, Seed and Grow). Or one can try in parallel to grow all possible clusters and then choose among the grown clusters using some criterion such as cluster size (GAP, Grow and Pick). In general, GAP is more accurate. @@ -3775,8 +3591,8 @@

    Description

    variables. The algorithm will in effect remove one measure in each impure pair from consideration. - Note that for FOFC, a test is done for each final cluster as - to whether the variables in teh cluster are all mutually + Note that for FOFC, a test is done for each final cluster to see + whether the variables in the cluster are all mutually dependent. In the interface, in order to see teh results of this test, one needs to open the logging window. See the Logging menu.

    @@ -3791,11 +3607,11 @@

    Description

    FTFC (Find Two Factor Clusters) is similar to FOFC, but instead of each cluster having one latent that is the parent of all - of the measure in the cluster, it instead has two such latents. So + the measure in the cluster, it instead has two such latents. So each measure has two latent parents; these are two “factors.” Similarly to FOFC, constraints are checked for, but in this case, the constraints must be sextad constraints, and more of them must be - satisfied for each pure cluster (see Kummerfelt et al., 2014). Thus, + satisfied for each pure cluster (see Kummerfeld et al., 2014). Thus, the number of measures in each cluster, once impure edges have been taken into account, must be at least six, preferably more.

    @@ -3844,7 +3660,7 @@

    Description

    Our implementation of LiNGAM has one parameter, penalty discount, used for the FGES adjacency search. The method as implemented does not scale much beyond 10 variables, because it is - checking every permutation of all of the variables (twice). The + checking every permutation of all the variables (twice). The implementation of ICA we use is FastIca (Hyvärinen et al., 2004).

    @@ -3855,7 +3671,7 @@

    Description

    Hyvärinen, A., Karhunen, J., & Oja, E. (2004). Independent component analysis (Vol. 46). John Wiley & Sons.

    -

    Direct LiNGAM is an implemention of said algorithms as specified in this reference:

    +

    Direct LiNGAM is an implementation of said algorithms as specified in this reference:

    Shimizu, S., Inazumi, T., Sogawa, Y., Hyvarinen, A., Kawahara, Y., Washio, T., ... & Hoyer, P. (2011). DirectLiNGAM: A direct method for learning a linear non-Gaussian structural equation model. Journal of @@ -3868,7 +3684,7 @@

    The FASK Algorithm

    Description

    -

    FASK learns a linear model in which all of the +

    FASK learns a linear model in which all the variables are skewed.

    The idea is as follows. First, FAS-stable is run on the data, @@ -3928,7 +3744,7 @@

    Description

    FASK-Vote is a metascript that learns a model from a list of datasets in a method similar to IMaGES (see). For adjacencies, it uses FAS-Stable with the voting-based score from IMaGES - used as a test (using all of the datasets, standardized), producing a + used as a test (using all the datasets, standardized), producing a single undirected graph G. It then orients each edge X--Y in G for each dataset using the FASK (see) left-right rule and orient X->Y if that rule orients X--Y as such in at least half of the datasets. The final graph is @@ -4023,7 +3839,7 @@

    Input Assumptions

    Output Format

    -

    Orients all of the edges in the input graph using the selected +

    Orients all the edges in the input graph using the selected score.

    Parameters

    @@ -4047,7 +3863,7 @@

    Description

    The procedure is best used, however, as a command line procedure, in py-causal, rpy-causal, or Causal Command. Upon running the algorithm (even in the interface), a directory of result files will be produced as - a record, including the dataset used, the possible causes and effects used, all of the CPDAGs used and + a record, including the dataset used, the possible causes and effects used, all the CPDAGs used and the tables of their IDA effects, and the CStaR output table itself.

    @@ -4062,8 +3878,8 @@

    Description

    If a directory already exists at the path, then any information available in path directory will be used to generate results in the path-.[n] directory.

    -

    Number of Subsamples. CStaR finds CPDAGs over subsampled data of size n / 2; this specifies how many - subsamples to use.

    +

    Number of Sub-samples. CStaR finds CPDAGs over sub-sampled data of size n / 2; this specifies how many + sub-samples to use.

    Minimum effect size. This allows a shorter table to be produced. It this is set to a value m > 0, then only records with PI > m will be displayed.

    @@ -4111,7 +3927,7 @@

    Input Assumptions

    Statistical Tests

    -

    All of the below tests do testwise deletion as a default way of +

    All the below tests do testwise deletion as a default way of dealing with missing values. For testwise deletion, if a test, say, I(X, Y | Z), is done, columns for X, Y, and Z are scanned for missing values. If any row occurs in which X, Y, or Z is missing, that row is deleted @@ -4138,11 +3954,6 @@

    BDeu Test

    subtracted, in that order. If the difference is negative, independence is inferred.

    -

    Parameters

    - -

    equivalentSamplelSize, structurePrior

    -

    Fisher Z Test

    Fisher Z judges independence if the @@ -4177,7 +3988,7 @@

    Generalized Information Criterion Scores

    based on the paper, Kim, Y., Kwon, S., & Choi, H. (2012). Consistent model selection criteria on high dimensions. The Journal 0of Machine Learning Research, 13(1), 1037-1057. One needs to select which lambda to use in place of the - usual lambda for the linear, Gaussian BIC score. An penalty discount parameter + usual lambda for the linear, Gaussian BIC score. A penalty discount parameter may also be specified, though this is by default for these scores equal to 1 (since the lambda choice is essentially picking a penalty discount for you). @@ -4188,6 +3999,7 @@

    MAG SEM BIC Test

    This gives a BIC score (used as a test here) for a Mixed Ancestral Graph (MAG). + Note that BIC is calculated as 2L - k ln N, so "higher is better."

    @@ -4220,7 +4032,7 @@

    Conditional Correlation Independence (CCI) Test

    to a (possibly nonlinear) function of its parents, plus some additive noise, where the noise may be arbitrarily distributed. That is, X = f(parent(X)) + E, where f is any function and E is noise however - distributed; the only requirement is that thre be the “+” in the formula + distributed; the only requirement is that there be the “+” in the formula separating the function from the noise. The noise can’t for instance, be multiplicative, e.g., X = f(parent(X)) x E. The goal of the method is to estimate whether X is independent of Y given variables Z, for some X, Y, @@ -4260,7 +4072,7 @@

    M-Separation Test

    property of graphs, not distributions. It's not really a test, but it can be used in place of a test of the true graph is known. This is a way to find out, for constraint-based algorithms, or even for some score-based - algorithms like FGES, what answer the algorithm would give if all of the + algorithms like FGES, what answer the algorithm would give if all the statistical decisions made are correct. Just draw an edge from the true graph to the algorithm--the m-separation option will appear, and you can then just run the search as usual. Note that D-Separation and M-separation @@ -4275,8 +4087,7 @@

    Discrete BIC Test

    directly, and this is penalized as is usual for a BIC score. The only surprising thing perhaps is that we use the formula BIC = 2L - k ln N, where L is the likelihood, k the number of parameters, and N the sample - size, instead of the usual L + k / 2 ln N. So higher BIC scores will - correspond to greater dependence. In the case of independence, the BIC + size, so "higher is better." In the case of independence, the BIC score will be negative, since the likelihood will be zero, and this will be penalized. The test yields a p-value; we simply use alpha - p as the score, where alpha is the cutoff for rejecting the null hypothesis of @@ -4320,7 +4131,7 @@

    Kernel Conditional Independence (KCI) Test

    Parameters

    alpha, kciUseAppromation, kciUseApproximation, kernelMultiplier, kciNumBootstraps, thresholdForNumEigenvalues, Conditional Gaussian Likelihood Ratio Test Gaussian conditional on each combination of values for the discrete variables, though it will work fairly well even if that assumption does not hold strictly. This test may be used with any constraint-based - algorithm (PC, FCI, etc.). See See Andrews, B., Ramsey, J., & Cooper, G. + algorithm (PC, FCI, etc.). See Andrews, B., Ramsey, J., & Cooper, G. F. (2018). Scoring Bayesian networks of mixed variables. International journal of data science and analytics, 6(1), 3-18.

    Degenerate Gaussian Likelihood Ratio Test may be used for the case where there is a mixture of discrete and - Gaussian variables. Calculates a a likelihood ratio based on likelihood + Gaussian variables. Calculates a likelihood ratio based on likelihood that is calculated using a conditional Gaussian assumption. See Andrews, B., Ramsey, J., & Cooper, G. F. (2019). Learning high-dimensional directed acyclic graphs with mixed data-types. Proceedings of machine @@ -4362,7 +4173,7 @@

    Resampling

    is available on the Set Parameters screen. When it is selected, the search will be performed multiple times on randomly selected subsets of the data, and the final output graph will be the result of a voting - procedure among all of the graphs. These subsets may be selected with + procedure among all the graphs. These subsets may be selected with replacement (bootstrapping) or without. There are also options for the user to set the size of the subset, and the number of resampling runs. The default number of resampling runs is zero, in which case no @@ -4396,12 +4207,12 @@

    Resampling

    there are three columns. These are to capture various types of --> edges that may be found in estimated PAGs--whether the --> edge is visible and/or definitely direct. For estimated CPDAGs, these three columns may be summed. - Similarly for <-- edges. + Similarly, for <-- edges.

    Scoring Functions

    -

    Like the tests, above, all of the below tests do testwise deletion +

    Like the tests, above, all the below tests do testwise deletion as a default way of dealing with missing values. For testwise deletion, if a score, say, score(X | Y, Z), is done, columns for X, Y, and Z are scanned for missing values. If any row occurs in which X, Y, or Z is @@ -4426,9 +4237,6 @@

    BDeu Score

    Parameters

    -

    equivalentSampleSize, samplePrior

    -

    Conditional Gaussian BIC Score

    Conditional Gaussian BIC Score may be @@ -4436,7 +4244,8 @@

    Conditional Gaussian BIC Score

    variables. Calculates a BIC score based on likelihood that is calculated using a conditional Gaussian assumption. See Andrews, B., Ramsey, J., & Cooper, G. F. (2018). Scoring Bayesian networks of mixed variables. - International journal of data science and analytics, 6(1), 3-18.

    + International journal of data science and analytics, 6(1), 3-18. + Note that BIC is calculated as 2L - k ln N, so "higher is better."

    Parameters

    @@ -4449,32 +4258,14 @@

    Parameters

    Calculates a BIC score based on likelihood that is calculated using a conditional Gaussian assumption. See Andrews, B., Ramsey, J., & Cooper, G. F. (2019). Learning high-dimensional directed acyclic graphs with - mixed data-types. Proceedings of machine learning research, 104, 4.

    + mixed data-types. Proceedings of machine learning research, 104, 4. + Note that BIC is calculated as 2L - k ln N, so "higher is better."

    Parameters

    structurePrior

    - - - - - - - - -

    M-separation Score

    This uses m-separation to make something @@ -4533,7 +4324,7 @@

    GIC Scores

    the paper, Kim, Y., Kwon, S., & Choi, H. (2012). Consistent model selection criteria on high dimensions. The Journal 0of Machine Learning Research, 13(1), 1037-1057. One needs to select which lambda to use in place of the - usual lambda for the linear, Gaussian BIC score. An penalty discount parameter + usual lambda for the linear, Gaussian BIC score. A penalty discount parameter may also be specified, though this is by default for these scores equal to 1 (since the lambda choice is essentially picking a penalty discount for you). @@ -4560,13 +4351,6 @@

    Zhang-Shen Bound Score

    - - - - - - -

    Search Parameters

    Zhang-Shen Bound Score

    Note: You must specify the "Value Type" of each parameter, and the value type must be one of the following: Integer, Long, Double, String, - Boolean.

    + Boolean.

    sampleStyle

    @@ -4822,7 +4605,7 @@

    alpha

    0.0)
  • Long Description: The cutoff, beyond which test results are judged as dependent, for a - statistical test of independence. Detaulf 0.05. Higher alpha yields a + statistical test of independence. Default 0.05. Higher alpha yields a sparser graph.
  • Default Value: 0.01
  • @@ -4970,7 +4753,7 @@

    coefLow

    id="coefLow_short_desc"> Low end of coefficient range (min = 0.0)
  • Long Description: - The parameter m1 for coefficents drawn from U(-m2, -m1) U U(m1, + The parameter m1 for coefficients drawn from U(-m2, -m1) U U(m1, m2).
  • Default Value: 0.0
  • @@ -5269,20 +5052,20 @@

    topBracket

numSubsamples

-
    -
  • Short Description: Number of - subsamples
  • + id="numSub-samples">numSub-samples +
      +
    • Short Description: Number of + sub-samples
    • Long Description: Number of subsamples
    • + id="numSub-samples_long_desc">Number of sub-samples
    • Default Value: 50
    • + id="numSub-samples_default_value">50
    • Lower Bound: - 1
    • + 1
    • Upper Bound: - 500000
    • + 500000
    • Value - Type: Integer
    • + Type: Integer

    covHigh

    @@ -5447,7 +5230,7 @@

    depth

    class="parameter_description_list">
  • Short Description: Threshold for judging a - regression of a variable onto its parents to be deternimistic (min = + regression of a variable onto its parents to be deterministic (min = 0.0)
  • Long Description: When regressing a child variable @@ -5509,7 +5292,7 @@

    discretize

  • Long Description: Yes if for the conditional Gaussian likelihood, when scoring X->D where X is continuous and D discrete, - one shoudl to simply discretize X for just those cases. If no, the + one should to simply discretize X for just those cases. If no, the integration will be exact.
  • Default Value: true
  • @@ -5531,7 +5314,7 @@

    discretize

  • Long Description: The generalized information criterion is defined with an information term that take a - Euclidean norm squares; the can be calculated directly.
  • + Euclidean norm squares; there can be calculated directly.
  • Default Value: false
  • Lower @@ -5837,7 +5620,7 @@

    faskDelta

    id="pcHeuristic">pcHeuristic
    • Short Description: - Heuristics in CPC to stabilize skeleton: 0 = None, 1 = Heuristic 1, 2 = Heuristic 2, 3 = Heuristic 3 + Heuristics to stabilize skeleton: 0 = None, 1 = Heuristic 1, 2 = Heuristic 2, 3 = Heuristic 3
    • Long Description: @@ -6248,6 +6031,32 @@

      ia

      id="includePositiveSkewsForBeta_value_type">Boolean
    +

    usePseudoinverse

    +
      +
    • Short Description: + Yes if the pseudoinverse should be used to avoid exceptions +
    • +
    • Long Description: + Yes if the pseudoinverse should be used in place of the regular + inverse in calculating residual variances to avoid singularity + exceptions +
    • +
    • Default Value: false
    • +
    • Lower Bound:
    • +
    • Upper + Bound:
    • +
    • Value + Type: Boolean
    • +
    +

    intervalBetweenRecordings

      ia
      • Short Description: Interval beween shocks (R. A. + id="intervalBetweenShocks_short_desc"> Interval between shocks (R. A. Fisher simulation model) (min = 1)
      • Long Description: This is a parameter for @@ -6417,25 +6226,25 @@

        kciEpsilon

      kciUseAppromation

      + id="kciUseApproximation">kciUseApproximation
      • Short Description: Use the approximate Gamma + id="kciUseApproximation_short_desc">Use the approximate Gamma approximation algorithm
      • Long Description: Referring to Zhang, K., Peters, J., + id="kciUseApproximation_long_desc"> Referring to Zhang, K., Peters, J., Janzing, D., & Schölkopf, B. (2012), if this parameter is set to ‘Yes’, the Gamma approximation algorithm is used; if no, the exact procedure is used.
      • Default Value: true
      • + id="kciUseApproximation_default_value">true
      • Lower - Bound:
      • + Bound:
      • Upper Bound:
      • + id="kciUseApproximation_upper_bound">
      • Value Type: Boolean
      • + id="kciUseApproximation_value_type">Boolean

      kciEpsilon

      class="parameter_description_list">
    • Short Description: Bowman and Azzalini (1997) default - kernel bandwidhts should be multiplied by...
    • + kernel bandwidths should be multiplied by...
    • Long Description: For the conditional correlation algorithm. Bowman, A. W., & Azzalini, A. @@ -6482,13 +6291,35 @@

      kciEpsilon

      id="kernelRegressionSampleSize_value_type">Integer
    +

    minCountPerCell

    +
      +
    • Short Description: + Minimum expected count per cell for nonempty Chi-Square tables. +
    • +
    • Long Description: + The minimum count per cell in any nonempty conditional Chi-Square table + This is real-valued and must be > 0.0; the default is 1.0. No matter + what this value is, if a row is empty, it will be removed from the + table.
    • +
    • Default Value: 1.0
    • +
    • Lower + Bound: 0.0
    • +
    • Upper Bound: Infinity
    • +
    • Value Type: + Double
    • +
    +

    kernelType

    • Short Description: Kernel type (1 = Gaussian, 2 = Epinechnikov)
    • Long Description: For CCI, this determine which kernel type + id="kernelType_long_desc"> For CCI, this determines which kernel type will be used (1 = Gaussian, 2 = Epinechnikov).
    • Default Value: 2
    • Lower Bound: 1
    • @@ -6682,7 +6513,7 @@

      zsMaxIndegree

      algorithm should go through orienting edges
    • Long Description: In orienting, this - algorith may go through a number of iterations, conditioning on more + algorithm may go through a number of iterations, conditioning on more and more variables until orientations are set. This sets that number.
    • Default Value: meanLow
    • Long Description: If the value is greater than zero, independent Gaussian noise will be added with mean zero and the - given variance to each variables in the simulated output. + given variance to each variable in the simulated output.
    • Default Value: 0.0
    • @@ -6986,7 +6817,7 @@

      mgmParam3

      • Short Description: Yes, if use the + id="noRandomlyDeterminedIndependence_short_desc"> Yes, if using the cutoff threshold for the independence test.
      • Long Description: mgmParam3
      • Long Description: In case the exact algorithm is not used for discrete children and continuous parents is not used, - the This parameter gives the number of categories to use for this + this parameter gives the number of categories to use for this second (discretize) backup copy of the continuous variables.
      • Default Value: numLatents id="numLatents_short_desc">Number of additional latent variables (min = 0)
      • Long Description: Thye numbger of additional latent + id="numLatents_long_desc"> The number of additional latent variables to include in the datasets
      • Default Value: 0
      • @@ -7215,7 +7046,7 @@

        probRemoveColumn

        edges
      • Long Description: This is a parameter for generating - random multiple indictor models (MIMs). A structural edge is an edge + random multiple indicator models (MIMs). A structural edge is an edge connecting two structural nodes.
      • Default Value: 3
      • @@ -7238,7 +7069,7 @@

        probRemoveColumn

        nodes
      • Long Description: This is a parameter for generating - random multiple indictor models (MIMs). A structural node is one of + random multiple indicator models (MIMs). A structural node is one of the latent variables in the model; each structural node has a number of child measured variables.
      • Default Value: numStarts first (default 1)
      • Long Description: The number of times the algorithm should - srarted from different initializations. By default, the algorithm + be started from different initializations. By default, the algorithm will be run through at least once using the initialized parameters (zero random restarts).
      • Default Value: useBes

      graspBreakAFterImprovement

      + id="graspBreakAfterImprovement">graspBreakAfterImprovement
      • Short Description: Yes if depth first search + id="graspBreakAfterImprovement_short_desc"> Yes if depth first search returns after first improvement, No for depth first traversal.
      • Long Description: Exploring the full list in + id="graspBreakAfterImprovement_long_desc"> Exploring the full list in every DFS call is equivalent to what we've been calling the Random Carnival Game procedure (RCG).
      • Default Value: true
      • + id="graspBreakAfterImprovement_default_value">true
      • Lower Bound:
      • + id="graspBreakAfterImprovement_lower_bound">
      • Upper - Bound:
      • + Bound:
      • Value Type: Boolean
      • + id="graspBreakAfterImprovement_value_type">Boolean

      graspDepth

      tucks
    • Long Description: This is the depth of recursion - at which multiple tucks may be consdidered per score improvement + at which multiple tucks may be considered per score improvement
    • Default Value: 1
    • @@ -7647,7 +7478,7 @@

      timeout

      id="timeout_short_desc">Timeout (best graph returned, -1 = no timeout)
    • Long Description: The algorithm will timeout at approximately + id="timeout_long_desc"> The algorithm will time out at approximately this number of seconds from when it started and return the final graph found at that point.
    • Default Value: precomputeCovarianc be precomputed for tubular continuous data
    • Long Description: - For more than 5000 variables or so, set this to false to calculate covariances + For more than 5000 variables or so, set this to false in order to calculate covariances on the fly from data.
    • Default Value: @@ -8049,7 +7880,7 @@

      probCycle

      in the graph (0 - 1)
    • Long Description: Any edge X*-*Y may be replaced with a - 2-cycle (feedback loop) between X and Y with this probility. + 2-cycle (feedback loop) between X and Y with this probability.
    • Default Value: 0.0
    • @@ -8088,7 +7919,7 @@

      probCycle

      class="parameter_description_list">
    • Short Description: Yes if the order of the columns in - each datasets should be randomized
    • + each dataset should be randomized
    • Long Description: In the real world where unfaithfulness is an issue the order of variables in the data may for @@ -8152,8 +7983,8 @@

      probCycle

      id="resamplingEnsemble_short_desc">Ensemble method: Preserved (1), Highest (2), Majority (3)
    • Long Description: Preserved = keep highest frequency - edges; Highest = keep highest frequency edges but ignore the no edge + id="resamplingEnsemble_long_desc"> Preserved = keep the highest frequency + edges; Highest = keep the highest frequency edges but ignore the no edge case if maximal; Majority = keep edges only if their frequency is greater than 0.5.
    • Default Value: sampleSize
    • Short Description: Sample size (min = 1)
    • Long - Description: Ddetermines now many + Description: Determines now many records should be generated for the data. The minimum number of records is 1; the default is set to 1000.
    • Default @@ -8385,7 +8216,7 @@

      semBicRule

      id="semBicRule_short_desc"> Lambda: 1 = Chickering, 2 = Nandy
    • Long Description: The - Chickering Rule uses a the difference of BIC scores to add or remove + Chickering Rule uses the difference of BIC scores to add or remove edges. The Nandy et al. rule uses a single calculation of a partial correlation in place of the likelihood difference.
    • Default Value: 1
    • @@ -8498,7 +8329,7 @@

      stableFAS

      id="standardize_short_desc">Yes if the data should be standardized
    • Long Description: Yes if each varaibles in the data should + id="standardize_long_desc"> Yes if each variable in the data should be standardized to have mean zero and variance 1.
    • Default Value: false
    • @@ -8523,9 +8354,9 @@

      stableFAS

      with about that number of parents. The prior structure weights are distributed according to a binomial distribution.
    • Default Value: 1.0
    • + id="structurePrior_default_value">0.0
    • Lower Bound: - 0
    • + 0.0
    • Upper Bound: 1.7976931348623157E308
    • @@ -8538,7 +8369,7 @@

      stableFAS

      • Short Description: Yes if the first step step for + id="symmetricFirstStep_short_desc"> Yes if the first step for FGES should do scoring for both X->Y and Y->X
      • Long Description: If Yes, scores @@ -8616,11 +8447,11 @@

        thr

        • Short Description: Yes, if use the + id="thresholdNoRandomConstrainSearch_short_desc"> Yes, if using the cutoff threshold for the meta-constraints independence test (stage 2).
        • Long Description: Yes, if use the + id="thresholdNoRandomConstrainSearch_long_desc"> Yes, if using the cutoff threshold for the meta-constraints independence test (stage 2).
        • Default Value: thr
          • Short Description: Yes, if use the cutoff + id="thresholdNoRandomDataSearch_short_desc"> Yes, if using the cutoff threshold for the constraints independence test (stage 1).
          • Long Description: useGap
            • Short Description: Yes if the GAP algorithms should be used. No + id="useGap_short_desc">Yes if the GAP algorithms should be used. Not if the SAG algorithm should be used
            • Long Description: True if one should first find all possible initial sets, grows these out, and then picks a - non-overlapping such largest sets from these. No if one should grow + non-overlapping such largest sets from these. Not if one should grow pure clusters one at a time, excluding variables found in earlier clusters.
            • Default Value: useGap

              useWishart

              • Short Description: Yes if the Wishart test shoud be used. No + id="useWishart_short_desc">Yes if the Wishart test should be used. Not if the Delta test should be used
              • Long Description: This is a parameter for the FOFC (Find One Factor Clusters) algorithm. There are two tests implemented there for testing for tetrads being zero, Wishart and Delta. This - parameter picks which of these tests should be use: ‘Yes’ for Wishart + parameter picks which of these tests should be used: ‘Yes’ for Wishart and ‘No’ for Delta.
              • Default Value: false
              • @@ -9109,7 +8940,7 @@

                verbose

                applications should be printed or logged
              • Long Description: If this parameter is - set to ‘Yes’, Meek rule appications will be printed out to the + set to ‘Yes’, Meek rule applications will be printed out to the log.
              • Default Value: false
              • @@ -9145,7 +8976,7 @@

                useScore

                • Short Description: Yes if CPDAG should be ouput, no if a + id="outputCpdag_short_desc">Yes if CPDAG should be output, no if a DAG.
                • Long Description: BOSS can output a DAG or the CPDAG of the @@ -9186,12 +9017,12 @@

                  useScore

                  class="parameter_description_list">
                • Short Description: Yes if the (MimBuild) - stucture model should be included in the output graph
                • + structure model should be included in the output graph
                • Long Description: FOFC proper yields a measurement model--that is, a set of pure children for each of the discovered latents. One can estimate the structure over the latents (the structure model) using Mimbuild. This - struture model is included in the output if this parameter is set to + structure model is included in the output if this parameter is set to Yes.
                • Default Value: true
                • @@ -9256,7 +9087,7 @@

                  Multiple Linear Regression

                  simply click on another variable and click on the arrow again.

                  To select a variable as a predictor variable, click on it in the - leftmost box, and then click on the second right- pointing arrow. To + leftmost box, and then click on the second right-pointing arrow. To remove a predictor variable, click on it in the predictor box and then click on the left-pointing arrow.

                  @@ -9292,7 +9123,7 @@

                  Appendices

                  An Introduction to PAGs

                  -

                  Peter Spirites

                  +

                  Peter Spirtes

                  The output of the FCI algorithm [Spirtes, 2001] is a partial ancestral graph (PAG), which is a graphical object that represents a set @@ -9338,9 +9169,9 @@

                  An Introduction to - A --> B + A --> B A is a cause of B. It may - be a direct or indirect cause that may include other measured + be a direct or indirect because that may include other measured variables. Also, there may be an unmeasured confounder of A and B. B is not a cause of A. @@ -9391,8 +9222,8 @@

                  An Introduction to an edge between A and B means "A is a cause of B"; an arrowhead ">" at the A end of an edge between A and B means "A is not a cause of B"; and a circle "o" at the A end of an edge between A and B means "can't tell - whether or not A is a cause of B". For example A --> B means that A is a - cause of B, and that B is not a cause of A in all of the CBNs represented + whether A is a cause of B". For example A --> B means that A is a + cause of B, and that B is not a cause of A in all the CBNs represented by the PAG.

                  The PAG in Figure 2 shows examples of each type of edge, and the CBNs. Figure 1. show some examples of what kinds of CBNs @@ -9455,8 +9286,8 @@

                  Arc Specializations in PAGs

                  Solving Out of Memory Errors

                  -

                  By default Java will - allocate the smaller of 1/4 system memory or 1GB to the Java virtual +

                  By default, Java will + allocate the smaller option of 1/4 system memory or 1GB to the Java virtual machine (JVM). If you run out of memory (heap memory space) running your analyses you should increase the memory allocated to the JVM with the following switch '-XmxXXG' where XX is the number of gigabytes of ram you @@ -9469,7 +9300,7 @@

                  Glossary of Terms

                  Adjacent

                  Two vertices in a graph are adjacent if there is - a directed, or undirected, or double headed edge between them.

                  + a directed, or undirected, or double-headed edge between them.

                  Degree

                  The total number of edges directed both into and @@ -9539,23 +9370,6 @@

                  Trek
                  Y or from Y to X, or two directed paths from a third variable Z into X and Y that do not intersect except at Z.

                  - - - - - - - diff --git a/docs/notes/cfci.orientation.txt b/tetrad-lib/src/main/resources/docs/notes/cfci.orientation.txt similarity index 100% rename from docs/notes/cfci.orientation.txt rename to tetrad-lib/src/main/resources/docs/notes/cfci.orientation.txt diff --git a/docs/notes/cliques.txt b/tetrad-lib/src/main/resources/docs/notes/cliques.txt similarity index 100% rename from docs/notes/cliques.txt rename to tetrad-lib/src/main/resources/docs/notes/cliques.txt diff --git a/docs/notes/cmd.txt b/tetrad-lib/src/main/resources/docs/notes/cmd.txt similarity index 100% rename from docs/notes/cmd.txt rename to tetrad-lib/src/main/resources/docs/notes/cmd.txt diff --git a/docs/notes/images b/tetrad-lib/src/main/resources/docs/notes/images similarity index 100% rename from docs/notes/images rename to tetrad-lib/src/main/resources/docs/notes/images diff --git a/docs/notes/images.1 b/tetrad-lib/src/main/resources/docs/notes/images.1 similarity index 100% rename from docs/notes/images.1 rename to tetrad-lib/src/main/resources/docs/notes/images.1 diff --git a/docs/notes/pc.fci.in.r.spirtes.2.3.2010.txt b/tetrad-lib/src/main/resources/docs/notes/pc.fci.in.r.spirtes.2.3.2010.txt similarity index 100% rename from docs/notes/pc.fci.in.r.spirtes.2.3.2010.txt rename to tetrad-lib/src/main/resources/docs/notes/pc.fci.in.r.spirtes.2.3.2010.txt diff --git a/docs/notes/serialization_notes.txt b/tetrad-lib/src/main/resources/docs/notes/serialization_notes.txt similarity index 100% rename from docs/notes/serialization_notes.txt rename to tetrad-lib/src/main/resources/docs/notes/serialization_notes.txt diff --git a/docs/referenced_papers/Adjacency-submitted.pdf b/tetrad-lib/src/main/resources/docs/referenced_papers/Adjacency-submitted.pdf similarity index 100% rename from docs/referenced_papers/Adjacency-submitted.pdf rename to tetrad-lib/src/main/resources/docs/referenced_papers/Adjacency-submitted.pdf diff --git a/docs/referenced_papers/AmStat_review.pdf b/tetrad-lib/src/main/resources/docs/referenced_papers/AmStat_review.pdf similarity index 100% rename from docs/referenced_papers/AmStat_review.pdf rename to tetrad-lib/src/main/resources/docs/referenced_papers/AmStat_review.pdf diff --git a/docs/referenced_papers/Bollen_Ting_1993SociolMeth.pdf b/tetrad-lib/src/main/resources/docs/referenced_papers/Bollen_Ting_1993SociolMeth.pdf similarity index 100% rename from docs/referenced_papers/Bollen_Ting_1993SociolMeth.pdf rename to tetrad-lib/src/main/resources/docs/referenced_papers/Bollen_Ting_1993SociolMeth.pdf diff --git a/docs/referenced_papers/CAUSAL.PS b/tetrad-lib/src/main/resources/docs/referenced_papers/CAUSAL.PS similarity index 100% rename from docs/referenced_papers/CAUSAL.PS rename to tetrad-lib/src/main/resources/docs/referenced_papers/CAUSAL.PS diff --git a/docs/referenced_papers/CMU-ISRI-04-127.pdf b/tetrad-lib/src/main/resources/docs/referenced_papers/CMU-ISRI-04-127.pdf similarity index 100% rename from docs/referenced_papers/CMU-ISRI-04-127.pdf rename to tetrad-lib/src/main/resources/docs/referenced_papers/CMU-ISRI-04-127.pdf diff --git a/docs/referenced_papers/chickering02b.pdf b/tetrad-lib/src/main/resources/docs/referenced_papers/chickering02b.pdf similarity index 100% rename from docs/referenced_papers/chickering02b.pdf rename to tetrad-lib/src/main/resources/docs/referenced_papers/chickering02b.pdf diff --git a/docs/referenced_papers/con00random.pdf b/tetrad-lib/src/main/resources/docs/referenced_papers/con00random.pdf similarity index 100% rename from docs/referenced_papers/con00random.pdf rename to tetrad-lib/src/main/resources/docs/referenced_papers/con00random.pdf diff --git a/docs/referenced_papers/glasso.f90 b/tetrad-lib/src/main/resources/docs/referenced_papers/glasso.f90 similarity index 100% rename from docs/referenced_papers/glasso.f90 rename to tetrad-lib/src/main/resources/docs/referenced_papers/glasso.f90 diff --git a/docs/referenced_papers/hartiganwong.pdf b/tetrad-lib/src/main/resources/docs/referenced_papers/hartiganwong.pdf similarity index 100% rename from docs/referenced_papers/hartiganwong.pdf rename to tetrad-lib/src/main/resources/docs/referenced_papers/hartiganwong.pdf diff --git a/docs/referenced_papers/hawkins1989.pdf b/tetrad-lib/src/main/resources/docs/referenced_papers/hawkins1989.pdf similarity index 100% rename from docs/referenced_papers/hawkins1989.pdf rename to tetrad-lib/src/main/resources/docs/referenced_papers/hawkins1989.pdf diff --git a/docs/referenced_papers/jmlr06.pdf b/tetrad-lib/src/main/resources/docs/referenced_papers/jmlr06.pdf similarity index 100% rename from docs/referenced_papers/jmlr06.pdf rename to tetrad-lib/src/main/resources/docs/referenced_papers/jmlr06.pdf diff --git a/docs/referenced_papers/math_s5_v1_article-17.pdf b/tetrad-lib/src/main/resources/docs/referenced_papers/math_s5_v1_article-17.pdf similarity index 100% rename from docs/referenced_papers/math_s5_v1_article-17.pdf rename to tetrad-lib/src/main/resources/docs/referenced_papers/math_s5_v1_article-17.pdf diff --git a/docs/referenced_papers/optimal.pdf b/tetrad-lib/src/main/resources/docs/referenced_papers/optimal.pdf similarity index 100% rename from docs/referenced_papers/optimal.pdf rename to tetrad-lib/src/main/resources/docs/referenced_papers/optimal.pdf diff --git a/docs/referenced_papers/p313-grira.pdf b/tetrad-lib/src/main/resources/docs/referenced_papers/p313-grira.pdf similarity index 100% rename from docs/referenced_papers/p313-grira.pdf rename to tetrad-lib/src/main/resources/docs/referenced_papers/p313-grira.pdf diff --git a/docs/referenced_papers/splits.pdf b/tetrad-lib/src/main/resources/docs/referenced_papers/splits.pdf similarity index 100% rename from docs/referenced_papers/splits.pdf rename to tetrad-lib/src/main/resources/docs/referenced_papers/splits.pdf diff --git a/docs/referenced_papers/uaidiscovery.pdf b/tetrad-lib/src/main/resources/docs/referenced_papers/uaidiscovery.pdf similarity index 100% rename from docs/referenced_papers/uaidiscovery.pdf rename to tetrad-lib/src/main/resources/docs/referenced_papers/uaidiscovery.pdf diff --git a/tetrad-lib/src/main/resources/tetrad-lib.properties b/tetrad-lib/src/main/resources/tetrad-lib.properties index e54506daf9..dc9a71c048 100644 --- a/tetrad-lib/src/main/resources/tetrad-lib.properties +++ b/tetrad-lib/src/main/resources/tetrad-lib.properties @@ -1,6 +1,6 @@ latest.version.url=https://cloud.ccd.pitt.edu datatype.continuous.test.default=edu.cmu.tetrad.algcomparison.independence.FisherZ -datatype.discrete.test.default=edu.cmu.tetrad.algcomparison.independence.Gsquare +datatype.discrete.test.default=edu.cmu.tetrad.algcomparison.independence.ChiSquare datatype.mixed.test.default=edu.cmu.tetrad.algcomparison.independence.ConditionalGaussianLRT datatype.continuous.score.default=edu.cmu.tetrad.algcomparison.score.SemBicScore datatype.discrete.score.default=edu.cmu.tetrad.algcomparison.score.BdeuScore diff --git a/tetrad-lib/src/test/java/edu/cmu/tetrad/algcomparison/TimeoutComparisonTest.java b/tetrad-lib/src/test/java/edu/cmu/tetrad/algcomparison/TimeoutComparisonTest.java deleted file mode 100644 index 984f490c40..0000000000 --- a/tetrad-lib/src/test/java/edu/cmu/tetrad/algcomparison/TimeoutComparisonTest.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (C) 2017 University of Pittsburgh. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA - */ -package edu.cmu.tetrad.algcomparison; - -import edu.cmu.tetrad.algcomparison.algorithm.Algorithms; -import edu.cmu.tetrad.algcomparison.algorithm.oracle.pag.Gfci; -import edu.cmu.tetrad.algcomparison.graph.RandomForward; -import edu.cmu.tetrad.algcomparison.independence.FisherZ; -import edu.cmu.tetrad.algcomparison.score.SemBicScore; -import edu.cmu.tetrad.algcomparison.simulation.SemSimulation; -import edu.cmu.tetrad.algcomparison.simulation.Simulations; -import edu.cmu.tetrad.algcomparison.statistic.*; -import edu.cmu.tetrad.util.Parameters; -import edu.cmu.tetrad.util.Params; -import org.junit.ClassRule; -import org.junit.Ignore; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.concurrent.TimeUnit; -import java.util.stream.Stream; - -import static java.lang.System.out; - -/** - * Nov 14, 2017 5:24:51 PM - * - * @author Kevin V. Bui (kvb2@pitt.edu) - */ -public class TimeoutComparisonTest { - - @ClassRule - public static TemporaryFolder tmpDir = new TemporaryFolder(); - - public TimeoutComparisonTest() { - } - - private static TimeoutComparison getTetradComparisonEngine() { - TimeoutComparison comparison = new TimeoutComparison(); - comparison.setShowAlgorithmIndices(true); - comparison.setShowSimulationIndices(true); - comparison.setSortByUtility(true); - comparison.setShowUtilities(true); - comparison.setParallelized(true); - - return comparison; - } - - private static Simulations getSimulations() { - Simulations simulations = new Simulations(); - simulations.add(new SemSimulation(new RandomForward())); - - return simulations; - } - - private static Algorithms getAlgorithms() { - Algorithms algorithms = new Algorithms(); - algorithms.add(new Gfci(new FisherZ(), new SemBicScore())); - - return algorithms; - } - - private static Statistics getStatistics() { - Statistics statistics = new Statistics(); - statistics.add(new AdjacencyPrecision()); - statistics.add(new AdjacencyRecall()); - statistics.add(new ArrowheadPrecision()); - statistics.add(new ArrowheadRecall()); - statistics.add(new MathewsCorrAdj()); - statistics.add(new MathewsCorrArrow()); - statistics.add(new F1Adj()); - statistics.add(new F1Arrow()); - statistics.add(new StructuralHammingDistance()); - statistics.add(new ElapsedCpuTime()); - - return statistics; - } - - private static Parameters getParameters() { - Parameters parameters = new Parameters(); - parameters.set(Params.NUM_RUNS, 1); - parameters.set(Params.NUM_MEASURES, 100); - parameters.set(Params.AVG_DEGREE, 4, 6); - parameters.set(Params.SAMPLE_SIZE, 250000); - parameters.set(Params.ALPHA, 1e-4, 1e-3, 1e-2); - - return parameters; - } - - /** - * Test of setComparisonGraph method, of class TimeoutComparison. - * - * @throws IOException - */ - @Ignore - @Test - public void testTimeoutComparison() throws IOException { - Parameters parameters = TimeoutComparisonTest.getParameters(); - Statistics statistics = TimeoutComparisonTest.getStatistics(); - Algorithms algorithms = TimeoutComparisonTest.getAlgorithms(); - Simulations simulations = TimeoutComparisonTest.getSimulations(); - - String resultsPath = TimeoutComparisonTest.tmpDir.newFolder("comparison").toString(); - - TimeoutComparison comparisonEngine = TimeoutComparisonTest.getTetradComparisonEngine(); - comparisonEngine.compareFromSimulations(resultsPath, simulations, algorithms, statistics, parameters, 60, TimeUnit.SECONDS); - - out.println("================================================================================"); - out.println("Output File:"); - out.println("================================================================================"); - Path outputFile = Paths.get(resultsPath, "Comparison.txt"); - if (Files.exists(outputFile)) { - try (Stream stream = Files.lines(outputFile)) { - stream.forEach(out::println); - } - } - out.println("================================================================================"); - } - -} diff --git a/tetrad-lib/src/test/java/edu/cmu/tetrad/annotation/AlgorithmAnnotationsTest.java b/tetrad-lib/src/test/java/edu/cmu/tetrad/annotation/AlgorithmAnnotationsTest.java index e167685b9c..e0fd29a149 100644 --- a/tetrad-lib/src/test/java/edu/cmu/tetrad/annotation/AlgorithmAnnotationsTest.java +++ b/tetrad-lib/src/test/java/edu/cmu/tetrad/annotation/AlgorithmAnnotationsTest.java @@ -37,7 +37,7 @@ public AlgorithmAnnotationsTest() { @Test public void testAnnotatedNameAttributeForUniqueness() { List> algorithms = AlgorithmAnnotations.getInstance().getAnnotatedClasses(); - List values = algorithms.stream().map(e -> e.getAnnotation().name().toLowerCase()).collect(Collectors.toList()); + List values = algorithms.stream().map(e -> e.annotation().name().toLowerCase()).collect(Collectors.toList()); long actual = values.size(); long expected = values.stream().distinct().count(); @@ -47,7 +47,7 @@ public void testAnnotatedNameAttributeForUniqueness() { @Test public void testAnnotatedCommandAttributeForUniqueness() { List> algorithms = AlgorithmAnnotations.getInstance().getAnnotatedClasses(); - List values = algorithms.stream().map(e -> e.getAnnotation().command().toLowerCase()).collect(Collectors.toList()); + List values = algorithms.stream().map(e -> e.annotation().command().toLowerCase()).collect(Collectors.toList()); long actual = values.size(); long expected = values.stream().distinct().count(); diff --git a/tetrad-lib/src/test/java/edu/cmu/tetrad/annotation/ScoreAnnotationsTest.java b/tetrad-lib/src/test/java/edu/cmu/tetrad/annotation/ScoreAnnotationsTest.java index f1bbed8f70..7f303c2af2 100644 --- a/tetrad-lib/src/test/java/edu/cmu/tetrad/annotation/ScoreAnnotationsTest.java +++ b/tetrad-lib/src/test/java/edu/cmu/tetrad/annotation/ScoreAnnotationsTest.java @@ -37,7 +37,7 @@ public ScoreAnnotationsTest() { @Test public void testAnnotatedNameAttributeForUniqueness() { List> scores = ScoreAnnotations.getInstance().getAnnotatedClasses(); - List values = scores.stream().map(e -> e.getAnnotation().name().toLowerCase()).collect(Collectors.toList()); + List values = scores.stream().map(e -> e.annotation().name().toLowerCase()).collect(Collectors.toList()); long actual = values.size(); long expected = values.stream().distinct().count(); @@ -47,7 +47,7 @@ public void testAnnotatedNameAttributeForUniqueness() { @Test public void testAnnotatedCommandAttributeForUniqueness() { List> scores = ScoreAnnotations.getInstance().getAnnotatedClasses(); - List values = scores.stream().map(e -> e.getAnnotation().command().toLowerCase()).collect(Collectors.toList()); + List values = scores.stream().map(e -> e.annotation().command().toLowerCase()).collect(Collectors.toList()); long actual = values.size(); long expected = values.stream().distinct().count(); diff --git a/tetrad-lib/src/test/java/edu/cmu/tetrad/annotation/TestOfIndependenceAnnotationsTest.java b/tetrad-lib/src/test/java/edu/cmu/tetrad/annotation/TestOfIndependenceAnnotationsTest.java index 6a6f8188d7..8fc433dc7e 100644 --- a/tetrad-lib/src/test/java/edu/cmu/tetrad/annotation/TestOfIndependenceAnnotationsTest.java +++ b/tetrad-lib/src/test/java/edu/cmu/tetrad/annotation/TestOfIndependenceAnnotationsTest.java @@ -37,7 +37,7 @@ public TestOfIndependenceAnnotationsTest() { @Test public void testAnnotatedNameAttributeForUniqueness() { List> indTests = TestOfIndependenceAnnotations.getInstance().getAnnotatedClasses(); - List values = indTests.stream().map(e -> e.getAnnotation().name().toLowerCase()).collect(Collectors.toList()); + List values = indTests.stream().map(e -> e.annotation().name().toLowerCase()).collect(Collectors.toList()); long actual = values.size(); long expected = values.stream().distinct().count(); @@ -47,7 +47,7 @@ public void testAnnotatedNameAttributeForUniqueness() { @Test public void testAnnotatedCommandAttributeForUniqueness() { List> indTests = TestOfIndependenceAnnotations.getInstance().getAnnotatedClasses(); - List values = indTests.stream().map(e -> e.getAnnotation().name().toLowerCase()).collect(Collectors.toList()); + List values = indTests.stream().map(e -> e.annotation().name().toLowerCase()).collect(Collectors.toList()); long actual = values.size(); long expected = values.stream().distinct().count(); diff --git a/tetrad-lib/src/test/java/edu/cmu/tetrad/bayes/JunctionTreeAlgorithmTest.java b/tetrad-lib/src/test/java/edu/cmu/tetrad/bayes/JunctionTreeAlgorithmTest.java index e99b508fe7..d1af1fe326 100644 --- a/tetrad-lib/src/test/java/edu/cmu/tetrad/bayes/JunctionTreeAlgorithmTest.java +++ b/tetrad-lib/src/test/java/edu/cmu/tetrad/bayes/JunctionTreeAlgorithmTest.java @@ -38,6 +38,7 @@ import java.nio.file.Paths; import java.text.DecimalFormat; import java.util.Arrays; +import java.util.Objects; import java.util.stream.Collectors; /** @@ -79,11 +80,11 @@ private static void printExampleProof(JunctionTreeAlgorithm jta, int[] values) { System.out.printf("P(v1=0|v2=0)P(v2=0)P(v3=0|v2=0) = %f%n", v1GivenV2 * v2Parent * v3Givenv2); } - @Ignore +// @Ignore @Test public void testJointProbGivenParents() throws IOException { - String graphFile = this.getClass().getResource("/jta/graph2.txt").getFile(); - String dataFile = this.getClass().getResource("/jta/data2.txt").getFile(); + String graphFile = Objects.requireNonNull(this.getClass().getResource("/jta/graph2.txt")).getFile(); + String dataFile = Objects.requireNonNull(this.getClass().getResource("/jta/data2.txt")).getFile(); Graph graph = readInGraph(Paths.get(graphFile)); DataModel dataModel = readInDiscreteData(Paths.get(dataFile)); @@ -106,7 +107,7 @@ public void testJointProbGivenParents() throws IOException { double probXYGivenZW = jta.getConditionalProbabilities(nodes, values, parents, parentValues); // 0.24614443432733896 } - @Ignore +// @Ignore @Test public void testJointProbability() { String graphFile = this.getClass().getResource("/jta/graph.txt").getFile(); @@ -123,11 +124,11 @@ public void testJointProbability() { } } - @Ignore +// @Ignore @Test public void testJunctionTree() { - String graphFile = this.getClass().getResource("/jta/graph.txt").getFile(); - String dataFile = this.getClass().getResource("/jta/data.txt").getFile(); + String graphFile = Objects.requireNonNull(this.getClass().getResource("/jta/graph.txt")).getFile(); + String dataFile = Objects.requireNonNull(this.getClass().getResource("/jta/data.txt")).getFile(); try { JunctionTreeAlgorithm jta = getJunctionTreeAlgorithm(graphFile, dataFile); @@ -146,8 +147,6 @@ public void testJunctionTree() { Assert.assertEquals(expected, actual); // P(v1=0|v2=1) - iNode = 0; - value = 0; parents[0] = 1; parentValues[0] = 1; conProb = jta.getConditionalProbability(iNode, value, parents, parentValues); @@ -156,7 +155,6 @@ public void testJunctionTree() { Assert.assertEquals(expected, actual); // P(v1=1|v2=0) - iNode = 0; value = 1; parents[0] = 1; parentValues[0] = 0; @@ -166,8 +164,6 @@ public void testJunctionTree() { Assert.assertEquals(expected, actual); // P(v1=1|v2=1) - iNode = 0; - value = 1; parents[0] = 1; parentValues[0] = 1; conProb = jta.getConditionalProbability(iNode, value, parents, parentValues); diff --git a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/SpecialDataClark.java b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/SpecialDataClark.java index 02fa4f19b2..a39203b1d7 100644 --- a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/SpecialDataClark.java +++ b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/SpecialDataClark.java @@ -51,8 +51,6 @@ public void createData(Parameters parameters, boolean newModel) { this.graphs = new ArrayList<>(); for (int i = 0; i < parameters.getInt("numRuns"); i++) { - System.out.println("Simulating dataset #" + (i + 1)); - if (parameters.getBoolean("differentGraphs") && i > 0) { graph = this.randomGraph.createGraph(parameters); } diff --git a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestCyclicity.java b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestCyclicity.java deleted file mode 100755 index c202b54802..0000000000 --- a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestCyclicity.java +++ /dev/null @@ -1,96 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// 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.test; - -import jdepend.framework.JDepend; -import jdepend.framework.JavaPackage; -import org.junit.Ignore; -import org.junit.Test; - -import java.io.File; -import java.io.IOException; -import java.util.Collection; -import java.util.LinkedList; -import java.util.List; - -import static org.junit.Assert.fail; - -/** - * Checks for package cycles. - */ -@Ignore -public class TestCyclicity { - private JDepend jdepend; - - private void setUp() { - this.jdepend = new JDepend(); - - try { - this.jdepend.addDirectory(new File("target/classes/edu/cmu/tetrad").getAbsolutePath()); -// jdepend.addDirectory(new File("../../../tetrad/target/classes/edu/cmu/tetradapp").getAbsolutePath()); - } catch (IOException e) { - fail(e.getMessage()); - } - } - - /** - * Tests that a package dependency cycle does not exist for any of the analyzed packages. - */ - @Test - public void testAllPackagesCycle() { - setUp(); - - Collection packages = this.jdepend.analyze(); - - for (Object aPackage : packages) { - JavaPackage p = (JavaPackage) aPackage; - - if (p.containsCycle()) { - System.out.println("\n***Package: " + p.getName() + "."); - System.out.println(); - System.out.println( - "This package participates in a package cycle. In the following " + - "\nlist, for each i, some class in package i depends on some " + - "\nclass in package i + 1. Please find the cycle and remove it."); - - List l = new LinkedList(); - p.collectCycle(l); - System.out.println(); - - for (int j = 0; j < l.size(); j++) { - JavaPackage pack = (JavaPackage) l.get(j); - System.out.println((j + 1) + ".\t" + pack.getName()); - } - - System.out.println(); - } - } - - if (this.jdepend.containsCycles()) { - fail("Package cycle(s) found!"); - } - } -} - - - - diff --git a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestFges.java b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestFges.java index c9e7477ca5..56654a8b64 100644 --- a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestFges.java +++ b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestFges.java @@ -22,7 +22,6 @@ package edu.cmu.tetrad.test; import edu.cmu.tetrad.algcomparison.algorithm.Algorithm; -import edu.cmu.tetrad.algcomparison.algorithm.oracle.cpdag.Cpc; import edu.cmu.tetrad.algcomparison.algorithm.oracle.cpdag.Fges; import edu.cmu.tetrad.algcomparison.graph.RandomForward; import edu.cmu.tetrad.algcomparison.graph.RandomGraph; @@ -31,7 +30,8 @@ import edu.cmu.tetrad.algcomparison.score.ScoreWrapper; import edu.cmu.tetrad.algcomparison.simulation.LinearFisherModel; import edu.cmu.tetrad.algcomparison.simulation.Simulation; -import edu.cmu.tetrad.algcomparison.statistic.*; +import edu.cmu.tetrad.algcomparison.statistic.AdjacencyPrecision; +import edu.cmu.tetrad.algcomparison.statistic.AdjacencyRecall; import edu.cmu.tetrad.bayes.BayesIm; import edu.cmu.tetrad.bayes.BayesPm; import edu.cmu.tetrad.bayes.MlBayesIm; @@ -40,24 +40,21 @@ import edu.cmu.tetrad.search.FgesMb; import edu.cmu.tetrad.search.IndependenceTest; import edu.cmu.tetrad.search.Pc; -import edu.cmu.tetrad.search.score.*; +import edu.cmu.tetrad.search.score.BdeScore; +import edu.cmu.tetrad.search.score.GraphScore; +import edu.cmu.tetrad.search.score.SemBicScore; import edu.cmu.tetrad.search.test.MsepTest; -import edu.cmu.tetrad.search.utils.GraphSearchUtils; -import edu.cmu.tetrad.search.utils.MeekRules; -import edu.cmu.tetrad.sem.GeneralizedSemIm; -import edu.cmu.tetrad.sem.GeneralizedSemPm; import edu.cmu.tetrad.sem.SemIm; import edu.cmu.tetrad.sem.SemPm; -import edu.cmu.tetrad.util.*; -import edu.pitt.csb.mgm.Mgm; -import edu.pitt.csb.mgm.MixedUtils; -import org.apache.commons.math3.util.FastMath; +import edu.cmu.tetrad.util.Parameters; +import edu.cmu.tetrad.util.Params; +import edu.cmu.tetrad.util.RandomUtil; +import edu.cmu.tetrad.util.TetradLogger; +import org.jetbrains.annotations.NotNull; import org.junit.Test; import java.io.IOException; import java.io.PrintStream; -import java.text.DecimalFormat; -import java.text.NumberFormat; import java.util.*; import static junit.framework.TestCase.assertFalse; @@ -68,9 +65,8 @@ * @author josephramsey */ public class TestFges { - boolean precomputeCovariances = true; - private final PrintStream out = System.out; + boolean precomputeCovariances = true; // private OutputStream out = private HashMap hashIndices; @@ -117,9 +113,6 @@ public static void main(String... args) { Graph out1 = alg.search(sim.getDataModel(0), parameters); System.out.println(out1); } - - } else { - new TestFges().test9(); } } @@ -141,13 +134,6 @@ public void explore1() { } Graph dag = edu.cmu.tetrad.graph.RandomGraph.randomGraphRandomForwardEdges(vars, 0, numEdges, 30, 15, 15, false, true); -// printDegreeDistribution(dag, System.out); - - int[] causalOrdering = new int[vars.size()]; - - for (int i = 0; i < vars.size(); i++) { - causalOrdering[i] = i; - } SemPm pm = new SemPm(dag); SemIm im = new SemIm(pm); @@ -175,25 +161,6 @@ public void explore1() { double ar = new AdjacencyRecall().getValue(trueCPDAG, estCPDAG, data); System.out.println("ap = " + ap + " ar = " + ar); - - -// int[][] counts = SearchGraphUtils.graphComparison(estCPDAG, trueCPDAG, null); -// -// int[][] expectedCounts = { -// {2, 0, 0, 0, 0, 0}, -// {0, 0, 0, 0, 0, 0}, -// {0, 0, 0, 0, 0, 0}, -// {0, 0, 0, 0, 0, 0}, -// {0, 0, 0, 8, 0, 0}, -// {0, 0, 0, 0, 0, 0}, -// {0, 0, 0, 0, 0, 0}, -// {0, 0, 0, 0, 0, 0}, -// }; -// -// for (int i = 0; i < counts.length; i++) { -// assertTrue(Arrays.equals(counts[i], expectedCounts[i])); -// } - } @Test @@ -203,8 +170,6 @@ public void explore2() { final int numVars = 10; final double edgeFactor = 1.0; final int numCases = 1000; - final double structurePrior = 1; - final double samplePrior = 1; List vars = new ArrayList<>(); @@ -214,37 +179,16 @@ public void explore2() { Graph dag = edu.cmu.tetrad.graph.RandomGraph.randomGraphRandomForwardEdges(vars, 0, (int) (numVars * edgeFactor), 30, 15, 15, false, true); -// printDegreeDistribution(dag, out); BayesPm pm = new BayesPm(dag, 2, 3); BayesIm im = new MlBayesIm(pm, MlBayesIm.RANDOM); DataSet data = im.simulateData(numCases, false); -// out.println("Finishing simulation"); - BdeScore score = new BdeScore(data); edu.cmu.tetrad.search.Fges ges = new edu.cmu.tetrad.search.Fges(score); ges.setVerbose(false); ges.setFaithfulnessAssumed(false); - - Graph estCPDAG = ges.search(); - - Graph trueCPDAG = GraphTransforms.cpdagForDag(dag); - - int[][] counts = GraphSearchUtils.graphComparison(trueCPDAG, estCPDAG, null); - - int[][] expectedCounts = { - {2, 0, 0, 0, 0, 1}, - {0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0}, - {2, 0, 0, 13, 0, 3}, - {0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0}, - }; - } @Test @@ -267,7 +211,7 @@ public void testExplore4() { public void testExplore5() { Graph graph = GraphUtils.convert("A-->B,A-->C,A-->D,A->E,B-->F,C-->F,D-->F,E-->F"); edu.cmu.tetrad.search.Fges fges = new edu.cmu.tetrad.search.Fges(new GraphScore(graph)); - fges.setFaithfulnessAssumed(false); + fges.setFaithfulnessAssumed(true); Graph CPDAG = fges.search(); assertEquals(GraphTransforms.cpdagForDag(graph), CPDAG); } @@ -344,81 +288,33 @@ public void testFromGraphSimpleFgesMb() { assertEquals(mb1, mb2); } - // @Test - public void testFgesMbFromGraph() { - RandomUtil.getInstance().setSeed(1450184147770L); - - final int numNodes = 20; - final int numIterations = 2; - - for (int i = 0; i < numIterations; i++) { - System.out.println("Iteration " + (i + 1)); - Graph dag = edu.cmu.tetrad.graph.RandomGraph.randomDag(numNodes, 0, numNodes, 10, 10, 10, false); - GraphScore fgesScore = new GraphScore(dag); - - edu.cmu.tetrad.search.Fges fges = new edu.cmu.tetrad.search.Fges(fgesScore); - Graph CPDAG1 = fges.search(); - - Node x1 = fgesScore.getVariable("X1"); - - Set mb = new HashSet<>(); - mb.add(x1); - - mb.addAll(CPDAG1.getAdjacentNodes(x1)); - - for (Node child : CPDAG1.getChildren(x1)) { - mb.addAll(CPDAG1.getParents(child)); - } - - Graph mb1 = CPDAG1.subgraph(new ArrayList<>(mb)); - - FgesMb fgesMb = new FgesMb(fgesScore); - Graph mb2 = fgesMb.search(Collections.singletonList(x1)); - - assertEquals(mb1, mb2); - } - } + @Test + public void clarkTest() { + RandomGraph randomGraph = new RandomForward(); - private void printDegreeDistribution(Graph dag, PrintStream out) { - int max = 0; + Simulation simulation = new LinearFisherModel(randomGraph); - for (Node node : dag.getNodes()) { - int degree = dag.getAdjacentNodes(node).size(); - if (degree > max) max = degree; - } + Parameters parameters = getParameters(); - int[] counts = new int[max + 1]; - Map> names = new HashMap<>(); + simulation.createData(parameters, false); - for (int i = 0; i <= max; i++) { - names.put(i, new ArrayList<>()); - } + DataSet dataSet = (DataSet) simulation.getDataModel(0); + Graph trueGraph = simulation.getTrueGraph(0); - for (Node node : dag.getNodes()) { - int degree = dag.getAdjacentNodes(node).size(); - counts[degree]++; - names.get(degree).add(node); - } + ScoreWrapper score = new edu.cmu.tetrad.algcomparison.score.SemBicScore(); + IndependenceWrapper test = new FisherZ(); - for (int k = 0; k < counts.length; k++) { - if (counts[k] == 0) continue; + Algorithm fges = new Fges(score); - out.print(k + " " + counts[k]); + Graph fgesGraph = fges.search(dataSet, parameters); - for (Node node : names.get(k)) { - out.print(" " + node.getName()); - } + clarkTestForAlpha(0.05, parameters, dataSet, trueGraph, fgesGraph, test); + clarkTestForAlpha(0.01, parameters, dataSet, trueGraph, fgesGraph, test); - out.println(); - } } - @Test - public void clarkTest() { - RandomGraph randomGraph = new RandomForward(); - - Simulation simulation = new LinearFisherModel(randomGraph); - + @NotNull + private static Parameters getParameters() { Parameters parameters = new Parameters(); parameters.set(Params.NUM_MEASURES, 10); @@ -440,24 +336,7 @@ public void clarkTest() { parameters.set(Params.VERBOSE, false); parameters.set(Params.ALPHA, 0.01); - - simulation.createData(parameters, false); - - DataSet dataSet = (DataSet) simulation.getDataModel(0); - Graph trueGraph = simulation.getTrueGraph(0); - -// trueGraph = SearchGraphUtils.CPDAGForDag(trueGraph); - - ScoreWrapper score = new edu.cmu.tetrad.algcomparison.score.SemBicScore(); - IndependenceWrapper test = new FisherZ(); - - Algorithm fges = new Fges(score); - - Graph fgesGraph = fges.search(dataSet, parameters); - - clarkTestForAlpha(0.05, parameters, dataSet, trueGraph, fgesGraph, test); - clarkTestForAlpha(0.01, parameters, dataSet, trueGraph, fgesGraph, test); - + return parameters; } private void clarkTestForAlpha(double alpha, Parameters parameters, DataSet dataSet, Graph trueGraph, @@ -593,19 +472,50 @@ public void testSearch5() { @Test public void testCites() { - final String citesString = "164\n" + - "ABILITY\tGPQ\tPREPROD\tQFJ\tSEX\tCITES\tPUBS\n" + - "1.0\n" + - ".62\t1.0\n" + - ".25\t.09\t1.0\n" + - ".16\t.28\t.07\t1.0\n" + - "-.10\t.00\t.03\t.10\t1.0\n" + - ".29\t.25\t.34\t.37\t.13\t1.0\n" + - ".18\t.15\t.19\t.41\t.43\t.55\t1.0"; + final String citesString = """ + 164 + ABILITY\tGPQ\tPREPROD\tQFJ\tSEX\tCITES\tPUBS + 1.0 + .62\t1.0 + .25\t.09\t1.0 + .16\t.28\t.07\t1.0 + -.10\t.00\t.03\t.10\t1.0 + .29\t.25\t.34\t.37\t.13\t1.0 + .18\t.15\t.19\t.41\t.43\t.55\t1.0"""; char[] citesChars = citesString.toCharArray(); ICovarianceMatrix cov = SimpleDataLoader.loadCovarianceMatrix(citesChars, "//", DelimiterType.WHITESPACE, '\"', "*"); + Graph CPDAG = getGraph(cov); + + System.out.println(CPDAG); + + final String trueString = """ + Graph Nodes: + Graph Nodes: + Graph Nodes:;ABILITY;GPQ;PREPROD;QFJ;SEX;CITES;PUBS + + Graph Edges: + 1. ABILITY --> GPQ + 2. ABILITY --> PREPROD + 3. ABILITY --> PUBS + 4. GPQ --> QFJ + 5. PREPROD --> CITES + 6. PUBS --> CITES + 7. QFJ --> CITES + 8. QFJ --> PUBS + 9. SEX --> PUBS"""; + + try { + Graph trueGraph = GraphSaveLoadUtils.readerToGraphTxt(trueString); + CPDAG = GraphUtils.replaceNodes(CPDAG, trueGraph.getNodes()); + assertEquals(trueGraph, CPDAG); + } catch (IOException e) { + TetradLogger.getInstance().forceLogMessage("Error in testCites"); + } + } + + private static Graph getGraph(ICovarianceMatrix cov) { Knowledge knowledge = new Knowledge(); knowledge.addToTier(1, "ABILITY"); @@ -622,36 +532,7 @@ public void testCites() { fges.setVerbose(true); - Graph CPDAG = fges.search(); - - System.out.println(CPDAG); - - final String trueString = "Graph Nodes:\n" + - "Graph Nodes:\n" + - "Graph Nodes:;ABILITY;GPQ;PREPROD;QFJ;SEX;CITES;PUBS\n" + - "\n" + - "Graph Edges:\n" + - "1. ABILITY --> GPQ\n" + - "2. ABILITY --> PREPROD\n" + - "3. ABILITY --> PUBS\n" + - "4. GPQ --> QFJ\n" + - "5. PREPROD --> CITES\n" + - "6. PUBS --> CITES\n" + - "7. QFJ --> CITES\n" + - "8. QFJ --> PUBS\n" + - "9. SEX --> PUBS"; - - Graph trueGraph = null; - - - try { - trueGraph = GraphSaveLoadUtils.readerToGraphTxt(trueString); - CPDAG = GraphUtils.replaceNodes(CPDAG, trueGraph.getNodes()); - assertEquals(trueGraph, CPDAG); - } catch (IOException e) { - e.printStackTrace(); - } - + return fges.search(); } /** @@ -677,7 +558,7 @@ private void checkSearch(String inputGraph, String outputGraph) { resultGraph = GraphUtils.replaceNodes(resultGraph, trueGraph.getNodes()); // Do test. - assertTrue(resultGraph.equals(trueGraph)); + assertEquals(resultGraph, trueGraph); } /** @@ -701,14 +582,7 @@ private void checkWithKnowledge(String inputGraph, String answerGraph, // Build comparison graph. Graph answer = GraphUtils.convert(answerGraph); answer = GraphUtils.replaceNodes(answer, input.getNodes()); -// Graph answer = new PC(new IndTestMSep(input)).search(); - -// System.out.println("Input = " + input); -// System.out.println("Knowledge = " + knowledge); -// System.out.println("Answer = " + answer); -// System.out.println("Result graph = " + result); - // Do test. assertEquals(answer, result); } @@ -716,7 +590,7 @@ private void checkWithKnowledge(String inputGraph, String answerGraph, public void testFromGraph() { final int numNodes = 10; final int aveDegree = 4; - final int numIterations = 1; + final int numIterations = 10; for (int i = 0; i < numIterations; i++) { Graph dag = edu.cmu.tetrad.graph.RandomGraph.randomDag(numNodes, 0, aveDegree * numNodes / 2, 10, 10, 10, false); @@ -730,67 +604,6 @@ public void testFromGraph() { } } - // @Test - public void testFromData() { - final int numIterations = 1; - - Parameters params = new Parameters(); - - int[] nodeOptions = {5, 10, 20, 30, 40, 50, 75, 100}; - int[] avgDegreeOptions = {2, 4, 6}; - int[] sampleSizeOptions = {100, 500, 1000, 10000, 100000}; - - int numRowsInTable = nodeOptions.length * avgDegreeOptions.length * sampleSizeOptions.length; - - TextTable table = new TextTable(numRowsInTable + 1, 5); - - table.setToken(0, 0, "# Nodes"); - table.setToken(0, 1, "Avg Degree"); - table.setToken(0, 2, "# Samples"); - table.setToken(0, 3, "True # edges"); - table.setToken(0, 4, "Est # Edges"); - - int count = 0; - - for (int numNodes : nodeOptions) { - for (int avgDegree : avgDegreeOptions) { - for (int sampleSize : sampleSizeOptions) { - for (int q = 0; q < 1; q++) { - for (int i = 0; i < numIterations; i++) { - Graph dag = edu.cmu.tetrad.graph.RandomGraph.randomDag(numNodes, 0, - (avgDegree * numNodes) / 2, 100, 100, 100, false); - SemPm pm = new SemPm(dag); - SemIm im = new SemIm(pm, params); - DataSet data = im.simulateData(sampleSize, false); - SemBicScore score = new SemBicScore(data, precomputeCovariances); - score.setPenaltyDiscount(.5); - edu.cmu.tetrad.search.Fges fges = new edu.cmu.tetrad.search.Fges(score); - fges.setFaithfulnessAssumed(false); - fges.setVerbose(false); - Graph CPDAG1 = fges.search(); - System.out.println("num nodes = " + numNodes + " avg degree = " + avgDegree - + " sample size = " + sampleSize - + " true # edges = " + dag.getNumEdges() - + " est # edges = " + CPDAG1.getNumEdges()); - - count++; - table.setToken(count, 0, "" + numNodes); - table.setToken(count, 1, "" + avgDegree); - table.setToken(count, 2, "" + sampleSize); - table.setToken(count, 3, "" + dag.getNumEdges()); - table.setToken(count, 4, "" + CPDAG1.getNumEdges()); - - } - } - } - } - } - - System.out.println("\n==========================\n"); - System.out.println(table); - - } - @Test public void testFromGraphWithForbiddenKnowledge() { final int numNodes = 10; @@ -819,9 +632,6 @@ public void testFromGraphWithForbiddenKnowledge() { assertFalse(CPDAG1.isParentOf(x, y)); } - - // This sometimes fails if the following cycle check is uncommented. -// assertFalse(CPDAG1.existsDirectedCycle()); } } @@ -891,735 +701,12 @@ private Knowledge requiredKnowledge(Graph graph) { return knowledge; } - private Graph getSubgraph(Graph graph, boolean discrete1, boolean discrete2, DataSet dataSet) { - Graph newGraph = new EdgeListGraph(graph.getNodes()); - - for (Edge edge : graph.getEdges()) { - Node node1 = dataSet.getVariable(edge.getNode1().getName()); - Node node2 = dataSet.getVariable(edge.getNode2().getName()); - - if (discrete1 && node1 instanceof DiscreteVariable) { - if (discrete2 && node2 instanceof DiscreteVariable) { - newGraph.addEdge(edge); - } - } else if (!discrete1 && node1 instanceof ContinuousVariable) { - if (!discrete2 && node2 instanceof ContinuousVariable) { - newGraph.addEdge(edge); - } - } else if ((discrete1 && !discrete2) || (!discrete1 && discrete2)) { - if (node1 instanceof ContinuousVariable && node2 instanceof DiscreteVariable) { - newGraph.addEdge(edge); - } else if (node1 instanceof DiscreteVariable && node2 instanceof ContinuousVariable) { - newGraph.addEdge(edge); - } - } - } - - return newGraph; - } - - private Graph searchSemFges(DataSet Dk) { - Dk = DataTransforms.convertNumericalDiscreteToContinuous(Dk); - SemBicScore score = new SemBicScore(new CovarianceMatrix(Dk)); - score.setPenaltyDiscount(2.0); - edu.cmu.tetrad.search.Fges fges = new edu.cmu.tetrad.search.Fges(score); - return fges.search(); - } - - private Graph searchBdeuFges(DataSet Dk, int k) { - Discretizer discretizer = new Discretizer(Dk); - List nodes = Dk.getVariables(); - - for (Node node : nodes) { - if (node instanceof ContinuousVariable) { - discretizer.equalIntervals(node, k); - } - } - - Dk = discretizer.discretize(); - - BdeuScore score = new BdeuScore(Dk); - score.setSamplePrior(1.0); - score.setStructurePrior(1.0); - edu.cmu.tetrad.search.Fges fges = new edu.cmu.tetrad.search.Fges(score); - return fges.search(); - } - - private Graph searchMixedFges(DataSet dk) { - ConditionalGaussianScore score = new ConditionalGaussianScore(dk, 2.0, true); - score.setPenaltyDiscount(2.0); - score.setStructurePrior(0.0); - edu.cmu.tetrad.search.Fges fges = new edu.cmu.tetrad.search.Fges(score); - return fges.search(); - } - - public Graph searchMGMFges(DataSet ds, double penalty) { - Mgm m = new Mgm(ds, new double[]{0.1, 0.1, 0.1}); - //m.setVerbose(this.verbose); - Graph gm = m.search(); - DataSet dataSet = MixedUtils.makeContinuousData(ds); - SemBicScore score = new SemBicScore(new CovarianceMatrix(dataSet)); - score.setPenaltyDiscount(penalty); - edu.cmu.tetrad.search.Fges fg = new edu.cmu.tetrad.search.Fges(score); - fg.setBoundGraph(gm); - fg.setVerbose(false); - return fg.search(); - } - - public DataSet getMixedDataAjStyle(Graph g, int k, int samps) { - - HashMap nd = new HashMap<>(); - - List nodes = g.getNodes(); - - RandomUtil.shuffle(nodes); - - for (int i = 0; i < nodes.size(); i++) { - if (i < nodes.size() / 2) { - nd.put(nodes.get(i).getName(), k); - } else { - nd.put(nodes.get(i).getName(), 0); - } - } - - g = MixedUtils.makeMixedGraph(g, nd); - - - GeneralizedSemPm pm = MixedUtils.GaussianCategoricalPm(g, "Split(-1.5,-.5,.5,1.5)"); -// System.out.println(pm); - - GeneralizedSemIm im = MixedUtils.GaussianCategoricalIm(pm); -// System.out.println(im); - - DataSet ds = im.simulateDataFisher(samps); - return MixedUtils.makeMixedData(ds, nd); - } - - // @Test - public void testBestAlgorithms() { - String[] algorithms = {"SemFGES", "BDeuFGES", "MixedFGES", "PC", "PCS", "CPC", "MGMFges", "MGMPcs"}; - String[] statLabels = {"AP", "AR", "OP", "OR", "SUM", "McAdj", "McOr", "F1Adj", "F1Or", "E"}; - - final int numMeasures = 10; - final int numEdges = 10; - - final int numRuns = 50; - final int maxCategories = 5; - final int sampleSize = 1000; - final double penaltyDiscount = 4.0; - final double ofInterestCutoff = 0.05; - - double[][][][] allAllRet = new double[maxCategories][][][]; - int latentIndex = -1; - - for (int numCategories = 2; numCategories <= maxCategories; numCategories++) { - latentIndex++; - - System.out.println(); - - System.out.println("num categories = " + numCategories); - System.out.println("num measures = " + numMeasures); - System.out.println("num edges = " + numEdges); - System.out.println("sample size = " + sampleSize); - System.out.println("penaltyDiscount = " + penaltyDiscount); - System.out.println("num runs = " + numRuns); - - double[][][] allRet = new double[algorithms.length][][]; - - for (int t = 0; t < algorithms.length; t++) { - allRet[t] = printStats(algorithms, t, - numCategories); - } - - allAllRet[latentIndex] = allRet; - } - - System.out.println(); - System.out.println("======="); - System.out.println(); - System.out.println("Algorithms with max = " + ofInterestCutoff + "*(max - min) < stat <= max."); - System.out.println(); - System.out.println("AP = Average Adj Precision; AR = Average Adj Recall"); - System.out.println("OP = Average orientation (arrow) Precision; OR = Average orientation (arrow) recall"); - System.out.println("McAdj = Mathew's correlation for adjacencies; McOr = Mathew's correlatin for orientatons"); - System.out.println("F1Adj = F1 score for adjacencies; F1Or = F1 score for orientations"); - System.out.println("E = Averaged Elapsed Time (ms), AP/P"); - System.out.println(); - System.out.println("num categories = 2 to " + maxCategories); - System.out.println("sample size = " + sampleSize); - System.out.println("penaltyDiscount = " + penaltyDiscount); - System.out.println("num runs = " + numRuns); - System.out.println(); - System.out.println("num measures = " + numMeasures); - System.out.println("num edges = " + numEdges); - - printBestStats(allAllRet, algorithms, statLabels); - } - - private double[][] printStats(String[] algorithms, int t, - int numCategories) { - NumberFormat nf = new DecimalFormat("0.00"); - - double[] sumAdjPrecision = new double[4]; - double[] sumAdjRecall = new double[4]; - double[] sumArrowPrecision = new double[4]; - double[] sumArrowRecall = new double[4]; - double[] sumSum = new double[4]; - double[] sumMcAdj = new double[4]; - double[] sumMcOr = new double[4]; - double[] sumF1Adj = new double[4]; - double[] sumF1Or = new double[4]; - double totalElapsed = 0.0; - - int[] countAP = new int[4]; - int[] countAR = new int[4]; - int[] countOP = new int[4]; - int[] countOR = new int[4]; - int[] countSum = new int[4]; - int[] countMcAdj = new int[4]; - int[] countMcOr = new int[4]; - int[] countF1Adj = new int[4]; - int[] countF1Or = new int[4]; - - for (int i = 0; i < 50; i++) { - List nodes = new ArrayList<>(); - - for (int r = 0; r < 30; r++) { - String name = "X" + (r + 1); - nodes.add(new ContinuousVariable(name)); - } - - Graph dag = edu.cmu.tetrad.graph.RandomGraph.randomGraphRandomForwardEdges(nodes, 0, 60, - 10, 10, 10, false); - DataSet data = getMixedDataAjStyle(dag, numCategories, 1000); - - Graph out; - final double penalty = 2; - - long start = MillisecondTimes.timeMillis(); - - switch (t) { - case 0: - out = searchSemFges(data); - break; - case 1: - out = searchBdeuFges(data, numCategories); - break; - case 2: - out = searchMixedFges(data); - break; - case 3: - out = searchMGMFges(data, penalty); - break; - default: - throw new IllegalStateException(); - } - - out = GraphUtils.replaceNodes(out, dag.getNodes()); - - Graph[] est = new Graph[4]; - - est[0] = out; - est[1] = getSubgraph(out, true, true, data); - est[2] = getSubgraph(out, true, false, data); - est[3] = getSubgraph(out, false, false, data); - - Graph[] truth = new Graph[4]; - - truth[0] = dag; - truth[1] = getSubgraph(dag, true, true, data); - truth[2] = getSubgraph(dag, true, false, data); - truth[3] = getSubgraph(dag, false, false, data); - - long stop = MillisecondTimes.timeMillis(); - - long elapsed = stop - start; - totalElapsed += elapsed; - - for (int u = 0; u < 4; u++) { - int adjTp = 0; - int adjFp = 0; - int adjTn; - int adjFn = 0; - int arrowsTp = 0; - int arrowsFp = 0; - int arrowsTn = 0; - int arrowsFn = 0; - - for (Edge edge : est[u].getEdges()) { - if (truth[u].isAdjacentTo(edge.getNode1(), edge.getNode2())) { - adjTp++; - } else { - adjFp++; - } - - if (edge.isDirected()) { - Edge _edge = truth[u].getEdge(edge.getNode1(), edge.getNode2()); - - if (edge != null && edge.equals(_edge)) { - arrowsTp++; - } else { - arrowsFp++; - } - } - } - - List nodes1 = truth[u].getNodes(); - - for (int w = 0; w < nodes1.size(); w++) { - for (int s = w + 1; w < nodes1.size(); w++) { - Node W = nodes1.get(w); - Node S = nodes1.get(s); - - if (truth[u].isAdjacentTo(W, S)) { - if (!est[u].isAdjacentTo(W, S)) { - adjFn++; - } - - Edge e1 = truth[u].getEdge(W, S); - Edge e2 = est[u].getEdge(W, S); - - if (!(e2 != null && e2.equals(e1))) { - arrowsFn++; - } - } - - Edge e1 = truth[u].getEdge(W, S); - Edge e2 = est[u].getEdge(W, S); - - if (!(e1 != null && e2 == null) || (e1 != null && e2 != null && !e1.equals(e2))) { - arrowsFn++; - } - } - } - - int allEdges = truth[u].getNumNodes() * (truth[u].getNumNodes() - 1); - - adjTn = allEdges / 2 - (adjFn + adjFp + adjTp); - arrowsTn = allEdges - (arrowsFn + arrowsFp + arrowsTp); - - double adjPrecision = adjTp / (double) (adjTp + adjFp); - double adjRecall = adjTp / (double) (adjTp + adjFn); - - double arrowPrecision = arrowsTp / (double) (arrowsTp + arrowsFp); - double arrowRecall = arrowsTp / (double) (arrowsTp + arrowsFn); - - if (!Double.isNaN(adjPrecision)) { - sumAdjPrecision[u] += adjPrecision; - countAP[u]++; - } - - if (!Double.isNaN(adjRecall)) { - sumAdjRecall[u] += adjRecall; - countAR[u]++; - } - - if (!Double.isNaN(arrowPrecision)) { - sumArrowPrecision[u] += arrowPrecision; - countOP[u]++; - } - - if (!Double.isNaN(arrowRecall)) { - sumArrowRecall[u] += arrowRecall; - countOR[u]++; - } - - double sum = adjPrecision + adjRecall + arrowPrecision + arrowRecall; - double mcAdj = (adjTp * adjTn - adjFp * adjFn) / - FastMath.sqrt((adjTp + adjFp) * (adjTp + adjFn) * (adjTn + adjFp) * (adjTn + adjFn)); - double mcOr = (arrowsTp * arrowsTn - arrowsFp * arrowsFn) / - FastMath.sqrt((arrowsTp + arrowsFp) * (arrowsTp + arrowsFn) * - (arrowsTn + arrowsFp) * (arrowsTn + arrowsFn)); - double f1Adj = 2 * (adjPrecision * adjRecall) / (adjPrecision + adjRecall); - double f1Arrows = 2 * (arrowPrecision * arrowRecall) / (arrowPrecision + arrowRecall); - - if (f1Arrows < 0) { - System.out.println(); - } - - if (!Double.isNaN(sum)) { - sumSum[u] += sum; - countSum[u]++; - } - - if (!Double.isNaN(mcAdj)) { - sumMcAdj[u] += mcAdj; - countMcAdj[u]++; - } - - if (!Double.isNaN(mcOr)) { - sumMcOr[u] += mcOr; - countMcOr[u]++; - } - - if (!Double.isNaN(f1Adj)) { - sumF1Adj[u] += f1Adj; - countF1Adj[u]++; - } - - if (!Double.isNaN(f1Arrows)) { - sumF1Or[u] += f1Arrows; - countF1Or[u]++; - } - } - } - - double[] avgAdjPrecision = new double[4]; - double[] avgAdjRecall = new double[4]; - double[] avgArrowPrecision = new double[4]; - double[] avgArrowRecall = new double[4]; - double[] avgSum = new double[4]; - double[] avgMcAdj = new double[4]; - double[] avgMcOr = new double[4]; - double[] avgF1Adj = new double[4]; - double[] avgF1Or = new double[4]; - double[] avgElapsed = new double[4]; - - for (int u = 0; u < 4; u++) { - avgAdjPrecision[u] = sumAdjPrecision[u] / (double) countAP[u]; - avgAdjRecall[u] = sumAdjRecall[u] / (double) countAR[u]; - avgArrowPrecision[u] = sumArrowPrecision[u] / (double) countOP[u]; - avgArrowRecall[u] = sumArrowRecall[u] / (double) countOR[u]; - avgSum[u] = sumSum[u] / (double) countSum[u]; - avgMcAdj[u] = sumMcAdj[u] / (double) countMcAdj[u]; - avgMcOr[u] = sumMcOr[u] / (double) countMcOr[u]; - avgF1Adj[u] = sumF1Adj[u] / (double) countF1Adj[u]; - avgF1Or[u] = sumF1Or[u] / (double) countF1Or[u]; - avgElapsed[u] = -totalElapsed / (double) 50; - } - - double[][] ret = { - avgAdjPrecision, - avgAdjRecall, - avgArrowPrecision, - avgArrowRecall, - avgSum, - avgMcAdj, - avgMcOr, - avgF1Adj, - avgF1Or, - avgElapsed - }; - - System.out.println(); - - for (int u = 0; u < 4; u++) { - String header = getHeader(u); - - System.out.println("\n" + header + "\n"); - - System.out.println(algorithms[t] + " adj precision " + nf.format(avgAdjPrecision[u])); - System.out.println(algorithms[t] + " adj recall " + nf.format(avgAdjRecall[u])); - System.out.println(algorithms[t] + " arrow precision " + nf.format(avgArrowPrecision[u])); - System.out.println(algorithms[t] + " arrow recall " + nf.format(avgArrowRecall[u])); - System.out.println(algorithms[t] + " sum " + nf.format(avgSum[u])); - System.out.println(algorithms[t] + " McAdj " + nf.format(avgMcAdj[u])); - System.out.println(algorithms[t] + " McOr " + nf.format(avgMcOr[u])); - System.out.println(algorithms[t] + " F1adj " + nf.format(avgF1Adj[u])); - System.out.println(algorithms[t] + " F1Or " + nf.format(avgF1Or[u])); - System.out.println(algorithms[t] + " avg elapsed " + nf.format(avgElapsed[u])); - } - - - return ret; - } - - private String getHeader(int u) { - String header; - - switch (u) { - case 0: - header = "All edges"; - break; - case 1: - header = "Discrete-discrete"; - break; - case 2: - header = "Discrete-continuous"; - break; - case 3: - header = "Continuous-continuous"; - break; - default: - throw new IllegalStateException(); - } - return header; - } - - private void printBestStats(double[][][][] allAllRet, String[] algorithms, String[] statLabels) { - TextTable table = new TextTable(allAllRet.length + 1, allAllRet[0][0].length + 1); - - - class Pair { - private final String algorithm; - private final double stat; - - public Pair(String algorithm, double stat) { - this.algorithm = algorithm; - this.stat = stat; - } - - public String getAlgorithm() { - return this.algorithm; - } - - public double getStat() { - return this.stat; - } - } - - - System.out.println(); - System.out.println("And the winners are... !"); - - for (int u = 0; u < 4; u++) { - for (int numCategories = 2; numCategories <= 5; numCategories++) { - - table.setToken(numCategories - 1, 0, numCategories + ""); - - for (int statIndex = 0; statIndex < allAllRet[numCategories - 2][0].length; statIndex++) { -// double maxStat = Double.NaN; - String maxAlg = "-"; - - List algStats = new ArrayList<>(); - - for (int t = 0; t < algorithms.length; t++) { - double stat = allAllRet[numCategories - 2][t][statIndex][u]; - if (!Double.isNaN(stat)) { - algStats.add(new Pair(algorithms[t], stat)); - } - } - - if (algStats.isEmpty()) { - maxAlg = "-"; - } else { - Collections.sort(algStats, new Comparator() { - - @Override - public int compare(Pair o1, Pair o2) { - return -Double.compare(o1.getStat(), o2.getStat()); - } - }); - - double maxStat = algStats.get(0).getStat(); - maxAlg = algStats.get(0).getAlgorithm(); - - double minStat = algStats.get(algStats.size() - 1).getStat(); - - double diff = maxStat - minStat; - double ofInterest = maxStat - 0.05 * (diff); - - for (int i = 1; i < algStats.size(); i++) { - if (algStats.get(i).getStat() >= ofInterest) { - maxAlg += "," + algStats.get(i).getAlgorithm(); - } - } - } - - table.setToken(numCategories - 1, statIndex + 1, maxAlg); - } - } - - for (int j = 0; j < statLabels.length; j++) { - table.setToken(0, j + 1, statLabels[j]); - } - - System.out.println(); - System.out.println(getHeader(u)); - System.out.println(); - - System.out.println(table); - } - - - NumberFormat nf = new DecimalFormat("0.00"); - - System.out.println(); - System.out.println("Details:"); - System.out.println(); - System.out.println("Average statistics"); - - for (int u = 0; u < 4; u++) { - System.out.println(); - System.out.println(getHeader(u)); - System.out.println(); - - for (int numCategories = 2; numCategories <= 5; numCategories++) { - System.out.println("\n# categories = " + numCategories); - - for (int t = 0; t < algorithms.length; t++) { - String algorithm = algorithms[t]; - - System.out.println("\nAlgorithm = " + algorithm); - System.out.println(); - - for (int statIndex = 0; statIndex < allAllRet[numCategories - 2][0].length; statIndex++) { - String statLabel = statLabels[statIndex]; - double stat = allAllRet[numCategories - 2][t][statIndex][u]; - System.out.println("\tAverage" + statLabel + " = " + nf.format(stat)); - } - } - } - } - - } - - // @Test - public void test7() { - for (int i = 0; i < 10; i++) { - - Graph graph = edu.cmu.tetrad.graph.RandomGraph.randomGraph(10, 0, - 10, 10, 10, 10, false); - SemPm semPm = new SemPm(graph); - SemIm semIm = new SemIm(semPm); - DataSet dataSet = semIm.simulateData(1000, false); - - edu.cmu.tetrad.search.Fges fges = new edu.cmu.tetrad.search.Fges(new SemBicScore(new CovarianceMatrix(dataSet))); - Graph CPDAG = fges.search(); - - Graph dag = dagFromCPDAG(CPDAG); - - assertFalse(dag.paths().existsDirectedCycle()); - } - } - - private Graph dagFromCPDAG(Graph CPDAG) { - Graph dag = new EdgeListGraph(CPDAG); - - MeekRules rules = new MeekRules(); - - WHILE: - while (true) { - List edges = new ArrayList<>(dag.getEdges()); - - for (Edge edge : edges) { - if (Edges.isUndirectedEdge(edge)) { - Node x = edge.getNode1(); - Node y = edge.getNode2(); - - List okx = dag.getAdjacentNodes(x); - okx.removeAll(dag.getChildren(x)); - okx.remove(y); - - List oky = dag.getAdjacentNodes(y); - oky.removeAll(dag.getChildren(y)); - oky.remove(x); - - if (!okx.isEmpty()) { - Node other = okx.iterator().next(); - dag.removeEdge(other, x); - dag.removeEdge(y, x); - dag.addDirectedEdge(other, x); - dag.addDirectedEdge(y, x); - } else if (!oky.isEmpty()) { - Node other = oky.iterator().next(); - dag.removeEdge(other, y); - dag.removeEdge(x, y); - dag.addDirectedEdge(other, y); - dag.addDirectedEdge(x, y); - } else { - dag.removeEdge(x, y); - dag.addDirectedEdge(x, y); - } - - rules.orientImplied(dag); - continue WHILE; - } - } - - break; - } - - return dag; - } - - public void test9() { - - Parameters parameters = new Parameters(); - - parameters.set(Params.NUM_MEASURES, 50); - parameters.set(Params.NUM_LATENTS, 0); - parameters.set(Params.AVG_DEGREE, 2); - parameters.set(Params.MAX_DEGREE, 20); - parameters.set(Params.MAX_INDEGREE, 20); - parameters.set(Params.MAX_OUTDEGREE, 20); - parameters.set(Params.CONNECTED, false); - - parameters.set(Params.COEF_LOW, 0.2); - parameters.set(Params.COEF_HIGH, 0.9); - parameters.set(Params.VAR_LOW, 1); - parameters.set(Params.VAR_HIGH, 3); - parameters.set(Params.VERBOSE, false); - parameters.set(Params.COEF_SYMMETRIC, true); - parameters.set(Params.NUM_RUNS, 1); - parameters.set(Params.PERCENT_DISCRETE, 0); - parameters.set(Params.NUM_CATEGORIES, 3); - parameters.set(Params.DIFFERENT_GRAPHS, true); - parameters.set(Params.SAMPLE_SIZE, 500); - parameters.set(Params.INTERVAL_BETWEEN_SHOCKS, 10); - parameters.set(Params.INTERVAL_BETWEEN_RECORDINGS, 10); - parameters.set(Params.FISHER_EPSILON, 0.001); - parameters.set(Params.RANDOMIZE_COLUMNS, true); - - RandomGraph graph = new RandomForward(); - LinearFisherModel sim = new LinearFisherModel(graph); - sim.createData(parameters, false); - Graph previous = null; - int prevDiff = Integer.MAX_VALUE; - -// for (int l = 7; l >= 1; l--) { - for (int i = 2; i <= 20; i++) { - parameters.set(Params.PENALTY_DISCOUNT, i / (double) 10); - - ScoreWrapper score = new edu.cmu.tetrad.algcomparison.score.SemBicScore(); - Algorithm alg = new Cpc(new FisherZ()); - - Graph out = alg.search(sim.getDataModel(0), parameters); -// Graph out = GraphUtils.undirectedGraph(alg.search(sim.getDataModel(0), parameters)); - - Set edges1 = out.getEdges(); - - int numEdges = edges1.size(); - - if (previous != null) { - Set edges2 = previous.getEdges(); - edges2.removeAll(edges1); - int diff = edges2.size(); -// - System.out.println("Penalty discount =" + parameters.getDouble(Params.PENALTY_DISCOUNT) - + " # edges = " + numEdges - + " # additional = " + diff); - - previous = out; - if (diff > prevDiff) break; - prevDiff = diff; - } else { - previous = out; - } - } - - Graph estGraph = previous; - Graph trueGraph = sim.getTrueGraph(0); - - estGraph = GraphUtils.replaceNodes(estGraph, trueGraph.getNodes()); - - Statistic ap = new AdjacencyPrecision(); - Statistic ar = new AdjacencyRecall(); - Statistic ahp = new ArrowheadPrecision(); - Statistic ahr = new ArrowheadRecall(); - - System.out.println("AP = " + ap.getValue(trueGraph, estGraph, null)); - System.out.println("AR = " + ar.getValue(trueGraph, estGraph, null)); - System.out.println("AHP = " + ahp.getValue(trueGraph, estGraph, null)); - System.out.println("AHR = " + ahr.getValue(trueGraph, estGraph, null)); - } - @Test public void testSemBicDiffs() { final int N = 1000; final int numCond = 3; - Graph graph = edu.cmu.tetrad.graph.RandomGraph.randomGraph(10, 0, 20, 100, + Graph graph = edu.cmu.tetrad.graph.RandomGraph.randomGraph(10, 0, 10, 100, 100, 100, false); List nodes = graph.getNodes(); buildIndexing(nodes); @@ -1646,8 +733,8 @@ public void testSemBicDiffs() { double diff = scoreGraphChange(x, y, z, this.hashIndices, score); boolean diffNegative = diff < 0; - if (!_msep && _msep != diffNegative) { - System.out.println(count++ + "\t" + (_msep ? "msep" : "mconn") + "\t" + (diffNegative ? "indep" : "dep") + "\tdiff = " + diff); + if (!_msep && diffNegative) { + System.out.println(count++ + "\t" + "mconn" + "\t" + "indep" + "\tdiff = " + diff); } } @@ -1688,7 +775,6 @@ private void buildIndexing(List nodes) { this.hashIndices.put(n, ++i); } } - } diff --git a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGeneralResamplingTest.java b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGeneralResamplingTest.java index 151d3947cc..ca8dac8c0b 100644 --- a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGeneralResamplingTest.java +++ b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGeneralResamplingTest.java @@ -24,7 +24,6 @@ import edu.cmu.tetrad.algcomparison.algorithm.oracle.pag.Gfci; import edu.cmu.tetrad.algcomparison.independence.BdeuTest; import edu.cmu.tetrad.algcomparison.independence.ChiSquare; -import edu.cmu.tetrad.algcomparison.independence.FisherZ; import edu.cmu.tetrad.algcomparison.independence.IndependenceWrapper; import edu.cmu.tetrad.algcomparison.score.BdeuScore; import edu.cmu.tetrad.algcomparison.score.ScoreWrapper; @@ -38,12 +37,10 @@ import edu.cmu.tetrad.graph.GraphTransforms; import edu.cmu.tetrad.graph.Node; import edu.cmu.tetrad.graph.RandomGraph; -import edu.cmu.tetrad.sem.LargeScaleSimulation; import edu.cmu.tetrad.util.Parameters; import edu.cmu.tetrad.util.Params; import edu.cmu.tetrad.util.RandomUtil; import edu.pitt.dbmi.algo.resampling.GeneralResamplingTest; -import org.junit.Ignore; import org.junit.Test; import java.util.ArrayList; @@ -164,10 +161,7 @@ public void testFGESc() { final boolean faithfulnessAssumed = false; final int maxDegree = -1; - final int numVars = 20; - final int edgesPerNode = 2; final int numLatentConfounders = 0; - final int numCases = 50; final int numBootstrapSamples = 5; final boolean verbose = true; @@ -176,12 +170,6 @@ public void testFGESc() { System.out.println("Truth Graph:"); System.out.println(dag); - int[] causalOrdering = new int[numVars]; - - for (int i = 0; i < numVars; i++) { - causalOrdering[i] = i; - } - BayesPm pm = new BayesPm(dag); BayesIm im = new MlBayesIm(pm, MlBayesIm.RANDOM); DataSet data = im.simulateData(1000, false); @@ -202,8 +190,6 @@ public void testFGESc() { bootstrapTest.setVerbose(verbose); bootstrapTest.setParameters(parameters); Graph resultGraph = bootstrapTest.search(); -// System.out.println("Estimated Graph:"); -// System.out.println(resultGraph.toString()); // Adjacency Confusion Matrix int[][] adjAr = GeneralResamplingTest.getAdjConfusionMatrix(dag, resultGraph); @@ -216,7 +202,7 @@ public void testFGESc() { TestGeneralResamplingTest.printEdgeTypeConfusionMatrix(edgeAr); } - @Ignore + // @Ignore @Test public void testFGESd() { final double structurePrior = 1; @@ -224,8 +210,6 @@ public void testFGESd() { final boolean faithfulnessAssumed = false; final int maxDegree = -1; - final int numVars = 20; - final int edgesPerNode = 2; final int numLatentConfounders = 0; final int numCases = 50; final int numBootstrapSamples = 5; @@ -276,8 +260,6 @@ public void testGFCIc() { final boolean faithfulnessAssumed = false; final int maxDegree = -1; - final int numVars = 20; - final int edgesPerNode = 2; final int numLatentConfounders = 2; final int numCases = 50; final int numBootstrapSamples = 5; @@ -288,17 +270,8 @@ public void testGFCIc() { BayesPm pm = new BayesPm(dag, 2, 3); BayesIm im = new MlBayesIm(pm, MlBayesIm.RANDOM); -// DagToPag dagToPag = new DagToPag(dag); -// Graph truePag = dagToPag.convert(); - Graph truePag = GraphTransforms.dagToPag(dag); - int[] causalOrdering = new int[numVars]; - - for (int i = 0; i < numVars; i++) { - causalOrdering[i] = i; - } - DataSet data = im.simulateData(numCases, false); Parameters parameters = new Parameters(); @@ -332,7 +305,7 @@ public void testGFCIc() { TestGeneralResamplingTest.printEdgeTypeConfusionMatrix(edgeAr); } - @Ignore + // @Ignore @Test public void testGFCId() { final double structurePrior = 1; @@ -340,8 +313,6 @@ public void testGFCId() { final boolean faithfulnessAssumed = false; final int maxDegree = -1; - final int numVars = 20; - final int edgesPerNode = 2; final int numLatentConfounders = 4; final int numCases = 50; final int numBootstrapSamples = 5; @@ -349,10 +320,6 @@ public void testGFCId() { final long seed = 123; Graph dag = TestGeneralResamplingTest.makeDiscreteDAG(numLatentConfounders); - -// DagToPag dagToPag = new DagToPag(dag); -// Graph truePag = dagToPag.convert(); - Graph truePag = GraphTransforms.dagToPag(dag); BayesPm pm = new BayesPm(dag, 2, 3); @@ -394,69 +361,6 @@ public void testGFCId() { TestGeneralResamplingTest.printEdgeTypeConfusionMatrix(edgeAr); } - @Ignore - @Test - public void testFCIc() { - final int penaltyDiscount = 2; - final int depth = 3; - final int maxPathLength = -1; - - final int numVars = 20; - final int edgesPerNode = 2; - final int numLatentConfounders = 2; - final int numCases = 50; - final int numBootstrapSamples = 5; - final boolean verbose = true; - - Graph dag = TestGeneralResamplingTest.makeContinuousDAG(numLatentConfounders); - -// DagToPag dagToPag = new DagToPag(dag); -// Graph truePag = dagToPag.convert(); - - Graph truePag = GraphTransforms.dagToPag(dag); - - int[] causalOrdering = new int[numVars]; - - for (int i = 0; i < numVars; i++) { - causalOrdering[i] = i; - } - - LargeScaleSimulation simulator = new LargeScaleSimulation(dag, dag.getNodes(), causalOrdering); - - DataSet data = simulator.simulateDataFisher(numCases); - - Parameters parameters = new Parameters(); - parameters.set(Params.PENALTY_DISCOUNT, penaltyDiscount); - parameters.set(Params.DEPTH, depth); - parameters.set(Params.MAX_PATH_LENGTH, maxPathLength); - parameters.set("numCPDAGsToStore", 0); - parameters.set(Params.VERBOSE, verbose); - - IndependenceWrapper test = new FisherZ(); - Fci algorithm = new Fci(test); - - GeneralResamplingTest bootstrapTest = new GeneralResamplingTest(data, algorithm, - numBootstrapSamples, 100.0, - true, 0, true); - bootstrapTest.setVerbose(verbose); - bootstrapTest.setParameters(parameters); - //bootstrapTest.setParallelMode(false); - Graph resultGraph = bootstrapTest.search(); - //System.out.println("Estimated PAG_of_the_true_DAG Graph:"); - //System.out.println(resultGraph.toString()); - - // Adjacency Confusion Matrix - int[][] adjAr = GeneralResamplingTest.getAdjConfusionMatrix(truePag, resultGraph); - - TestGeneralResamplingTest.printAdjConfusionMatrix(adjAr); - - // Edge Type Confusion Matrix - int[][] edgeAr = GeneralResamplingTest.getEdgeTypeConfusionMatrix(truePag, resultGraph); - - TestGeneralResamplingTest.printEdgeTypeConfusionMatrix(edgeAr); - } - - @Ignore @Test public void testFCId() { final double structurePrior = 1; @@ -464,8 +368,6 @@ public void testFCId() { final int depth = -1; final int maxPathLength = -1; - final int numVars = 20; - final int edgesPerNode = 2; final int numLatentConfounders = 4; final int numCases = 50; final int numBootstrapSamples = 5; @@ -473,10 +375,6 @@ public void testFCId() { final long seed = 123; Graph dag = TestGeneralResamplingTest.makeDiscreteDAG(numLatentConfounders); - -// DagToPag dagToPag = new DagToPag(dag); -// Graph truePag = dagToPag.convert(); - Graph truePag = GraphTransforms.dagToPag(dag); BayesPm pm = new BayesPm(dag, 2, 3); @@ -503,8 +401,6 @@ public void testFCId() { bootstrapTest.setVerbose(verbose); bootstrapTest.setParameters(parameters); Graph resultGraph = bootstrapTest.search(); - //System.out.println("Estimated Bootstrapped PAG_of_the_true_DAG Graph:"); - //System.out.println(resultGraph.toString()); // Adjacency Confusion Matrix int[][] adjAr = GeneralResamplingTest.getAdjConfusionMatrix(truePag, resultGraph); @@ -516,5 +412,4 @@ public void testFCId() { TestGeneralResamplingTest.printEdgeTypeConfusionMatrix(edgeAr); } - } diff --git a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGeneralizedSem.java b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGeneralizedSem.java index 9e6390bd10..0992fba21a 100644 --- a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGeneralizedSem.java +++ b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGeneralizedSem.java @@ -29,7 +29,6 @@ import edu.cmu.tetrad.util.RandomUtil; import edu.cmu.tetrad.util.StatUtils; import edu.cmu.tetrad.util.Vector; -import org.junit.Ignore; import org.junit.Test; import java.text.ParseException; @@ -42,7 +41,7 @@ /** * @author josephramsey */ -@Ignore +//@Ignore public class TestGeneralizedSem { private final boolean printStuff = false; @@ -463,720 +462,6 @@ public void test6() { print(estIm); print(estimator.getReport()); - - double aSquaredStar = estimator.getaSquaredStar(); - - assertEquals(1.04, aSquaredStar, 0.01); - } - - @Test - public void test7() { - RandomUtil.getInstance().setSeed(29999483L); - - List nodes = new ArrayList<>(); - final int numVars = 10; - - for (int i = 0; i < numVars; i++) nodes.add(new ContinuousVariable("X" + (i + 1))); - - Graph graph = RandomGraph.randomGraphRandomForwardEdges(nodes, 0, numVars, 30, 15, 15, false, true); - - GeneralizedSemPm pm = new GeneralizedSemPm(graph); - GeneralizedSemIm im = new GeneralizedSemIm(pm); - - print(im); - - DataSet data = im.simulateDataRecursive(1000, false); - - GeneralizedSemEstimator estimator = new GeneralizedSemEstimator(); - GeneralizedSemIm estIm = estimator.estimate(pm, data); - - print(estIm); - print(estimator.getReport()); - - double aSquaredStar = estimator.getaSquaredStar(); - - assertEquals(0.67, aSquaredStar, 0.01); - } - - @Test - public void test8() { - RandomUtil.getInstance().setSeed(29999483L); - - Node x = new GraphNode("X"); - Node y = new GraphNode("Y"); - - List nodes = new ArrayList<>(); - nodes.add(x); - nodes.add(y); - - Graph graph = new EdgeListGraph(nodes); - - graph.addDirectedEdge(x, y); - - SemPm spm = new SemPm(graph); - SemIm sim = new SemIm(spm); - - sim.setEdgeCoef(x, y, 20); - sim.setErrVar(x, 1); - sim.setErrVar(y, 1); - - GeneralizedSemPm pm = new GeneralizedSemPm(spm); - GeneralizedSemIm im = new GeneralizedSemIm(pm, sim); - - print(im); - - try { - pm.setParameterEstimationInitializationExpression("b1", "U(10, 30)"); - pm.setParameterEstimationInitializationExpression("T1", "U(.1, 3)"); - pm.setParameterEstimationInitializationExpression("T2", "U(.1, 3)"); - } catch (ParseException e) { - e.printStackTrace(); - } - - DataSet data = im.simulateDataRecursive(1000, false); - - GeneralizedSemEstimator estimator = new GeneralizedSemEstimator(); - GeneralizedSemIm estIm = estimator.estimate(pm, data); - - print(estIm); -// System.out.println(estimator.getReport()); - - double aSquaredStar = estimator.getaSquaredStar(); - - assertEquals(0.69, aSquaredStar, 0.01); - } - - @Test - public void test9() { - RandomUtil.getInstance().setSeed(29999483L); - - try { - Node x1 = new GraphNode("X1"); - Node x2 = new GraphNode("X2"); - Node x3 = new GraphNode("X3"); - Node x4 = new GraphNode("X4"); - - Graph g = new EdgeListGraph(); - g.addNode(x1); - g.addNode(x2); - g.addNode(x3); - g.addNode(x4); - - g.addDirectedEdge(x1, x2); - g.addDirectedEdge(x2, x3); - g.addDirectedEdge(x3, x4); - g.addDirectedEdge(x1, x4); - - GeneralizedSemPm pm = new GeneralizedSemPm(g); - - pm.setNodeExpression(x1, "E_X1"); - pm.setNodeExpression(x2, "a1 * tan(X1) + E_X2"); - pm.setNodeExpression(x3, "a2 * tan(X2) + E_X3"); - pm.setNodeExpression(x4, "a3 * tan(X1) + a4 * tan(X3) ^ 2 + E_X4"); - - pm.setNodeExpression(pm.getErrorNode(x1), "Beta(5, 2)"); - pm.setNodeExpression(pm.getErrorNode(x2), "Beta(2, 5)"); - pm.setNodeExpression(pm.getErrorNode(x3), "Beta(1, 3)"); - pm.setNodeExpression(pm.getErrorNode(x4), "Beta(1, 7)"); - - pm.setParameterEstimationInitializationExpression("c1", "U(1, 3)"); - pm.setParameterEstimationInitializationExpression("c2", "U(1, 3)"); - pm.setParameterEstimationInitializationExpression("c3", "U(1, 3)"); - pm.setParameterEstimationInitializationExpression("c4", "U(1, 3)"); - pm.setParameterEstimationInitializationExpression("c5", "U(1, 3)"); - pm.setParameterEstimationInitializationExpression("c6", "U(1, 3)"); - pm.setParameterEstimationInitializationExpression("c7", "U(1, 3)"); - pm.setParameterEstimationInitializationExpression("c8", "U(1, 3)"); - - GeneralizedSemIm im = new GeneralizedSemIm(pm); - - print("True model: "); - print(im); - - DataSet data = im.simulateDataRecursive(1000, false); - - pm.setNodeExpression(pm.getErrorNode(x1), "Beta(c1, c2)"); - pm.setNodeExpression(pm.getErrorNode(x2), "Beta(c3, c4)"); - pm.setNodeExpression(pm.getErrorNode(x3), "Beta(c5, c6)"); - pm.setNodeExpression(pm.getErrorNode(x4), "Beta(c7, c8)"); - - GeneralizedSemEstimator estimator = new GeneralizedSemEstimator(); - GeneralizedSemIm estIm = estimator.estimate(pm, data); - - print("\n\n\nEstimated model: "); - print(estIm); - print(estimator.getReport()); - - - double aSquaredStar = estimator.getaSquaredStar(); - - assertEquals(0.62, aSquaredStar, 0.01); - } catch (ParseException e) { - e.printStackTrace(); - } - } - - @Test - public void test10() { - RandomUtil.getInstance().setSeed(29999483L); - - try { - Node x1 = new GraphNode("X1"); - Node x2 = new GraphNode("X2"); - Node x3 = new GraphNode("X3"); - Node x4 = new GraphNode("X4"); - - Graph g = new EdgeListGraph(); - g.addNode(x1); - g.addNode(x2); - g.addNode(x3); - g.addNode(x4); - - g.addDirectedEdge(x1, x2); - g.addDirectedEdge(x2, x3); - g.addDirectedEdge(x3, x4); - g.addDirectedEdge(x1, x4); - - GeneralizedSemPm pm = new GeneralizedSemPm(g); - - pm.setNodeExpression(x1, "E_X1"); - pm.setNodeExpression(x2, "a1 * tan(X1) + E_X2"); - pm.setNodeExpression(x3, "a2 * tan(X2) + E_X3"); - pm.setNodeExpression(x4, "a3 * tan(X1) * a4 * tan(X3) ^ 2 + E_X4"); - - pm.setNodeExpression(pm.getErrorNode(x1), "Gamma(5, 2)"); - pm.setNodeExpression(pm.getErrorNode(x2), "Gamma(5, 2)"); - pm.setNodeExpression(pm.getErrorNode(x3), "Gamma(5, 2)"); - pm.setNodeExpression(pm.getErrorNode(x4), "Gamma(5, 2)"); - - pm.setParameterEstimationInitializationExpression("c1", "U(1, 5)"); - pm.setParameterEstimationInitializationExpression("c2", "U(1, 5)"); - pm.setParameterEstimationInitializationExpression("c3", "U(1, 5)"); - pm.setParameterEstimationInitializationExpression("c4", "U(1, 5)"); - pm.setParameterEstimationInitializationExpression("c5", "U(1, 5)"); - pm.setParameterEstimationInitializationExpression("c6", "U(1, 5)"); - pm.setParameterEstimationInitializationExpression("c7", "U(1, 5)"); - pm.setParameterEstimationInitializationExpression("c8", "U(1, 5)"); - - GeneralizedSemIm im = new GeneralizedSemIm(pm); - - print("True model: "); - print(im); - - DataSet data = im.simulateDataRecursive(1000, false); - - pm.setNodeExpression(pm.getErrorNode(x1), "Gamma(c1, c2)"); - pm.setNodeExpression(pm.getErrorNode(x2), "Gamma(c3, c4)"); - pm.setNodeExpression(pm.getErrorNode(x3), "Gamma(c5, c6)"); - pm.setNodeExpression(pm.getErrorNode(x4), "Gamma(c7, c8)"); - - - GeneralizedSemEstimator estimator = new GeneralizedSemEstimator(); - GeneralizedSemIm estIm = estimator.estimate(pm, data); - - print("\n\n\nEstimated model: "); - print(estIm); - print(estimator.getReport()); - - double aSquaredStar = estimator.getaSquaredStar(); - - assertEquals(1.42, aSquaredStar, 0.01); - } catch (ParseException e) { - e.printStackTrace(); - } - } - - @Test - public void test11() { - RandomUtil.getInstance().setSeed(29999483L); - - try { - Node x1 = new GraphNode("X1"); - Node x2 = new GraphNode("X2"); - Node x3 = new GraphNode("X3"); - Node x4 = new GraphNode("X4"); - - Graph g = new EdgeListGraph(); - g.addNode(x1); - g.addNode(x2); - g.addNode(x3); - g.addNode(x4); - - g.addDirectedEdge(x1, x2); - g.addDirectedEdge(x2, x3); - g.addDirectedEdge(x3, x4); - g.addDirectedEdge(x1, x4); - - GeneralizedSemPm pm = new GeneralizedSemPm(g); - - pm.setNodeExpression(x1, "E_X1"); - pm.setNodeExpression(x2, "a1 * tan(X1) + E_X2"); - pm.setNodeExpression(x3, "a2 * tan(X2) + E_X3"); - pm.setNodeExpression(x4, "a3 * tan(X1) + a4 * tan(X3) ^ 2 + E_X4"); - - pm.setNodeExpression(pm.getErrorNode(x1), "N(0, c1)"); - pm.setNodeExpression(pm.getErrorNode(x2), "N(0, c2)"); - pm.setNodeExpression(pm.getErrorNode(x3), "N(0, c3)"); - pm.setNodeExpression(pm.getErrorNode(x4), "N(0, c4)"); - - pm.setParameterExpression("c1", "4"); - pm.setParameterExpression("c2", "4"); - pm.setParameterExpression("c3", "4"); - pm.setParameterExpression("c4", "4"); - - GeneralizedSemIm im = new GeneralizedSemIm(pm); - - print("True model: "); - print(im); - - DataSet data = im.simulateDataRecursive(1000, false); - - GeneralizedSemIm imInit = new GeneralizedSemIm(pm); - imInit.setParameterValue("c1", 8); - imInit.setParameterValue("c2", 8); - imInit.setParameterValue("c3", 8); - imInit.setParameterValue("c4", 8); - - GeneralizedSemEstimator estimator = new GeneralizedSemEstimator(); - GeneralizedSemIm estIm = estimator.estimate(pm, data); - - print("\n\n\nEstimated model: "); - print(estIm); - print(estimator.getReport()); - - double aSquaredStar = estimator.getaSquaredStar(); - - assertEquals(7.07, aSquaredStar, 0.01); - } catch (ParseException e) { - e.printStackTrace(); - } - } - - @Test - public void test12() { - RandomUtil.getInstance().setSeed(29999483L); - - try { - Node x1 = new GraphNode("X1"); - Node x2 = new GraphNode("X2"); - Node x3 = new GraphNode("X3"); - Node x4 = new GraphNode("X4"); - - Graph g = new EdgeListGraph(); - g.addNode(x1); - g.addNode(x2); - g.addNode(x3); - g.addNode(x4); - - g.addDirectedEdge(x1, x2); - g.addDirectedEdge(x2, x3); - g.addDirectedEdge(x3, x4); - g.addDirectedEdge(x1, x4); - - GeneralizedSemPm pm = new GeneralizedSemPm(g); - - pm.setNodeExpression(x1, "E_X1"); - pm.setNodeExpression(x2, "a1 * tan(X1) + E_X2"); - pm.setNodeExpression(x3, "a2 * tan(X2) + E_X3"); - pm.setNodeExpression(x4, "a3 * tan(X1) + a4 * tan(X3) ^ 2 + E_X4"); - - pm.setNodeExpression(pm.getErrorNode(x1), "Normal(c1, c2)"); - pm.setNodeExpression(pm.getErrorNode(x2), "Normal(c3, c4)"); - pm.setNodeExpression(pm.getErrorNode(x3), "Normal(c5, c6)"); - pm.setNodeExpression(pm.getErrorNode(x4), "Normal(c7, c8)"); - - pm.setParameterExpression("c1", "1"); - pm.setParameterExpression("c2", "5"); - pm.setParameterExpression("c3", "1"); - pm.setParameterExpression("c4", "5"); - pm.setParameterExpression("c5", "1"); - pm.setParameterExpression("c6", "5"); - pm.setParameterExpression("c7", "1"); - pm.setParameterExpression("c8", "5"); - - GeneralizedSemIm im = new GeneralizedSemIm(pm); - - print("True model: "); - print(im); - - DataSet data = im.simulateDataRecursive(1000, false); - - GeneralizedSemIm imInit = new GeneralizedSemIm(pm); - imInit.setParameterValue("c1", 3); - imInit.setParameterValue("c2", 4); - imInit.setParameterValue("c3", 3); - imInit.setParameterValue("c4", 4); - imInit.setParameterValue("c5", 3); - imInit.setParameterValue("c6", 4); - imInit.setParameterValue("c7", 3); - imInit.setParameterValue("c8", 4); - - GeneralizedSemEstimator estimator = new GeneralizedSemEstimator(); - GeneralizedSemIm estIm = estimator.estimate(pm, data); - - print("\n\n\nEstimated model: "); - print(estIm); - print(estimator.getReport()); - - double aSquaredStar = estimator.getaSquaredStar(); - - assertEquals(2.56, aSquaredStar, 0.01); - } catch (ParseException e) { - e.printStackTrace(); - } - } - - @Test - public void test13() { - RandomUtil.getInstance().setSeed(29999483L); - - try { - Node x1 = new GraphNode("X1"); - Node x2 = new GraphNode("X2"); - Node x3 = new GraphNode("X3"); - Node x4 = new GraphNode("X4"); - - Graph g = new EdgeListGraph(); - g.addNode(x1); - g.addNode(x2); - g.addNode(x3); - g.addNode(x4); - - g.addDirectedEdge(x1, x2); - g.addDirectedEdge(x2, x3); - g.addDirectedEdge(x3, x4); - g.addDirectedEdge(x1, x4); - - GeneralizedSemPm pm = new GeneralizedSemPm(g); - - pm.setNodeExpression(x1, "E_X1"); - pm.setNodeExpression(x2, "a1 * tan(X1) + E_X1"); - pm.setNodeExpression(x3, "a2 * tan(X2) + E_X1"); - pm.setNodeExpression(x4, "a3 * tan(X1) + a4 * tan(X3) + E_X1"); - - pm.setNodeExpression(pm.getErrorNode(x1), "StudentT(c2)"); - pm.setNodeExpression(pm.getErrorNode(x2), "StudentT(c4)"); - pm.setNodeExpression(pm.getErrorNode(x3), "StudentT(c6)"); - pm.setNodeExpression(pm.getErrorNode(x4), "StudentT(c8)"); - - pm.setParameterExpression("c2", "3"); - pm.setParameterExpression("c4", "3"); - pm.setParameterExpression("c6", "3"); - pm.setParameterExpression("c8", "3"); - - GeneralizedSemIm im = new GeneralizedSemIm(pm); - - print("True model: "); - print(im); - - DataSet data = im.simulateDataRecursive(500, false); - - GeneralizedSemIm imInit = new GeneralizedSemIm(pm); - imInit.setParameterValue("c2", 1); - imInit.setParameterValue("c4", 1); - imInit.setParameterValue("c6", 1); - imInit.setParameterValue("c8", 1); - - GeneralizedSemEstimator estimator = new GeneralizedSemEstimator(); - GeneralizedSemIm estIm = estimator.estimate(pm, data); - - print("\n\n\nEstimated model: "); - print(estIm); - print(estimator.getReport()); - - double aSquaredStar = estimator.getaSquaredStar(); - - assertEquals(3.19, aSquaredStar, 0.01); - } catch (ParseException e) { - e.printStackTrace(); - } - } - - @Test - public void test14() { - RandomUtil.getInstance().setSeed(29999483L); - - try { - Node x1 = new GraphNode("X1"); - Node x2 = new GraphNode("X2"); - Node x3 = new GraphNode("X3"); - Node x4 = new GraphNode("X4"); - - Graph g = new EdgeListGraph(); - g.addNode(x1); - g.addNode(x2); - g.addNode(x3); - g.addNode(x4); - - g.addDirectedEdge(x1, x2); - g.addDirectedEdge(x2, x3); - g.addDirectedEdge(x3, x4); - g.addDirectedEdge(x1, x4); - - GeneralizedSemPm pm = new GeneralizedSemPm(g); - - pm.setNodeExpression(x1, "E_X1"); - pm.setNodeExpression(x2, "a1 * tan(X1) + E_X2"); - pm.setNodeExpression(x3, "a2 * tan(X2) + E_X3"); - pm.setNodeExpression(x4, "a3 * tan(X1) + a4 * tan(X3) ^ 2 + E_X4"); - - pm.setNodeExpression(pm.getErrorNode(x1), "N(0, c1)"); - pm.setNodeExpression(pm.getErrorNode(x2), "N(0, c2)"); - pm.setNodeExpression(pm.getErrorNode(x3), "N(0, c3)"); - pm.setNodeExpression(pm.getErrorNode(x4), "N(0, c4)"); - - pm.setParameterExpression("a1", "1"); - pm.setParameterExpression("a2", "1"); - pm.setParameterExpression("a3", "1"); - pm.setParameterExpression("a4", "1"); - pm.setParameterExpression("c1", "4"); - pm.setParameterExpression("c2", "4"); - pm.setParameterExpression("c3", "4"); - pm.setParameterExpression("c4", "4"); - - GeneralizedSemIm im = new GeneralizedSemIm(pm); - - print("True model: "); - print(im); - - DataSet data = im.simulateDataRecursive(1000, false); - - GeneralizedSemIm imInit = new GeneralizedSemIm(pm); - imInit.setParameterValue("c1", 8); - imInit.setParameterValue("c2", 8); - imInit.setParameterValue("c3", 8); - imInit.setParameterValue("c4", 8); - - GeneralizedSemEstimator estimator = new GeneralizedSemEstimator(); - GeneralizedSemIm estIm = estimator.estimate(pm, data); - - print("\n\n\nEstimated model: "); - print(estIm); - print(estimator.getReport()); - - double aSquaredStar = estimator.getaSquaredStar(); - - assertEquals(71.25, aSquaredStar, 0.01); - } catch (ParseException e) { - e.printStackTrace(); - } - } - - @Test - public void test15() { - RandomUtil.getInstance().setSeed(29999483L); - - try { - Node x1 = new GraphNode("X1"); - Node x2 = new GraphNode("X2"); - Node x3 = new GraphNode("X3"); - Node x4 = new GraphNode("X4"); - - Graph g = new EdgeListGraph(); - g.addNode(x1); - g.addNode(x2); - g.addNode(x3); - g.addNode(x4); - - g.addDirectedEdge(x1, x2); - g.addDirectedEdge(x2, x3); - g.addDirectedEdge(x3, x4); - g.addDirectedEdge(x1, x4); - - GeneralizedSemPm pm = new GeneralizedSemPm(g); - - pm.setNodeExpression(x1, "E_X1"); - pm.setNodeExpression(x2, "a1 * X1 + E_X2"); - pm.setNodeExpression(x3, "a2 * X2 + E_X3"); - pm.setNodeExpression(x4, "a3 * X1 + a4 * X3 ^ 2 + E_X4"); - - pm.setNodeExpression(pm.getErrorNode(x1), "Gamma(c1, c2)"); - pm.setNodeExpression(pm.getErrorNode(x2), "ChiSquare(c3)"); - pm.setNodeExpression(pm.getErrorNode(x3), "ChiSquare(c4)"); - pm.setNodeExpression(pm.getErrorNode(x4), "ChiSquare(c5)"); - - pm.setParameterExpression("c1", "5"); - pm.setParameterExpression("c2", "2"); - pm.setParameterExpression("c3", "10"); - pm.setParameterExpression("c4", "10"); - pm.setParameterExpression("c5", "10"); - - pm.setParameterEstimationInitializationExpression("c1", "U(1, 5)"); - pm.setParameterEstimationInitializationExpression("c2", "U(1, 5)"); - pm.setParameterEstimationInitializationExpression("c3", "U(1, 5)"); - pm.setParameterEstimationInitializationExpression("c4", "U(1, 5)"); - pm.setParameterEstimationInitializationExpression("c5", "U(1, 5)"); - - GeneralizedSemIm im = new GeneralizedSemIm(pm); - - print("True model: "); - print(im); - - DataSet data = im.simulateDataRecursive(1000, false); - - GeneralizedSemEstimator estimator = new GeneralizedSemEstimator(); - GeneralizedSemIm estIm = estimator.estimate(pm, data); - - print("\n\n\nEstimated model: "); - print(estIm); - print(estimator.getReport()); - - double aSquaredStar = estimator.getaSquaredStar(); - - assertEquals(.79, aSquaredStar, 0.01); - } catch (ParseException e) { - e.printStackTrace(); - } - } - - @Test - public void test16() { - RandomUtil.getInstance().setSeed(29999483L); - - try { - Node x1 = new GraphNode("X1"); - Node x2 = new GraphNode("X2"); - Node x3 = new GraphNode("X3"); - Node x4 = new GraphNode("X4"); - - Graph g = new EdgeListGraph(); - g.addNode(x1); - g.addNode(x2); - g.addNode(x3); - g.addNode(x4); - - g.addDirectedEdge(x1, x2); - g.addDirectedEdge(x2, x3); - g.addDirectedEdge(x3, x4); - g.addDirectedEdge(x1, x4); - - GeneralizedSemPm pm = new GeneralizedSemPm(g); - - pm.setNodeExpression(x1, "E_X1"); - pm.setNodeExpression(x2, "a1 * X1 + E_X2"); - pm.setNodeExpression(x3, "a2 * X2 + E_X3"); - pm.setNodeExpression(x4, "a3 * X1 + a4 * X3 ^ 2 + E_X4"); - - pm.setNodeExpression(pm.getErrorNode(x1), "N(0, c1)"); - pm.setNodeExpression(pm.getErrorNode(x2), "N(0, c2)"); - pm.setNodeExpression(pm.getErrorNode(x3), "N(0, c3)"); - pm.setNodeExpression(pm.getErrorNode(x4), "N(0, c4)"); - - GeneralizedSemIm im = new GeneralizedSemIm(pm); - - im.setParameterValue("a1", 1); - im.setParameterValue("a2", 1); - im.setParameterValue("a3", 1); - im.setParameterValue("a4", 1); - im.setParameterValue("c1", 1); - im.setParameterValue("c2", 1); - im.setParameterValue("c3", 1); - im.setParameterValue("c4", 1); - - print("True model: "); - print(im); - - DataSet data = im.simulateDataRecursive(1000, false); - - GeneralizedSemIm imInit = new GeneralizedSemIm(pm); - - imInit.setParameterValue("a1", .5); - imInit.setParameterValue("a2", .5); - imInit.setParameterValue("a3", .5); - imInit.setParameterValue("a4", .7); - imInit.setParameterValue("c1", 2); - imInit.setParameterValue("c2", 2); - imInit.setParameterValue("c3", 2); - imInit.setParameterValue("c4", 2); - - GeneralizedSemEstimator estimator = new GeneralizedSemEstimator(); - GeneralizedSemIm estIm = estimator.estimate(pm, data); - - print("\n\n\nEstimated model: "); - print(estIm); - print(estimator.getReport()); - - double aSquaredStar = estimator.getaSquaredStar(); - - assertEquals(50.38, aSquaredStar, 0.01); - } catch (ParseException e) { - e.printStackTrace(); - } - } - - @Test - public void test17() { - RandomUtil.getInstance().setSeed(29999483L); - - try { - Node x1 = new GraphNode("X1"); - Node x2 = new GraphNode("X2"); - Node x3 = new GraphNode("X3"); - Node x4 = new GraphNode("X4"); - - Graph g = new EdgeListGraph(); - g.addNode(x1); - g.addNode(x2); - g.addNode(x3); - g.addNode(x4); - - g.addDirectedEdge(x1, x2); - g.addDirectedEdge(x2, x3); - g.addDirectedEdge(x3, x4); - g.addDirectedEdge(x1, x4); - - GeneralizedSemPm pm = new GeneralizedSemPm(g); - - pm.setNodeExpression(x1, "E_X1"); - pm.setNodeExpression(x2, "a1 * X1 + E_X2"); - pm.setNodeExpression(x3, "a2 * X2 + E_X3"); - pm.setNodeExpression(x4, "a3 * X1 * a3 * a4 * X3 + E_X4"); - - pm.setNodeExpression(pm.getErrorNode(x1), "N(0, c1)"); - pm.setNodeExpression(pm.getErrorNode(x2), "N(0, c2)"); - pm.setNodeExpression(pm.getErrorNode(x3), "N(0, c3)"); - pm.setNodeExpression(pm.getErrorNode(x4), "N(0, c4)"); - - GeneralizedSemIm im = new GeneralizedSemIm(pm); - - im.setParameterValue("a1", 1); - im.setParameterValue("a2", 1); - im.setParameterValue("a3", 1); - im.setParameterValue("a4", 1); - im.setParameterValue("c1", 1); - im.setParameterValue("c2", 1); - im.setParameterValue("c3", 1); - im.setParameterValue("c4", 1); - - print("True model: "); - print(im); - - DataSet data = im.simulateDataRecursive(1000, false); - - GeneralizedSemIm imInit = new GeneralizedSemIm(pm); - - imInit.setParameterValue("a1", RandomUtil.getInstance().nextUniform(-3, 3)); - imInit.setParameterValue("a2", RandomUtil.getInstance().nextUniform(-3, 3)); - imInit.setParameterValue("a3", RandomUtil.getInstance().nextUniform(-3, 3)); - imInit.setParameterValue("a4", RandomUtil.getInstance().nextUniform(-3, 3)); - imInit.setParameterValue("c1", RandomUtil.getInstance().nextUniform(1, 3)); - imInit.setParameterValue("c2", RandomUtil.getInstance().nextUniform(1, 3)); - imInit.setParameterValue("c3", RandomUtil.getInstance().nextUniform(1, 3)); - imInit.setParameterValue("c4", RandomUtil.getInstance().nextUniform(1, 3)); - - GeneralizedSemEstimator estimator = new GeneralizedSemEstimator(); - GeneralizedSemIm estIm = estimator.estimate(pm, data); - - print("\n\n\nEstimated model: "); - print(estIm); - print(estimator.getReport()); - - double aSquaredStar = estimator.getaSquaredStar(); - - assertEquals(14.26, aSquaredStar, 0.01); - } catch (ParseException e) { - e.printStackTrace(); - } } private GeneralizedSemPm makeTypicalPm() { diff --git a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGraphUtils.java b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGraphUtils.java index efebaeaa34..eadcca6cc8 100644 --- a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGraphUtils.java +++ b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestGraphUtils.java @@ -23,6 +23,7 @@ import edu.cmu.tetrad.data.ContinuousVariable; import edu.cmu.tetrad.graph.*; +import edu.cmu.tetrad.search.utils.GraphSearchUtils; import edu.cmu.tetrad.util.RandomUtil; import org.junit.Test; @@ -273,6 +274,12 @@ public void test8() { } } + @Test + public void test9() { + Graph graph = GraphUtils.convert("X1---X2,X2---X3, X3---X4, X4---X1"); + assert(!GraphSearchUtils.isPdag(graph)); + } + private Set set(Node... z) { Set list = new HashSet<>(); Collections.addAll(list, z); diff --git a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestIndTestFisherGeneralizedInverse.java b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestIndTestFisherGeneralizedInverse.java index 7cc0119326..ce0a50e167 100644 --- a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestIndTestFisherGeneralizedInverse.java +++ b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestIndTestFisherGeneralizedInverse.java @@ -23,9 +23,8 @@ import edu.cmu.tetrad.data.DataSet; import edu.cmu.tetrad.graph.*; -import edu.cmu.tetrad.search.IndependenceTest; +import edu.cmu.tetrad.search.test.IndTestFisherZ; import edu.cmu.tetrad.search.test.IndependenceResult; -import edu.cmu.tetrad.search.work_in_progress.IndTestFisherZGeneralizedInverse; import edu.cmu.tetrad.sem.SemIm; import edu.cmu.tetrad.sem.SemPm; import edu.cmu.tetrad.util.RandomUtil; @@ -77,8 +76,11 @@ public void testDirections() { DataSet data1 = im1.simulateData(500, false); DataSet data2 = im2.simulateData(500, false); - IndependenceTest test1 = new IndTestFisherZGeneralizedInverse(data1, 0.05); - IndependenceTest test2 = new IndTestFisherZGeneralizedInverse(data2, 0.05); + IndTestFisherZ test1 = new IndTestFisherZ(data1, 0.05); + IndTestFisherZ test2 = new IndTestFisherZ(data2, 0.05); + + test1.setUsePseudoinverse(true); + test2.setUsePseudoinverse(true); IndependenceResult result1 = test1.checkIndependence(data1.getVariable(x.getName()), data1.getVariable(y.getName())); double p1 = result1.getPValue(); diff --git a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestIndTestWaldLr.java b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestIndTestWaldLr.java deleted file mode 100644 index 1422e9ac42..0000000000 --- a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestIndTestWaldLr.java +++ /dev/null @@ -1,118 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// 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.test; - -import edu.cmu.tetrad.data.ContinuousVariable; -import edu.cmu.tetrad.data.DataSet; -import edu.cmu.tetrad.data.Discretizer; -import edu.cmu.tetrad.graph.Graph; -import edu.cmu.tetrad.graph.Node; -import edu.cmu.tetrad.graph.RandomGraph; -import edu.cmu.tetrad.search.IndependenceTest; -import edu.cmu.tetrad.search.test.MsepTest; -import edu.cmu.tetrad.sem.SemIm; -import edu.cmu.tetrad.sem.SemPm; -import edu.cmu.tetrad.util.RandomUtil; -import edu.pitt.csb.mgm.IndTestMultinomialLogisticRegressionWald; -import org.junit.Ignore; -import org.junit.Test; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import static org.junit.Assert.assertEquals; - - -/** - * Tests the IndTestTimeSeries class. - * - * @author josephramsey - */ -@Ignore -public class TestIndTestWaldLr { - - @Test - public void testIsIndependent() { - RandomUtil.getInstance().setSeed(1450705713157L); - - int numPassed = 0; - - for (int i = 0; i < 10; i++) { - List nodes = new ArrayList<>(); - - for (int i1 = 0; i1 < 10; i1++) { - nodes.add(new ContinuousVariable("X" + (i1 + 1))); - } - - Graph graph = RandomGraph.randomGraph(nodes, 0, 10, - 3, 3, 3, false); - SemPm pm = new SemPm(graph); - SemIm im = new SemIm(pm); - DataSet data = im.simulateData(1000, false); - - Discretizer discretizer = new Discretizer(data); - discretizer.setVariablesCopied(true); - discretizer.equalCounts(data.getVariable(0), 2); - discretizer.equalCounts(data.getVariable(3), 2); - data = discretizer.discretize(); - - Node x1 = data.getVariable("X1"); - Node x2 = data.getVariable("X2"); - Node x3 = data.getVariable("X3"); - Node x4 = data.getVariable("X4"); - Node x5 = data.getVariable("X5"); - - Set cond = new HashSet<>(); - cond.add(x3); - cond.add(x4); - cond.add(x5); - - Node x1Graph = graph.getNode(x1.getName()); - Node x2Graph = graph.getNode(x2.getName()); - - Set condGraph = new HashSet<>(); - - for (Node node : cond) { - condGraph.add(graph.getNode(node.getName())); - } - - // Using the Wald LR test since it's most up to date. - IndependenceTest test = new IndTestMultinomialLogisticRegressionWald(data, 0.05, false); - MsepTest msep = new MsepTest(graph); - - boolean correct = test.checkIndependence(x2, x1, cond) == msep.checkIndependence(x2Graph, x1Graph, condGraph); - - if (correct) { - numPassed++; - } - } - -// System.out.println(RandomUtil.getInstance().getSeed()); - - // Do not always get all 10. - assertEquals(10, numPassed); - } -} - - diff --git a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestMimbuild.java b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestMimbuild.java deleted file mode 100644 index 1b71ba7542..0000000000 --- a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestMimbuild.java +++ /dev/null @@ -1,202 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// 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.test; - -import edu.cmu.tetrad.data.Clusters; -import edu.cmu.tetrad.data.CovarianceMatrix; -import edu.cmu.tetrad.data.DataGraphUtils; -import edu.cmu.tetrad.data.DataSet; -import edu.cmu.tetrad.graph.Graph; -import edu.cmu.tetrad.graph.Node; -import edu.cmu.tetrad.graph.NodeType; -import edu.cmu.tetrad.search.Bpc; -import edu.cmu.tetrad.search.Fofc; -import edu.cmu.tetrad.search.Mimbuild; -import edu.cmu.tetrad.search.MimbuildTrek; -import edu.cmu.tetrad.search.utils.BpcTestType; -import edu.cmu.tetrad.search.utils.GraphSearchUtils; -import edu.cmu.tetrad.search.utils.MimUtils; -import edu.cmu.tetrad.sem.ReidentifyVariables; -import edu.cmu.tetrad.sem.SemIm; -import edu.cmu.tetrad.sem.SemPm; -import edu.cmu.tetrad.util.Parameters; -import edu.cmu.tetrad.util.RandomUtil; -import org.junit.Ignore; -import org.junit.Test; - -import java.io.IOException; -import java.rmi.MarshalledObject; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; - -import static org.junit.Assert.assertEquals; - - -/** - * @author josephramsey - */ -@Ignore -public class TestMimbuild { - - @Test - public void test1() { - RandomUtil.getInstance().setSeed(49283494L); - - for (int r = 0; r < 1; r++) { - Graph mim = DataGraphUtils.randomSingleFactorModel(5, 5, 6, 0, 0, 0); - - Graph mimStructure = structure(mim); - - Parameters params = new Parameters(); - params.set("coefLow", 0.0); - params.set("coefHigh", 1.0); - - SemPm pm = new SemPm(mim); - SemIm im = new SemIm(pm, params); - DataSet data = im.simulateData(300, false); - - final String algorithm = "FOFC"; - Graph searchGraph; - List> partition; - - if (algorithm.equals("FOFC")) { - Fofc fofc = new Fofc(data, BpcTestType.TETRAD_WISHART, - Fofc.Algorithm.GAP, 0.001); - searchGraph = fofc.search(); - partition = fofc.getClusters(); - } else if (algorithm.equals("BPC")) { - final BpcTestType testType = BpcTestType.TETRAD_WISHART; - final BpcTestType purifyType = BpcTestType.TETRAD_BASED; - - Bpc bpc = new Bpc( - data, 0.001, - testType - ); - searchGraph = bpc.search(); - - partition = MimUtils.convertToClusters2(searchGraph); - } else { - throw new IllegalStateException(); - } - - List latentVarList = reidentifyVariables(mim, data, partition); - - Graph mimbuildStructure; - - for (int mimbuildMethod : new int[]{2}) { - if (mimbuildMethod == 2) { - Mimbuild mimbuild = new Mimbuild(); - mimbuild.setPenaltyDiscount(1); - mimbuild.setMinClusterSize(3); - mimbuildStructure = mimbuild.search(partition, latentVarList, new CovarianceMatrix(data)); - int shd = GraphSearchUtils.structuralHammingDistance(mimStructure, mimbuildStructure); - assertEquals(7, shd); - } else if (mimbuildMethod == 3) { -// System.out.println("Mimbuild Trek\n"); - MimbuildTrek mimbuild = new MimbuildTrek(); - mimbuild.setAlpha(0.1); - mimbuild.setMinClusterSize(3); - mimbuildStructure = mimbuild.search(partition, latentVarList, new CovarianceMatrix(data)); - int shd = GraphSearchUtils.structuralHammingDistance(mimStructure, mimbuildStructure); - assertEquals(3, shd); - } else { - throw new IllegalStateException(); - } - } - - } - - } - - - private Graph changeLatentNames(Graph full, Clusters measurements, List latentVarList) { - Graph g2 = null; - - try { - g2 = (Graph) new MarshalledObject(full).get(); - } catch (IOException | ClassNotFoundException e) { - e.printStackTrace(); - } - - for (int i = 0; i < measurements.getNumClusters(); i++) { - List d = measurements.getCluster(i); - String latentName = latentVarList.get(i); - - for (Node node : full.getNodes()) { - if (!(node.getNodeType() == NodeType.LATENT)) { - continue; - } - - List _children = new ArrayList<>(full.getChildren(node)); - - _children.removeAll(ReidentifyVariables.getLatents(full)); - - List childNames = getNames(_children); - - if (new HashSet<>(childNames).equals(new HashSet<>(d))) { - assert g2 != null; - g2.getNode(node.getName()).setName(latentName); - } - } - } - - return g2; - } - - private List getNames(List nodes) { - List names = new ArrayList<>(); - for (Node node : nodes) { - names.add(node.getName()); - } - return names; - } - - - private List reidentifyVariables(Graph mim, DataSet data, List> partition) { - List latentVarList = null; - - if (2 == 1) { - latentVarList = ReidentifyVariables.reidentifyVariables1(partition, mim); - } else if (2 == 2) { - latentVarList = ReidentifyVariables.reidentifyVariables2(partition, mim, data); - } else { - throw new IllegalStateException(); - } - - return latentVarList; - } - - private Graph structure(Graph mim) { - List latents = new ArrayList<>(); - - for (Node node : mim.getNodes()) { - if (node.getNodeType() == NodeType.LATENT) { - latents.add(node); - } - } - - return mim.subgraph(latents); - } -} - - diff --git a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestPurify.java b/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestPurify.java deleted file mode 100644 index 6850c5f16b..0000000000 --- a/tetrad-lib/src/test/java/edu/cmu/tetrad/test/TestPurify.java +++ /dev/null @@ -1,317 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// 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.test; - -import edu.cmu.tetrad.data.CovarianceMatrix; -import edu.cmu.tetrad.data.DataGraphUtils; -import edu.cmu.tetrad.data.DataSet; -import edu.cmu.tetrad.graph.*; -import edu.cmu.tetrad.search.Mimbuild; -import edu.cmu.tetrad.search.utils.*; -import edu.cmu.tetrad.sem.SemIm; -import edu.cmu.tetrad.sem.SemPm; -import edu.cmu.tetrad.util.RandomUtil; -import org.junit.Ignore; -import org.junit.Test; - -import java.util.ArrayList; -import java.util.List; - -import static org.junit.Assert.assertEquals; - -/** - * @author josephramsey - */ -@Ignore -public class TestPurify { - - @Test - public void test1() { - RandomUtil.getInstance().setSeed(48290483L); - - SemGraph graph = new SemGraph(); - - Node l1 = new GraphNode("L1"); - l1.setNodeType(NodeType.LATENT); - - Node l2 = new GraphNode("L2"); - l2.setNodeType(NodeType.LATENT); - - Node l3 = new GraphNode("L3"); - l3.setNodeType(NodeType.LATENT); - - Node x1 = new GraphNode("X1"); - Node x2 = new GraphNode("X2"); - Node x3 = new GraphNode("X3"); - Node x4 = new GraphNode("X4"); - Node x4b = new GraphNode("X4b"); - - Node x5 = new GraphNode("X5"); - Node x6 = new GraphNode("X6"); - Node x7 = new GraphNode("X7"); - Node x8 = new GraphNode("X8"); - Node x8b = new GraphNode("X8b"); - - Node x9 = new GraphNode("X9"); - Node x10 = new GraphNode("X10"); - Node x11 = new GraphNode("X11"); - Node x12 = new GraphNode("X12"); - Node x12b = new GraphNode("X12b"); - - graph.addNode(l1); - graph.addNode(l2); - graph.addNode(l3); - - graph.addNode(x1); - graph.addNode(x2); - graph.addNode(x3); - graph.addNode(x4); - graph.addNode(x4b); - - graph.addNode(x5); - graph.addNode(x6); - graph.addNode(x7); - graph.addNode(x8); - graph.addNode(x8b); - - graph.addNode(x9); - graph.addNode(x10); - graph.addNode(x11); - graph.addNode(x12); - graph.addNode(x12b); - - graph.addDirectedEdge(l1, x1); - graph.addDirectedEdge(l1, x2); - graph.addDirectedEdge(l1, x3); - graph.addDirectedEdge(l1, x4); - graph.addDirectedEdge(l1, x4b); - graph.addDirectedEdge(l1, x5); - - graph.addDirectedEdge(l2, x5); - graph.addDirectedEdge(l2, x6); - graph.addDirectedEdge(l2, x7); - graph.addDirectedEdge(l2, x8); - graph.addDirectedEdge(l2, x8b); - - graph.addDirectedEdge(l3, x9); - graph.addDirectedEdge(l3, x10); - graph.addDirectedEdge(l3, x11); - graph.addDirectedEdge(l3, x12); - graph.addDirectedEdge(l3, x12b); - - graph.addDirectedEdge(x1, x4); - - SemPm pm = new SemPm(graph); - SemIm im = new SemIm(pm); - DataSet data = im.simulateData(1000, false); - - List> partition = new ArrayList<>(); - - List cluster1 = new ArrayList<>(); - cluster1.add(x1); - cluster1.add(x2); - cluster1.add(x3); - cluster1.add(x4); - cluster1.add(x4b); - cluster1.add(x5); - - List cluster2 = new ArrayList<>(); - cluster2.add(x5); - cluster2.add(x6); - cluster2.add(x7); - cluster2.add(x8); - cluster2.add(x8b); - - List cluster3 = new ArrayList<>(); - cluster3.add(x9); - cluster3.add(x10); - cluster3.add(x11); - cluster3.add(x12); - cluster3.add(x12b); - - partition.add(cluster1); - partition.add(cluster2); - partition.add(cluster3); - - TetradTest test = new TetradTestContinuous(data, BpcTestType.TETRAD_WISHART, 0.05); - IPurify purify = new PurifyTetradBased(test); - purify.setTrueGraph(graph); - - List> partition2 = purify.purify(partition); - - assertEquals(3, partition2.get(0).size()); - assertEquals(2, partition2.get(1).size()); - assertEquals(5, partition2.get(2).size()); - } - - @Test - public void test1b() { - RandomUtil.getInstance().setSeed(48290483L); - - SemGraph graph = new SemGraph(); - - Node l1 = new GraphNode("L1"); - l1.setNodeType(NodeType.LATENT); - - Node l2 = new GraphNode("L2"); - l2.setNodeType(NodeType.LATENT); - - Node x1 = new GraphNode("X1"); - Node x2 = new GraphNode("X2"); - Node x3 = new GraphNode("X3"); - Node x4 = new GraphNode("X4"); - Node x5 = new GraphNode("X5"); - Node x6 = new GraphNode("X6"); - - Node x7 = new GraphNode("X7"); - Node x8 = new GraphNode("X8"); - Node x9 = new GraphNode("X9"); - Node x10 = new GraphNode("X10"); - Node x11 = new GraphNode("X11"); - Node x12 = new GraphNode("X12"); - - graph.addNode(l1); - graph.addNode(l2); - - graph.addNode(x1); - graph.addNode(x2); - graph.addNode(x3); - graph.addNode(x4); - graph.addNode(x5); - graph.addNode(x6); - - graph.addNode(x7); - graph.addNode(x8); - graph.addNode(x9); - graph.addNode(x10); - graph.addNode(x11); - graph.addNode(x12); - - graph.addDirectedEdge(l1, x1); - graph.addDirectedEdge(l1, x2); - graph.addDirectedEdge(l1, x3); - graph.addDirectedEdge(l1, x4); - graph.addDirectedEdge(l1, x5); - graph.addDirectedEdge(l1, x5); - graph.addDirectedEdge(l1, x6); - - graph.addDirectedEdge(l2, x6); - graph.addDirectedEdge(l2, x7); - graph.addDirectedEdge(l2, x8); - graph.addDirectedEdge(l2, x9); - graph.addDirectedEdge(l2, x10); - graph.addDirectedEdge(l2, x11); - graph.addDirectedEdge(l2, x12); - - graph.addDirectedEdge(x3, x4); - graph.addDirectedEdge(x9, x10); - - SemPm pm = new SemPm(graph); - SemIm im = new SemIm(pm); - DataSet data = im.simulateData(3000, false); - - List> partition = new ArrayList<>(); - - List cluster1 = new ArrayList<>(); - cluster1.add(x1); - cluster1.add(x2); - cluster1.add(x3); - cluster1.add(x4); - cluster1.add(x5); - - List cluster2 = new ArrayList<>(); - cluster2.add(x7); - cluster2.add(x8); - cluster2.add(x9); - cluster2.add(x10); - cluster2.add(x11); - cluster2.add(x12); - - partition.add(cluster1); - partition.add(cluster2); - - TetradTest test = new TetradTestContinuous(data, BpcTestType.TETRAD_WISHART, 0.0001); - IPurify purify = new PurifyTetradBased(test); - purify.setTrueGraph(graph); - - List> clustering = purify.purify(partition); - - assertEquals(4, clustering.get(0).size()); - assertEquals(5, clustering.get(1).size()); - - } - - @Test - public void test2() { - RandomUtil.getInstance().setSeed(48290483L); - - Graph graph = new EdgeListGraph(DataGraphUtils.randomSingleFactorModel(3, 3, 5, 0, 0, 0)); - - SemPm pm = new SemPm(graph); - SemIm im = new SemIm(pm); - DataSet data = im.simulateData(1000, false); - - List latents = new ArrayList<>(); - - for (Node node : graph.getNodes()) { - if (node.getNodeType() == NodeType.LATENT) latents.add(node); - } - - Graph structuralGraph = graph.subgraph(latents); - - List> clustering = new ArrayList<>(); - - for (Node node : latents) { - List adj = new ArrayList<>(graph.getAdjacentNodes(node)); - adj.removeAll(latents); - - clustering.add(adj); - } - - TetradTestContinuous test = new TetradTestContinuous(data, BpcTestType.TETRAD_WISHART, 0.001); - - IPurify purify = new PurifyTetradBased(test); - - List> purifiedClustering = purify.purify(clustering); - List latentsNames = new ArrayList<>(); - - for (Node latent : latents) { - latentsNames.add(latent.getName()); - } - - Mimbuild mimbuild = new Mimbuild(); - mimbuild.setPenaltyDiscount(1); - Graph _graph = mimbuild.search(purifiedClustering, latentsNames, new CovarianceMatrix(data)); - - List _latents = new ArrayList<>(); - - for (Node node : _graph.getNodes()) { - if (node.getNodeType() == NodeType.LATENT) _latents.add(node); - } - - Graph _structuralGraph = _graph.subgraph(_latents); - - assertEquals(2, _structuralGraph.getNumEdges()); - } -} - -