/*
Copyright 2008-2010 Gephi
Authors : Mathieu Bastian <mathieu.bastian@gephi.org>
Website : http://www.gephi.org
This file is part of Gephi.
Gephi is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
Gephi 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Gephi. If not, see <http://www.gnu.org/licenses/>.
*/
package org.gephi.graph.api;
/**
* Implementation of graphs within graphs concept, by proposing methods to manipulate
* the hierarchy of nodes.
* <p>
* The hierarchical graph maintains a tree of all nodes, it's the hierarchy and a
* <b>in-view</b> flag for each. Note that 'view' means something else than for
* <code>GraphView</code>.
* <p>
* A node in the hierarchy view means it is visible and none of its ancestors or
* descendants are. If this node is expanded, it's children become 'in-view'. If it is
* retracted, its parent becomes 'in-view'. The hierarchy view can be modified with
* <code>expand()</code>, <code>retract()</code>, <code>resetViewToLeaves()</code>,
* <code>resetViewToTopNodes()</code> and <code>resetViewToLevel()</code>. Note that
* the nodes and edges returns by <code>getNodes()</code> or <code>getEdges()</code>
* use only nodes in the current view. To get all nodes in the hierarchy, see
* <code>getNodesTree()</code>.
*
* @author Mathieu Bastian
* @see GraphModel
*/
public interface HierarchicalGraph extends Graph {
/**
* Add <code>node</code> as a child of <code>parent</code> in the graph. If <code>parent</code> is
* <code>null</code>, <code>node</code> is added as a child of the (virtual) root node.
* Fails if the node already exists.
* @param node the node to add
* @param parent the existing node whose a child is to be added or <code>null</code>
* @return <code>true</code> if add is successful, false otherwise
* @throws IllegalArgumentException if <code>node</code> is <code>null</code>,
* or if <code>parent</code> is not legal in the graph
* @throws IllegalMonitorStateException if the current thread is holding a read lock
*/
public boolean addNode(Node node, Node parent);
/**
* Remove <code>metaEdge</code> from the graph. Fails if the edge doesn't exist.
* @param metaEdge the meta edge that is to be removed
* @return <code>true</code> if remove is successful, false otherwise
* @throws IllegalArgumentException if <code>edge</code> is <code>null</code> or nodes not legal in
* the graph
* @throws IllegalMonitorStateException if the current thread is holding a read lock
*/
public boolean removeMetaEdge(Edge metaEdge);
/**
* Returns the number of children of <code>node</code>. Returns <code>zero</code> if <code>node</code> is a leaf.
* <p><b>Warning:</b> This method is not thread safe, be sure to call it in a locked
* statement.
* @param node the node to be queried
* @return the number of <code>node</code>'s children
* @throws IllegalArgumentException if <code>node</code> is <code>null</code> or not legal in the graph
*/
public int getChildrenCount(Node node);
/**
* Returns the number of descendant of <code>node</code>. Returns <code>zero</code> if <code>node</code> is a leaf.
* <p><b>Warning:</b> This method is not thread safe, be sure to call it in a locked
* statement.
* @param node the node to be queried
* @return the number of <code>node</code>'s descendant
* @throws IllegalArgumentException if <code>node</code> is <code>null</code> or not legal in the graph
*/
public int getDescendantCount(Node node);
/**
* Returns the parent of <code>node</code> or <code>null</code> if <code>node</code>'s parent is (virtual) root.
* <p><b>Warning:</b> This method is not thread safe, be sure to call it in a locked
* statement.
* @param node the node whose parent is to be returned
* @return <code>node</code>'s parent
* @throws IllegalArgumentException if <code>node</code> is <code>null</code> or not legal in the graph
*/
public Node getParent(Node node);
/**
* Returns children of <code>node</code>.
* @param node the node whose children are to be returned
* @return a node iterable of <code>node</code>'s children
* @throws IllegalArgumentException if <code>node</code> is <code>null</code> or not legal in the graph
*/
public NodeIterable getChildren(Node node);
/**
* Returns descendants of <code>node</code>. Descendants are nodes which <code>node</code> is an ancestor.
* @param node the node whose descendant are to be returned
* @return a node iterable of <code>node</code>'s descendant
* @throws IllegalArgumentException if <code>node</code> is <code>null</code> or not legal in the graph
*/
public NodeIterable getDescendant(Node node);
/**
* Returns edges incident to <code>nodeGroup</code> and <code>nodeGroup</code>'s descendants. Edges connected
* to nodes which are not descendant of <code>nodeGroup</code> are excluded.
* @param nodeGroup the node whose inner edges are to be returned
* @return an edge iterable of edges inner <code>nodeGroup</code>
* @throws IllegalArgumentException if <code>nodeGroup</code> is <code>null</code> or not legal in the graph
*/
public EdgeIterable getInnerEdges(Node nodeGroup);
/**
* Returns edges <b>not</b> incident to <code>nodeGroup</code> or <code>nodeGroup</code>'s descendants.
* Edges connected to nodes which are descendant of <code>nodeGroup</code> are excluded.
* @param nodeGroup the node whose outer edges are to be returned
* @return an edge iterable of edges outer <code>nodeGroup</code>
* @throws IllegalArgumentException if <code>nodeGroup</code> is <code>null</code> or not legal in the graph
*/
public EdgeIterable getOuterEdges(Node nodeGroup);
/**
* Returns roots of the hierarchy forest. They are children of the tree's (virtual) root an have
* the level equal <code>zero</code>. If all nodes have the same level (i.e. no hierarchy) this
* method is similar as <code>getNodes()</code>.
* @return a node iterable of nodes at the top of the tree
*/
public NodeIterable getTopNodes();
/**
* Similar as {@link #getNodes()} but all nodes are visited, not only those in the current view.
* @return a node iterable of all nodes in the hierarchy
*/
public NodeIterable getNodesTree();
/**
* Similar as {@link #getEdges()} but all nodes are visited in the hierarchy, so
* it returns edges for all possible nodes.
* @return an edge iterable of all edges
*/
public EdgeIterable getEdgesTree();
/**
* Returns the number of edges and meta edges in the graph
* <p>
* Special case of interest:
* <ul><li>Count self-loops once only.</li>
* <li>For <b>hierarchical</b> graph, count edges incident only to nodes
* in the current view.</li></ul>
* <p><b>Warning:</b> This method is not thread safe, be sure to call it in a locked
* statement.
* @return the number of edges in the graph.
*/
public int getTotalEdgeCount();
/**
* Returns nodes at the given <code>level</code> in the hierarchy. Top nodes
* have the level <code>zero</code> and leaves' level is the height of the tree.
* @param level the level whose nodes are to be returned
* @return a node iterable of nodes located at <code>level</code> in the tree
* @throws IllegalArgumentException if <code>level</code> is not between 0 and the height of the tree
*/
public NodeIterable getNodes(int level);
/**
* The number of nodes located at the given <code>level</code> int the hierarchy. Similar as
* <code>getNodes(level).toArray().length</code>.
* <p><b>Warning:</b> This method is not thread safe, be sure to call it in a locked
* statement.
* @param level the level whose nodes are to be returned
* @return the number of nodes at <code>level</code>
* @throws IllegalArgumentException if <code>level</code> is not between 0 and the height of the tree
*/
public int getLevelSize(int level);
/**
* Returns <code>true</code> if <code>descendant</code> is a descendant of <code>node</code>. True if <code>node</code> is an ancestor
* of <code>descendant</code>.
* <p><b>Warning:</b> This method is not thread safe, be sure to call it in a locked
* statement.
* @param node the node to be queried
* @param descendant the descendant node to be queried
* @return <code>true</code> if <code>descendant</code> is a descendant of <code>node</code>
* @throws IllegalArgumentException if <code>node</code> or <code>descendant</code> is <code>null</code> or not legal in the graph
*/
public boolean isDescendant(Node node, Node descendant);
/**
* Returns <code>true</code> if <code>ancestor</code> is an ancestor of <code>node</code>. True if <code>node</code> is a descendant of
* <code>ancestor</code>.
* <p><b>Warning:</b> This method is not thread safe, be sure to call it in a locked
* statement.
* @param node the node to be queried
* @param ancestor the ancestor to be queried
* @return <code>true</code> if <code>ancestor</code> is an ancestor of <code>node</code>
* @throws IllegalArgumentException if <code>node</code> or <code>ancestor</code> is <code>null</code> or not legal in the graph
*/
public boolean isAncestor(Node node, Node ancestor);
/**
* Returns <code>true</code> if <code>following</code> is after <code>node</code>. The definition is similar to <code>XML</code> following
* axis. Is true when <code>following</code> has a greater <b>pre</b> and <b>post</b> order than <code>node</code>.
* <p><b>Warning:</b> This method is not thread safe, be sure to call it in a locked
* statement.
* @param node the node to be queried
* @param following the following to be queried
* @return <code>true</code> if <code>following</code> is following <code>node</code>
* @throws IllegalArgumentException if <code>node</code> or <code>following</code> is <code>null</code> or not legal in the graph
*/
public boolean isFollowing(Node node, Node following);
/**
* Returns <code>true</code> if <code>preceding</code> is before <code>node</code>. The definition is similar to <code>XML</code> preceding
* axis. Is true when <code>preceding</code> has a lower <b>pre</b> and <b>post</b> order than <code>node</code>.
* <p><b>Warning:</b> This method is not thread safe, be sure to call it in a locked
* statement.
* @param node the node to be queried
* @param preceding the preceding to be queried
* @return <code>true</code> if <code>preceding</code> is preceding <code>node</code>
* @throws IllegalArgumentException if <code>node</code> or <code>preceding</code> is <code>null</code> or not legal in the graph
*/
public boolean isPreceding(Node node, Node preceding);
/**
* Returns <code>true</code> if <code>parent</code> is the parent of <code>node</code>.
* <p><b>Warning:</b> This method is not thread safe, be sure to call it in a locked
* statement.
* @param node the node to be queried
* @param parent the parent to be queried
* @return <code>true</code> if <code>parent</code> is the parent of <code>node</code>
* @throws IllegalArgumentException if <code>node</code> or <code>parent</code> is <code>null</code> or not legal in the graph
*/
public boolean isParent(Node node, Node parent);
/**
* Returns the height of the tree. The height is <code>zero</code> when all nodes have the same level.
* <p><b>Warning:</b> This method is not thread safe, be sure to call it in a locked
* statement.
* @return the height of the tree
*/
public int getHeight();
/**
* Returns the level of <code>node</code> in the hierarchy. Roots have the level <code>zero</code> and it inscreases when going down
* in the tree.
* <p><b>Warning:</b> This method is not thread safe, be sure to call it in a locked
* statement.
* @param node the node to be queried
* @return the level value of <code>node</code>
* @throws IllegalArgumentException if <code>node</code> is <code>null</code> or not legal in the graph
*/
public int getLevel(Node node);
/**
* Move <code>node</code> and descendants of <code>node</code> to <code>nodeGroup</code>, as <code>node</code> will be a child of
* <code>nodeGroup</code>. Be aware <code>nodeGroup</code> can't be a descendant of <code>node</code>.
* @param node the node to be appened to <code>nodeGroup</code> children
* @param nodeGroup the node to receive <code>node</code> as a child
* @throws IllegalArgumentException if <code>node</code> or <code>nodeGroup</code> is <code>null</code> or not legal in the graph,
* or if <code>nodeGroup</code> is a descendant of node
* @throws IllegalMonitorStateException if the current thread is holding a read lock
*/
public void moveToGroup(Node node, Node nodeGroup);
/**
* Remove <code>node</code> from its parent group and append it to <code>node</code>'s parent. In other words <code>node</code> rise
* one level in the tree and is no more a child of its parent.
* @param node the node to be removed from it's group
* @throws IllegalArgumentException if <code>node</code> is <code>null</code> or not legal in the graph,
* or if <code>node</code> is already at the top of the tree
* @throws IllegalMonitorStateException if the current thread is holding a read lock
*/
public void removeFromGroup(Node node);
/**
* Group <code>nodes</code> into a new node group (i.e. cluster). Creates an upper node in the tree and appends <code>nodes</code> to it.
* Content of <code>nodes</code> can be existing groups. In that case, <code>nodes</code> must only contains roots of groups.
* Therefore all nodes in <code>nodes</code> must have the same <b>parent</b>. The method returns the newly
* created group of nodes.
* @param nodes the nodes to be grouped in a new group
* @return the newly created group of nodes which contains <code>nodes</code> and descendants of <code>nodes</code>
* @throws IllegalArgumentException if <code>nodes</code> is <code>null</code>,
* or if <code>nodes</code> is empty,
* or if content nodes are not legal in the graph,
* or if <code>nodes</code>' parent is not similar between elements
* @throws IllegalMonitorStateException if the current thread is holding a read lock
*/
public Node groupNodes(Node[] nodes);
/**
* Ungroup nodes in <code>nodeGroup</code> and destroy <code>nodeGroup</code>. Descendants of <code>nodeGroup</code> are appened to
* <code>nodeGroup</code>'s parent node. This method is the opposite of <code>groupNodes()</code>. If called with the result of
* <code>groupNodes()</code> the state will be equal to the state before calling <code>groupNodes()</code>.
* @param nodeGroup the parent node of nodes to be ungrouped
* @throws IllegalArgumentException if <code>node</code> is <code>null</code>, empty or not legal in the graph
* @throws IllegalMonitorStateException if the current thread is holding a read lock
*/
public void ungroupNodes(Node nodeGroup);
/**
* Flatten the hierarchy by keeping only nodes in the view and by transforming meta edges into edges. All nodes not in the
* view are removed from the graph. New edges are created from meta edges, with same attributes and weight.
*/
public void flatten();
public EdgeIterable getHierarchyEdges();
/**
* Returns the hierarchy tree of all nodes in the form of a <code>TreeNode</code>.
* @return a Java <code>TreeNode</code> wrapper of all nodes in the hierarchy tree
*/
public ImmutableTreeNode wrapToTreeNode();
/**
* Expands the graph view from <code>node</code> to its children. The children of <code>node</code> are put in the view and
* <code>node</code> is pulled off. Fails if <code>node</code> is not currently in the view or if <code>node</code> don't
* have any children.
* <p>
* Meta edges are automatically updated.
* @param node the node to be expanded
* @return <code>true</code> if the expand succeed or <code>false</code> if not
* @throws IllegalArgumentException if <code>node</code> is <code>null</code> or not legal in the graph
* @throws IllegalMonitorStateException if the current thread is holding a read lock
*/
public boolean expand(Node node);
/**
* Retracts the graph view from <code>node</code>'s children to <code>node</code>. The children of <code>node</code> are pulled
* off the view and <code>node</code> is added to the view. Fails if <code>node</code> is already in the view of if <code>node</code>
* don't have any children.
* <p>
* Meta edges are automatically updated.
* @param node the nodes' parent to be retracted
* @return <code>true</code> if the expand succeed or <code>false</code> if not
* @throws IllegalArgumentException if <code>node</code> is <code>null</code> or not legal in the graph
* @throws IllegalMonitorStateException if the current thread is holding a read lock
*/
public boolean retract(Node node);
/**
* Returns true if <code>node</code> is currently in the graph view.
* <p><b>Warning:</b> This method is not thread safe, be sure to call it in a locked
* statement.
* @param node the node to be queried
* @return <code>true</code> if <code>node</code> is in the view, <code>false</code> otherwise
* @throws IllegalArgumentException if <code>nodeGroup</code> is <code>null</code> or not legal in
* the graph
*/
public boolean isInView(Node node);
/**
* Reset the current view to leaves of the clustered graph tree. Therefore the
* <code>getNodesInView()</code> method returns only these leaves.
* @throws IllegalMonitorStateException if the current thread is holding a read lock
*/
public void resetViewToLeaves();
/**
* Reset the current view to top nodes of the clustered graph tree. Therefore the
* <code>getNodesInView()</code> method returns only these nodes.
* @throws IllegalMonitorStateException if the current thread is holding a read lock
*/
public void resetViewToTopNodes();
/**
* Reset the current view to nodes located at the specified <code>level</code> in the
* clustered graph hierarchy. Therefore the <code>getNodesInView()</code> method returns
* only these nodes.
* @throws IllegalArgumentException if <code>level</code> is not between 0 and the height of the tree
* @throws IllegalMonitorStateException if the current thread is holding a read lock
*/
public void resetViewToLevel(int level);
/**
* Returns meta edges for the whole graph. Meta edges are edges between a group and a leaf
* or between two groups. They represents proper edges between descendants of groups. Meta
* edges are always located only on nodes which are in the current view.
* <p>
* <b>Example:</b>
* In a clustered graph, let's define <code>group1</code> and <code>group2</code>, both with
* two leaves as children. Leaves are named <code>l11</code>, <code>l12</code>, <code>l21</code>
* and <code>l22</code>. Then we add an edge between <code>l11</code> and <code>l22</code>.
* Then we look at the view of the graph. Let's say the view is set for groups only, that means
* only groups are visible and leaves are not. At this point we can say a meta edge exist between
* <code>group1</code> and <code>group2</code> and it represents the edge <code>l11-l22</code>.
* <p>
* Therefore meta edges are useful when a graph is retracted/collapsed into clusters. Relations
* between clusters can be get with meta edges directly. Note that a meta edge knows which edges
* it represents and its weight is the sum of content edges' weight.
* @return an edge iterable of all meta edges in the current graph view
*/
public EdgeIterable getMetaEdges();
/**
* Return a unique <code>EdgeIterable</code> for edges and meta edges. The content is the
* union of <code>getEdges()</code> and <code>getMetaEdges()</code>.
* @return an edge iterable of all edges and meta edges in the current graph view
*/
public EdgeIterable getEdgesAndMetaEdges();
/**
* Returns meta edges for <code>nodeGroup</code>.
* @param nodeGroup the node whose meta edges are queried
* @return an edge iterable of meta edges incident to nodeGroup
* @throws IllegalArgumentException if <code>nodeGroup</code> is <code>null</code> or not legal in
* the graph
*/
public EdgeIterable getMetaEdges(Node nodeGroup);
/**
* Returns edges and meta edges incident to <code>node</code>.
* <p>
* For <b>directed</b> graph, note that self-loops are repeated only once. <b>Undirected</b>
* graphs repeats edges once by default.
* @param node the node whose incident edges and meta edges are to be returned
* @return an edge iterable of edges and meta edges incident to <code>node</code>
* @throws IllegalArgumentException if <code>node</code> is <code>null</code>
* or not legal in the graph.
*/
public EdgeIterable getEdgesAndMetaEdges(Node node);
/**
* Finds and returns a <b>directed</b> or <b>undirected</b> meta edge that connects <code>node1</code> and
* <code>node2</code>. Returns <code>null</code> if no such edge is found.
* <p><b>Warning:</b> This method is not thread safe, be sure to call it in a locked
* statement.
* @param node1 the first incident node of the queried meta edge
* @param node2 thge second incident node of the queried meta edge
* @return a meta edge that connects <code>node1</code> and <code>node2</code>
* or <code>null</code> if no such edge exists
* @throws IllegalArgumentException if <code>node1</code> or <code>node2</code>
* are <code>null</code> or not legal nodes in the graph
*/
public MetaEdge getMetaEdge(Node node1, Node node2);
/**
* Returns the degree for node's meta edges.
* <p><b>Warning:</b> This method is not thread safe, be sure to call it in a locked
* statement.
* @param node the node whose meta degree is queried
* @return the number of meta edges connected to <code>node</code>
* @throws IllegalArgumentException if <code>node</code> is <code>null</code> of not legal in
* the graph.
*/
public int getMetaDegree(Node node);
/**
* Returns the sum of the degree and the meta-edge degree. Equavalent to
* <code>getDegree(Node) + getMetaDegree(Node)</code>.
* <p><b>Warning:</b> This method is not thread safe, be sure to call it in a locked
* statement.
* @param node the node whose total degree is queried
* @return the number of meta edges connected to <code>node</code>
* @throws IllegalArgumentException if <code>node</code> is <code>null</code> of not legal in
* the graph.
*/
public int getTotalDegree(Node node);
/**
* Clears all meta edges for <code>node</code>.
* @param node the node whose meta edges will be deleted
* @throws IllegalArgumentException if <code>node</code> is <code>null</code> of not legal in
* the graph.
* @throws IllegalMonitorStateException if the current thread is holding a read lock
*/
public void clearMetaEdges(Node node);
}