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

edu.cmu.tetrad.graph.Edge Maven / Gradle / Ivy

///////////////////////////////////////////////////////////////////////////////
// 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.graph;

import edu.cmu.tetrad.graph.EdgeTypeProbability.EdgeType;
import edu.cmu.tetrad.util.TetradSerializable;

import java.awt.*;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * Represents an edge node1 *-# node2 where * and # are endpoints of type Endpoint--that is, Endpoint.TAIL,
 * Endpoint.ARROW, or Endpoint.CIRCLE.
 * 

* Note that because speed is of the essence, and Edge cannot be compared to an object of any other type; this will * throw an exception. * * @author josephramsey */ public class Edge implements TetradSerializable, Comparable { private static final long serialVersionUID = 23L; private final Node node1; private final Node node2; private Endpoint endpoint1; private Endpoint endpoint2; // Usual coloring--set to something else for a special line color. private transient Color lineColor; private boolean bold = false; private boolean highlighted = false; private List properties = new ArrayList<>(); private List edgeTypeProbabilities = new ArrayList<>(); private double probability; /** * Constructs a new edge by specifying the nodes it connects and the endpoint types. * * @param node1 the first node * @param node2 the second node _ * @param endpoint1 the endpoint at the first node * @param endpoint2 the endpoint at the second node */ public Edge(Node node1, Node node2, Endpoint endpoint1, Endpoint endpoint2) { if (node1 == null || node2 == null) { throw new NullPointerException("Nodes must not be null. node1 = " + node1 + " node2 = " + node2); } if (endpoint1 == null || endpoint2 == null) { throw new NullPointerException("Endpoints must not be null."); } // Flip edges pointing left the other way. if (pointingLeft(endpoint1, endpoint2)) { this.node1 = node2; this.node2 = node1; this.endpoint1 = endpoint2; this.endpoint2 = endpoint1; } else { this.node1 = node1; this.node2 = node2; this.endpoint1 = endpoint1; this.endpoint2 = endpoint2; } } // =========================CONSTRUCTORS============================// public Edge(Edge edge) { this(edge.node1, edge.node2, edge.endpoint1, edge.endpoint2); this.lineColor = edge.getLineColor(); this.bold = edge.bold; this.highlighted = edge.highlighted; this.properties = new ArrayList<>(edge.properties); this.edgeTypeProbabilities = new ArrayList<>(edge.edgeTypeProbabilities); this.probability = edge.probability; } /** * Generates a simple exemplar of this class to test serialization. */ public static Edge serializableInstance() { return new Edge(GraphNode.serializableInstance(), GraphNode.serializableInstance(), Endpoint.ARROW, Endpoint.ARROW); } /** * @return the A node. */ public final Node getNode1() { return this.node1; } // ==========================PUBLIC METHODS===========================// /** * @return the B node. */ public final Node getNode2() { return this.node2; } /** * @return the endpoint of the edge at the A node. */ public final Endpoint getEndpoint1() { return this.endpoint1; } public final void setEndpoint1(Endpoint e) { this.endpoint1 = e; } /** * @return the endpoint of the edge at the B node. */ public final Endpoint getEndpoint2() { return this.endpoint2; } public final void setEndpoint2(Endpoint e) { this.endpoint2 = e; } /** * @return the endpoint nearest to the given node. * @throws IllegalArgumentException if the given node is not along the edge. */ public final Endpoint getProximalEndpoint(Node node) { if (this.node1 == node) { return getEndpoint1(); } else if (this.node2 == node) { return getEndpoint2(); } return null; } /** * @return the endpoint furthest from the given node. * @throws IllegalArgumentException if the given node is not along the edge. */ public final Endpoint getDistalEndpoint(Node node) { if (this.node1 == node) { return getEndpoint2(); } else if (this.node2 == node) { return getEndpoint1(); } return null; } /** * Traverses the edge in an undirected fashion--given one node along the edge, returns the node at the opposite end * of the edge. */ public final Node getDistalNode(Node node) { if (this.node1 == node) { return this.node2; } if (this.node2 == node) { return this.node1; } return null; } /** * @return true just in case this edge is directed. */ public boolean isDirected() { return Edges.isDirectedEdge(this); } /** * @return true just in case the edge is pointing toward the given node-- that is, x --> node or x o--> node. */ public boolean pointsTowards(Node node) { Endpoint proximal = getProximalEndpoint(node); Endpoint distal = getDistalEndpoint(node); return (proximal == Endpoint.ARROW && (distal == Endpoint.TAIL || distal == Endpoint.CIRCLE)); } /** * @return the edge with endpoints reversed. */ public Edge reverse() { return new Edge(getNode2(), getNode1(), getEndpoint1(), getEndpoint2()); } /** * Produces a string representation of the edge. */ public final String toString() { StringBuilder buf = new StringBuilder(); Endpoint endptTypeA = getEndpoint1(); Endpoint endptTypeB = getEndpoint2(); buf.append(getNode1()); buf.append(" "); if (isNull()) { buf.append("..."); } else { if (endptTypeA == Endpoint.TAIL) { buf.append("-"); } else if (endptTypeA == Endpoint.ARROW) { buf.append("<"); } else if (endptTypeA == Endpoint.CIRCLE) { buf.append("o"); } buf.append("-"); if (endptTypeB == Endpoint.TAIL) { buf.append("-"); } else if (endptTypeB == Endpoint.ARROW) { buf.append(">"); } else if (endptTypeB == Endpoint.CIRCLE) { buf.append("o"); } } buf.append(" "); buf.append(getNode2()); // Bootstrapping edge type distribution List edgeTypeDist = getEdgeTypeProbabilities(); if (edgeTypeDist.size() > 0) { buf.append(" "); String n1 = getNode1().getName(); String n2 = getNode2().getName(); for (EdgeTypeProbability etp : edgeTypeDist) { double prob = etp.getProbability(); if (prob > 0) { StringBuilder _type = new StringBuilder("" + etp.getEdgeType()); switch (etp.getEdgeType()) { case nil: _type = new StringBuilder("no edge"); break; case ta: _type = new StringBuilder("-->"); break; case at: _type = new StringBuilder("<--"); break; case ca: _type = new StringBuilder("o->"); break; case ac: _type = new StringBuilder("<-o"); break; case cc: _type = new StringBuilder("o-o"); break; case aa: _type = new StringBuilder("<->"); break; case tt: _type = new StringBuilder("---"); break; default: break; } if (etp.getEdgeType() != EdgeType.nil) { _type = new StringBuilder(n1 + " " + _type + " " + n2); } List properties = etp.getProperties(); if (properties != null && properties.size() > 0) { for (Property property : properties) { _type.append(" ").append(property.toString()); } } buf.append("[").append(_type).append("]:").append(String.format("%.4f", prob)).append(";"); } } if (probability > 0.0) { buf.append(String.format("[edge]:%.4f", probability)); } } List properties = getProperties(); if (properties != null && properties.size() > 0) { for (Property property : properties) { buf.append(" "); buf.append(property.toString()); } } return buf.toString(); } public final int hashCode() { return 1; } /** * Two edges are equal just in case they connect the same nodes and have the same endpoints proximal to each node. */ public final boolean equals(Object o) { if (o == null) return false; if (!(o instanceof Edge)) return false; Edge edge = (Edge) o; // Equality of nodes can only dependent on the object identity of the // nodes, not on their name. Otherwise, the identity of an edge could be // changed by changing the name of one of its nodes. Node node1 = getNode1(); Node node2 = getNode2(); Node node1b = edge.getNode1(); Node node2b = edge.getNode2(); Endpoint end1 = getEndpoint1(); Endpoint end2 = getEndpoint2(); Endpoint end1b = edge.getEndpoint1(); Endpoint end2b = edge.getEndpoint2(); boolean equals1 = node1 == node1b && node2 == node2b && end1 == end1b && end2 == end2b; boolean equals2 = node1 == node2b && node2 == node1b && end1 == end2b && end2 == end1b; return equals1 || equals2; } public int compareTo(Edge _edge) { int comp1 = getNode1().compareTo(_edge.getNode1()); if (comp1 != 0) { return comp1; } return getNode2().compareTo(_edge.getNode2()); } private boolean pointingLeft(Endpoint endpoint1, Endpoint endpoint2) { return (endpoint1 == Endpoint.ARROW && (endpoint2 == Endpoint.TAIL || endpoint2 == Endpoint.CIRCLE)); } // ===========================PRIVATE METHODS===========================// /** * 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(); if (this.node1 == null) { throw new NullPointerException(); } if (this.node2 == null) { throw new NullPointerException(); } if (this.endpoint1 == null) { throw new NullPointerException(); } if (this.endpoint2 == null) { throw new NullPointerException(); } } public boolean isNull() { return this.endpoint1 == Endpoint.NULL && this.endpoint2 == Endpoint.NULL; } public Color getLineColor() { return this.lineColor; } public void addProperty(Property property) { if (!this.properties.contains(property)) { this.properties.add(property); } } public ArrayList getProperties() { return new ArrayList<>(this.properties); } public void addEdgeTypeProbability(EdgeTypeProbability prob) { if (!this.edgeTypeProbabilities.contains(prob)) { this.edgeTypeProbabilities.add(prob); } } public List getEdgeTypeProbabilities() { return this.edgeTypeProbabilities; } public double getProbability() { return probability; } public void setProbability(double probability) { this.probability = probability; } public boolean isHighlighted() { return highlighted; } public void setHighlighted(boolean highlighted) { this.highlighted = highlighted; } public enum Property { dd, nl, pd, pl } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy