ConcreteDGraph.java

  1. package org.thegalactic.dgraph;

  2. /*
  3.  * ConcreteDGraph.java
  4.  *
  5.  * Copyright: 2010-2015 Karell Bertet, France
  6.  * Copyright: 2015-2016 The Galactic Organization, France
  7.  *
  8.  * License: http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html CeCILL-B license
  9.  *
  10.  * This file is part of java-lattices.
  11.  * You can redistribute it and/or modify it under the terms of the CeCILL-B license.
  12.  */
  13. import java.util.AbstractSet;
  14. import java.util.ArrayList;
  15. import java.util.Collections;
  16. import java.util.Comparator;
  17. import java.util.Iterator;
  18. import java.util.List;
  19. import java.util.Map;
  20. import java.util.NoSuchElementException;
  21. import java.util.Set;
  22. import java.util.SortedSet;
  23. import java.util.TreeMap;
  24. import java.util.TreeSet;

  25. /**
  26.  * This class gives a standard representation for a directed graph by sets of
  27.  * successors and predecessors.
  28.  *
  29.  * A directed graph is composed of
  30.  *
  31.  * - a treeset of node, defined by class {@link Node}; - a treemap of successors
  32.  * that associates to each node a treeset of successors, defined by class
  33.  * {@link Edge}; - a treemap of predecessors that associates to each node a
  34.  * treeset of predecessors, defined by class {@link Edge}.
  35.  *
  36.  * This class provides methods implementing classical operation on a directed
  37.  * graph:
  38.  *
  39.  * - sinks - wells - subgraph - reflexive closure and reduction - transitive
  40.  * closure - strongly connected components - ...
  41.  *
  42.  * This class also provides a static method randomly generating a directed
  43.  * graph.
  44.  *
  45.  * ![ConcreteDGraph](ConcreteDGraph.png)
  46.  *
  47.  * @param <N> Node content type
  48.  * @param <E> Edge content type
  49.  *
  50.  * @uml DGraph.png
  51.  * !include resources/org/thegalactic/dgraph/DGraph.iuml
  52.  * !include resources/org/thegalactic/dgraph/Edge.iuml
  53.  * !include resources/org/thegalactic/dgraph/Node.iuml
  54.  *
  55.  * hide members
  56.  * show DGraph members
  57.  * class DGraph #LightCyan
  58.  * title DGraph UML graph
  59.  */
  60. public class ConcreteDGraph<N, E> extends AbstractDGraph<N, E> implements Cloneable {

  61.     /*
  62.      * ------------- FIELDS ------------------
  63.      */
  64.     /**
  65.      * A set of elements.
  66.      */
  67.     private TreeSet<Node<N>> nodes;

  68.     /**
  69.      * A map to associate a set of successors to each node.
  70.      *
  71.      * @todo use a TreeSet for edges with a specific comparator for predecessors
  72.      */
  73.     private TreeMap<Node<N>, TreeSet<Edge<N, E>>> successors;

  74.     /**
  75.      * A map to associate a set of predecessors to each node.
  76.      */
  77.     private TreeMap<Node<N>, TreeSet<Edge<N, E>>> predecessors;


  78.     /*
  79.      * ------------- CONSTRUCTORS ------------------
  80.      */
  81.     /**
  82.      * Constructs a new directed graph with an empty set of node.
  83.      */
  84.     public ConcreteDGraph() {
  85.         super();
  86.         this.nodes = new TreeSet<Node<N>>();
  87.         this.successors = new TreeMap<Node<N>, TreeSet<Edge<N, E>>>();
  88.         this.predecessors = new TreeMap<Node<N>, TreeSet<Edge<N, E>>>();
  89.     }

  90.     /**
  91.      * Constructs a new directed graph source the specified set of nodes.
  92.      *
  93.      * Successors and predecessors of each nodes are initialised by an empty
  94.      * set.
  95.      *
  96.      * @param set the set of nodes
  97.      */
  98.     public ConcreteDGraph(final SortedSet<Node<N>> set) {
  99.         this();
  100.         this.nodes.addAll(set);
  101.         for (final Node<N> node : this.nodes) {
  102.             this.successors.put(node, new TreeSet<Edge<N, E>>());
  103.             this.predecessors.put(node, new TreeSet<Edge<N, E>>());
  104.         }
  105.     }

  106.     /**
  107.      * Constructs this component as a copy of the specified directed graph.
  108.      *
  109.      * @param graph the directed graph to be copied
  110.      */
  111.     public ConcreteDGraph(final DGraph<N, E> graph) {
  112.         this(graph.getNodes());
  113.         for (final Edge<N, E> edge : graph.getEdges()) {
  114.             this.addEdge(edge);
  115.         }
  116.     }

  117.     /*
  118.      * --------------- ACCESSOR AND OVERLAPPING METHODS ------------
  119.      */
  120.     /**
  121.      * Returns a clone of this component composed of a clone of each node and
  122.      * each edge.
  123.      *
  124.      * @return the clone of this
  125.      *
  126.      * @throws java.lang.CloneNotSupportedException
  127.      */
  128.     @Override
  129.     public ConcreteDGraph<N, E> clone() throws CloneNotSupportedException {
  130.         final ConcreteDGraph<N, E> graph = (ConcreteDGraph<N, E>) super.clone();
  131.         graph.nodes = (TreeSet) this.nodes.clone();
  132.         graph.successors = new TreeMap<Node<N>, TreeSet<Edge<N, E>>>();
  133.         graph.predecessors = new TreeMap<Node<N>, TreeSet<Edge<N, E>>>();
  134.         for (final Map.Entry<Node<N>, TreeSet<Edge<N, E>>> entry : this.successors.entrySet()) {
  135.             graph.successors.put(entry.getKey(), (TreeSet<Edge<N, E>>) entry.getValue().clone());
  136.         }
  137.         for (final Map.Entry<Node<N>, TreeSet<Edge<N, E>>> entry : this.predecessors.entrySet()) {
  138.             graph.predecessors.put(entry.getKey(), (TreeSet<Edge<N, E>>) entry.getValue().clone());
  139.         }
  140.         return graph;
  141.     }

  142.     /**
  143.      * Returns the set of nodes of this component.
  144.      *
  145.      * @return the set of nodes
  146.      */
  147.     public final SortedSet<Node<N>> getNodes() {
  148.         return Collections.unmodifiableSortedSet(this.nodes);
  149.     }

  150.     /**
  151.      * Returns the set of edges of this component.
  152.      *
  153.      * @return the set of edges
  154.      */
  155.     public final SortedSet<Edge<N, E>> getEdges() {
  156.         return new Edges(this);
  157.     }

  158.     /**
  159.      * Returns the set of edges successors of the specified node.
  160.      *
  161.      * @param node the node to search for
  162.      *
  163.      * @return the set of edges
  164.      */
  165.     public final SortedSet<Edge<N, E>> getSuccessorEdges(final Node<N> node) {
  166.         return Collections.unmodifiableSortedSet(this.successors.get(node));
  167.     }

  168.     /**
  169.      * Returns the set of edges predecessors of the specified node.
  170.      *
  171.      * @param node the node to search for
  172.      *
  173.      * @return the set of edges
  174.      */
  175.     public final SortedSet<Edge<N, E>> getPredecessorEdges(final Node<N> node) {
  176.         return Collections.unmodifiableSortedSet(this.predecessors.get(node));
  177.     }

  178.     /**
  179.      * Returns the set of nodes successors of the specified node.
  180.      *
  181.      * @param node the node to search for
  182.      *
  183.      * @return the set of nodes
  184.      *
  185.      * @todo use iterator pattern (some changes in ArrowRelation.java and
  186.      * Lattice.java)
  187.      */
  188.     public final SortedSet<Node<N>> getSuccessorNodes(final Node<N> node) {
  189.         final SortedSet<Node<N>> successorsFromNode = new TreeSet<Node<N>>();
  190.         for (final Edge<N, E> edge : this.successors.get(node)) {
  191.             successorsFromNode.add(edge.getTarget());
  192.         }
  193.         return Collections.unmodifiableSortedSet(successorsFromNode);
  194.     }

  195.     /**
  196.      * Returns the set of nodes predecessors of the specified node.
  197.      *
  198.      * @param node the node to search for
  199.      *
  200.      * @return the set of nodes
  201.      *
  202.      * @todo use iterator pattern (some changes in ArrowRelation.java and
  203.      * Lattice.java)
  204.      */
  205.     public final SortedSet<Node<N>> getPredecessorNodes(final Node<N> node) {
  206.         final SortedSet<Node<N>> predecessorsFromNode = new TreeSet<Node<N>>();
  207.         for (final Edge<N, E> edge : this.predecessors.get(node)) {
  208.             predecessorsFromNode.add(edge.getSource());
  209.         }
  210.         return Collections.unmodifiableSortedSet(predecessorsFromNode);
  211.     }

  212.     /**
  213.      * Returns, if it exists, the edge between node source and node to.
  214.      *
  215.      * @param source The origin node
  216.      * @param target The destination node
  217.      *
  218.      * @return the found edge or null
  219.      *
  220.      * @todo see getNode
  221.      */
  222.     public final Edge<N, E> getEdge(final Node<N> source, final Node<N> target) {
  223.         Edge<N, E> edge = null;
  224.         if (source != null && target != null) {
  225.             try {
  226.                 final Edge<N, E> search = new Edge<N, E>(source, target);
  227.                 edge = this.successors.get(source).subSet(search, true, search, true).first();
  228.             } catch (NoSuchElementException ex) {
  229.             }
  230.         }
  231.         return edge;
  232.     }

  233.     /**
  234.      * Returns the node that is equal to the specified one.
  235.      *
  236.      * @param search The node to search for
  237.      *
  238.      * @return the found node or null
  239.      *
  240.      * @todo maybe use try { return this.nodes.subSet(search, true, search,
  241.      * true).first(); } catch (NoSuchElementException e) { return null; }
  242.      *
  243.      */
  244.     public final Node<N> getNode(final Node<N> search) {
  245.         for (final Node<N> node : this.nodes) {
  246.             if (node.equals(search)) {
  247.                 return node;
  248.             }
  249.         }
  250.         return null;
  251.     }

  252.     /**
  253.      * Returns the node whose content is equal to the specified one.
  254.      *
  255.      * @param content The content to search for
  256.      *
  257.      * @return the found node or null
  258.      *
  259.      * @todo this method is not efficient. Do we remove it or add an index on
  260.      * DGraph using content field? Verify where it is called for migrating it if
  261.      * necessary.
  262.      */
  263.     public final Node<N> getNodeByContent(final Object content) {
  264.         for (final Node<N> node : this.nodes) {
  265.             if (node.getContent().equals(content)) {
  266.                 return node;
  267.             }
  268.         }
  269.         return null;
  270.     }

  271.     /**
  272.      * Returns the node whose ident is equal to the specified one.
  273.      *
  274.      * @param identifier node identifier
  275.      *
  276.      * @return the found node or null
  277.      */
  278.     public final Node<N> getNodeByIdentifier(int identifier) {
  279.         for (final Node<N> node : this.nodes) {
  280.             if (node.getIdentifier() == identifier) {
  281.                 return node;
  282.             }
  283.         }
  284.         return null;
  285.     }

  286.     /**
  287.      * Returns the number of nodes of this component.
  288.      *
  289.      * @return the number of nodes
  290.      */
  291.     public final int sizeNodes() {
  292.         return this.nodes.size();
  293.     }

  294.     /**
  295.      * Returns the number of edges of this component.
  296.      *
  297.      * @return the number of edges
  298.      */
  299.     public final int sizeEdges() {
  300.         int size = 0;
  301.         for (final Node<N> node : this.nodes) {
  302.             size += this.successors.get(node).size();
  303.         }
  304.         return size;
  305.     }


  306.     /*
  307.      * --------------- NODES AND EDGES MODIFICATION METHODS ------------
  308.      */
  309.     /**
  310.      * Checks if the specified node belong to this component.
  311.      *
  312.      * @param node the node to insert
  313.      *
  314.      * @return true if the node has been successfully inserted
  315.      */
  316.     public final boolean containsNode(final Node<N> node) {
  317.         return this.nodes.contains(node);
  318.     }

  319.     /**
  320.      * Adds the specified node to the set of node of this component.
  321.      *
  322.      * @param node the node to insert
  323.      *
  324.      * @return true if the node has been successfully inserted
  325.      */
  326.     public final boolean addNode(final Node<N> node) {
  327.         if (!this.containsNode(node)) {
  328.             this.nodes.add(node);
  329.             this.successors.put(node, new TreeSet<Edge<N, E>>());
  330.             this.predecessors.put(node, new TreeSet<Edge<N, E>>());
  331.             return true;
  332.         }
  333.         return false;
  334.     }

  335.     /**
  336.      * Removes the specified node from this component.
  337.      *
  338.      * @param node the node to remove
  339.      *
  340.      * @return true if the node was successfully removed
  341.      */
  342.     public final boolean removeNode(final Node<N> node) {
  343.         if (this.containsNode(node)) {
  344.             // Remove the edges (node,target) with key node in successors, and key target in predecessors
  345.             for (final Edge<N, E> successor : this.successors.get(node)) {
  346.                 if (successor.getTarget().compareTo(node) != 0) {
  347.                     for (final Edge<N, E> predecessor : this.predecessors.get(successor.getTarget())) {
  348.                         if (predecessor.getSource().compareTo(node) == 0) {
  349.                             this.predecessors.get(successor.getTarget()).remove(predecessor);
  350.                         }
  351.                     }
  352.                 }
  353.                 this.successors.remove(node);
  354.             }
  355.             // Remove the edges (source,node) with key node in predecessors, and key source in successors
  356.             for (final Edge<N, E> predecessor : this.predecessors.get(node)) {
  357.                 if (predecessor.getSource().compareTo(node) != 0) {
  358.                     for (final Edge<N, E> successor : this.successors.get(predecessor.getSource())) {
  359.                         if (successor.getTarget().compareTo(node) == 0) {
  360.                             this.successors.get(predecessor.getSource()).remove(successor);
  361.                         }
  362.                     }
  363.                 }
  364.                 this.predecessors.remove(node);
  365.             }
  366.             // Remove node
  367.             this.nodes.remove(node);
  368.             return true;
  369.         }
  370.         return false;
  371.     }

  372.     /**
  373.      * Removes the specified set of nodes from this component.
  374.      *
  375.      * @param nodes set of nodes
  376.      *
  377.      * @return true if all nodes were removed
  378.      */
  379.     public final boolean removeNodes(final Set<Node<N>> nodes) {
  380.         boolean all = true;
  381.         for (final Node<N> node : nodes) {
  382.             if (!this.removeNode(node)) {
  383.                 all = false;
  384.             }
  385.         }
  386.         return all;
  387.     }

  388.     /**
  389.      * Checks if there exists an edge between the two specified nodes.
  390.      *
  391.      * @param source the node origine of the edge
  392.      * @param target the node destination of the edge
  393.      *
  394.      * @return true if the edge is contained by this component
  395.      */
  396.     public final boolean containsEdge(final Node<N> source, final Node<N> target) {
  397.         return this.containsNode(source)
  398.                 && this.containsNode(target)
  399.                 && this.getSuccessorNodes(source).contains(target)
  400.                 && this.getPredecessorNodes(target).contains(source);
  401.     }

  402.     /**
  403.      * Checks if the specified edge belong to this component.
  404.      *
  405.      * @param edge the edge to be checked
  406.      *
  407.      * @return true if the edge is contained by this component
  408.      */
  409.     public final boolean containsEdge(final Edge<N, E> edge) {
  410.         return this.containsEdge(edge.getSource(), edge.getTarget());
  411.     }

  412.     /**
  413.      * Adds an edge between the specified nodes to this component: `to` is added
  414.      * as a successor of `source`.
  415.      *
  416.      * If the case where specified nodes don't belongs to the node set, then the
  417.      * edge will not be added.
  418.      *
  419.      * @param source  the node origin of the edge
  420.      * @param target  the node destination of the edge
  421.      * @param content the edge content
  422.      *
  423.      * @return true if the edge was successfully added
  424.      */
  425.     public final boolean addEdge(final Node<N> source, final Node<N> target, final Object content) {
  426.         if (this.containsNode(source) && this.containsNode(target)) {
  427.             final Edge<N, E> edge = new Edge(source, target, content);
  428.             this.successors.get(source).add(edge);
  429.             this.predecessors.get(target).add(edge);
  430.             return true;
  431.         }
  432.         return false;
  433.     }

  434.     /**
  435.      * Adds an edge between the specified nodes to this component: `to` is added
  436.      * as a successor of `source`.
  437.      *
  438.      * If the case where specified nodes don't belongs to the node set, then the
  439.      * edge will not be added.
  440.      *
  441.      * @param source the node origin of the edge
  442.      * @param target the node destination of the edge
  443.      *
  444.      * @return true if the edge was successfully added
  445.      */
  446.     public final boolean addEdge(final Node<N> source, final Node<N> target) {
  447.         return this.addEdge(source, target, null);
  448.     }

  449.     /**
  450.      * Adds the specified edge to this component in the successors of
  451.      * edge.getSource() and in the predecessors of edge.getTarget().
  452.      *
  453.      * If the case where nodes to and source of this edges don't belongs to the
  454.      * node set, then the edge will not be added.
  455.      *
  456.      * @param edge the edge to be added
  457.      *
  458.      * @return true if the edge was added
  459.      */
  460.     public final boolean addEdge(final Edge<N, E> edge) {
  461.         if (this.containsNode(edge.getSource()) && this.containsNode(edge.getTarget())) {
  462.             this.successors.get(edge.getSource()).add(edge);
  463.             this.predecessors.get(edge.getTarget()).add(edge);
  464.             return true;
  465.         }
  466.         return false;
  467.     }

  468.     /**
  469.      * Removes source this component the edge between the specified node.
  470.      *
  471.      * `to` is removed source the successors of `source` and `to` is removed
  472.      * source
  473.      * the predecessors of `source`.
  474.      *
  475.      * @param source the node origine of the edge
  476.      * @param target the node destination of the edge
  477.      *
  478.      * @return true if the edge was removed
  479.      */
  480.     public final boolean removeEdge(final Node<N> source, final Node<N> target) {
  481.         if (this.containsEdge(source, target)) {
  482.             final Edge<N, E> edge = new Edge(source, target);
  483.             this.successors.get(source).remove(edge);
  484.             this.predecessors.get(target).remove(edge);
  485.             return true;
  486.         }
  487.         return false;
  488.     }

  489.     /**
  490.      * Removes source this component the specified edge source the successors of
  491.      * edge.getSource() and source the predecessors of edge.getTarget().
  492.      *
  493.      * @param edge the edge to be removed.
  494.      *
  495.      * @return true if the edge was removed
  496.      */
  497.     public final boolean removeEdge(final Edge<N, E> edge) {
  498.         if (this.containsEdge(edge)) {
  499.             this.successors.get(edge.getSource()).remove(edge);
  500.             this.predecessors.get(edge.getTarget()).remove(edge);
  501.             return true;
  502.         }
  503.         return false;
  504.     }

  505.     /*
  506.      * --------------- ACYCLIC CHECKING METHODS ------------
  507.      */
  508.     /**
  509.      * Returns the subgraph of this component induced by the specified set of
  510.      * nodes.
  511.      *
  512.      * The subgraph only contains nodes of the specified set that also are in
  513.      * this component.
  514.      *
  515.      * @param nodes The set of nodes
  516.      *
  517.      * @return The subgraph
  518.      *
  519.      * @todo implement a SubGraph class?
  520.      */
  521.     public ConcreteDGraph<N, E> getSubgraphByNodes(final Set<Node<N>> nodes) {
  522.         ConcreteDGraph<N, E> graph = new ConcreteDGraph<N, E>();
  523.         // addition of nodes in the subgraph
  524.         for (Node<N> node : nodes) {
  525.             if (this.containsNode(node)) {
  526.                 graph.addNode(node);
  527.             }
  528.         }
  529.         // addition of edges in the subgraph
  530.         for (Edge<N, E> edge : this.getEdges()) {
  531.             if (graph.containsNode(edge.getTarget())) {
  532.                 graph.addEdge(edge);
  533.             }
  534.         }
  535.         return graph;
  536.     }

  537.     /**
  538.      * Returns the subgraph of this component induced by the specified set of
  539.      * edges.
  540.      *
  541.      * The subgraph contains all nodes of this components, and only edges of the
  542.      * specified set that also are in this component.
  543.      *
  544.      * @param edges The set of edges
  545.      *
  546.      * @return The subgraph
  547.      *
  548.      * @todo implement a SubGraph class?
  549.      */
  550.     public ConcreteDGraph<N, E> getSubgraphByEdges(final Set<Edge<N, E>> edges) {
  551.         ConcreteDGraph<N, E> graph = new ConcreteDGraph<N, E>();
  552.         // addition of all nodes in the subgraph
  553.         for (Node<N> node : this.nodes) {
  554.             graph.addNode(node);
  555.         }
  556.         // addition of specified edges in the subgraph
  557.         for (Edge<N, E> edge : edges) {
  558.             if (this.containsEdge(edge)) {
  559.                 graph.addEdge(edge);
  560.             }
  561.         }
  562.         return graph;
  563.     }

  564.     /**
  565.      * Replaces this component by its complementary graph.
  566.      *
  567.      * There is an edge between to nodes in the complementary graph when there
  568.      * is no edges between the nodes in this component.
  569.      */
  570.     public void complementary() {
  571.         for (Node<N> source : this.nodes) {
  572.             TreeSet<Node<N>> newSuccessors = new TreeSet<Node<N>>(this.nodes);
  573.             newSuccessors.removeAll(this.getSuccessorNodes(source));
  574.             TreeSet<Node<N>> oldSuccessors = new TreeSet<Node<N>>(this.getSuccessorNodes(source));
  575.             for (Node<N> target : oldSuccessors) {
  576.                 this.removeEdge(source, target);
  577.             }
  578.             for (Node<N> target : newSuccessors) {
  579.                 this.addEdge(source, target);
  580.             }
  581.         }
  582.     }

  583.     /*
  584.      * --------------- GRAPH TREATMENT METHODS ------------
  585.      */
  586.     /**
  587.      * Computes the reflexive reduction of this component.
  588.      *
  589.      * @return the number of removed edges
  590.      */
  591.     public final int reflexiveReduction() {
  592.         int size = 0;
  593.         for (final Node<N> node : this.nodes) {
  594.             if (this.containsEdge(node, node)) {
  595.                 size++;
  596.                 this.removeEdge(node, node);
  597.             }
  598.         }
  599.         return size;
  600.     }

  601.     /**
  602.      * Computes the reflexive closure of this component.
  603.      *
  604.      * @return the number of added edges
  605.      */
  606.     public final int reflexiveClosure() {
  607.         int size = 0;
  608.         for (final Node<N> node : this.nodes) {
  609.             if (!this.containsEdge(node, node)) {
  610.                 size++;
  611.                 this.addEdge(node, node);
  612.             }
  613.         }
  614.         return size;
  615.     }

  616.     /**
  617.      * Computes the transitive closure of this component.
  618.      *
  619.      * This treatment is performed in $O(nm+m_c)$, where $n$ corresponds to the
  620.      * number of nodes, $m$ to the number of edges, and $m_c$ to the number of edges
  621.      * in the closure. This treatment improves the Roy-Warshall algorithm that
  622.      * directly implements the definition in $O(log(m) n^3)$.
  623.      *
  624.      * This treatment is overridden in class {@link DAGraph} with a more
  625.      * efficient algorithm dedicated to directed acyclic graph.
  626.      *
  627.      * @return the number of added edges
  628.      */
  629.     public int transitiveClosure() {
  630.         int size = 0;
  631.         // mark each node to false
  632.         final TreeMap<Node<N>, Boolean> mark = new TreeMap<Node<N>, Boolean>();
  633.         for (final Node<N> node : this.nodes) {
  634.             mark.put(node, Boolean.FALSE);
  635.         }
  636.         // treatment of nodes
  637.         final List<Node<N>> list = new ArrayList<Node<N>>();
  638.         for (final Node<N> source : this.nodes) {
  639.             list.clear();
  640.             list.add(source);
  641.             while (!list.isEmpty()) {
  642.                 // Remove the first node
  643.                 final Node<N> source2 = list.remove(0);
  644.                 for (final Node<N> target : this.getSuccessorNodes(source2)) {
  645.                     // treatment of target when not marked
  646.                     if (!mark.get(target)) {
  647.                         mark.put(target, Boolean.TRUE);
  648.                         this.addEdge(source, target);
  649.                         list.add(target);
  650.                         size++;
  651.                     }
  652.                 }
  653.             }
  654.             for (final Node<N> target : this.getSuccessorNodes(source)) {
  655.                 mark.put(target, Boolean.FALSE);
  656.             }
  657.         }
  658.         return size;
  659.     }

  660.     /**
  661.      * Transposes this component by replacing for each node its successor set by
  662.      * its predecessor set, and its predecessor set by its successor set.
  663.      */
  664.     public final void transpose() {
  665.         ConcreteDGraph<N, E> tmp = new ConcreteDGraph<N, E>(this);
  666.         for (Edge<N, E> edge : tmp.getEdges()) {
  667.             this.removeEdge(edge);
  668.             this.addEdge(new Edge(edge.getTarget(), edge.getSource(), edge.getContent()));
  669.         }
  670.     }

  671.     /**
  672.      * Returns the directed acyclic graph where each node corresponds to a
  673.      * strongly connected component (SCC) of this component stored in a TreeSet
  674.      * of nodes.
  675.      *
  676.      * When two nodes in two different SCC are in relation, the same is for the
  677.      * SCC they belongs to.
  678.      *
  679.      * @return The directed acyclic graph
  680.      */
  681.     public DAGraph<SortedSet<Node<N>>, Object> getStronglyConnectedComponent() {
  682.         DAGraph<SortedSet<Node<N>>, Object> cc = new DAGraph<SortedSet<Node<N>>, Object>();
  683.         // first depth first search
  684.         ConcreteDGraph<N, E> tmp = new ConcreteDGraph<N, E>(this);
  685.         tmp.transitiveClosure();
  686.         ArrayList<Node<N>> last = tmp.depthFirstSearch()[1];
  687.         // transposition of the graph
  688.         ConcreteDGraph<N, E> transposedGraph = new ConcreteDGraph<N, E>(this);
  689.         transposedGraph.transpose();
  690.         // sort nodes according to the reverse last sort
  691.         ArrayList<Node<N>> sort = new ArrayList<Node<N>>();
  692.         Object[] array = last.toArray();
  693.         for (int i = array.length - 1; i >= 0; i--) {
  694.             sort.add((Node<N>) array[i]);
  695.         }
  696.         // second depth first search according to sort
  697.         TreeSet<Node<N>> visited = new TreeSet<Node<N>>();
  698.         for (Node<N> node : sort) {
  699.             if (!visited.contains(node)) {
  700.                 last = transposedGraph.depthFirstSearch(node, visited, sort)[1];
  701.                 visited.addAll(last);
  702.                 TreeSet<Node<N>> sCC = new TreeSet<Node<N>>(last);
  703.                 // a strongly connected component is generated
  704.                 cc.addNode(new Node<SortedSet<Node<N>>>(sCC));    // addition of
  705.             }
  706.         }
  707.         // edges between strongly connected component
  708.         for (Node<SortedSet<Node<N>>> ccSource : cc.getNodes()) {
  709.             for (Node<SortedSet<Node<N>>> ccTarget : cc.getNodes()) {
  710.                 for (Node<N> source : ccSource.getContent()) {
  711.                     for (Node<N> target : ccTarget.getContent()) {
  712.                         if (tmp.getSuccessorNodes(source).contains(target)) {
  713.                             cc.addEdge(ccSource, ccTarget);
  714.                         }
  715.                     }
  716.                 }
  717.             }
  718.         }
  719.         cc.reflexiveReduction();
  720.         return cc;
  721.     }

  722.     /**
  723.      * Set the set of nodes of this component.
  724.      *
  725.      * @param nodes The nodes
  726.      *
  727.      * @return this for chaining
  728.      */
  729.     protected ConcreteDGraph<N, E> setNodes(final TreeSet<Node<N>> nodes) {
  730.         this.nodes = nodes;
  731.         return this;
  732.     }

  733.     /**
  734.      * Returns the successors of this component.
  735.      *
  736.      * @return the map
  737.      */
  738.     protected TreeMap<Node<N>, TreeSet<Edge<N, E>>> getSuccessors() {
  739.         return this.successors;
  740.     }

  741.     /**
  742.      * Set the successors of this component.
  743.      *
  744.      * @param successors The successors
  745.      *
  746.      * @return this for chaining
  747.      */
  748.     protected ConcreteDGraph<N, E> setSuccessors(final TreeMap<Node<N>, TreeSet<Edge<N, E>>> successors) {
  749.         this.successors = successors;
  750.         return this;
  751.     }

  752.     /**
  753.      * Returns the predecessors of this component.
  754.      *
  755.      * @return the map
  756.      */
  757.     protected TreeMap<Node<N>, TreeSet<Edge<N, E>>> getPredecessors() {
  758.         return this.predecessors;
  759.     }

  760.     /**
  761.      * Set the predecessors of this component.
  762.      *
  763.      * @param predecessors The predecessors
  764.      *
  765.      * @return this for chaining
  766.      */
  767.     protected ConcreteDGraph<N, E> setPredecessors(final TreeMap<Node<N>, TreeSet<Edge<N, E>>> predecessors) {
  768.         this.predecessors = predecessors;
  769.         return this;
  770.     }

  771.     /**
  772.      * Returns a two cells array containing the first visited sort on the nodes,
  773.      * and the last visited sort on the nodes, by a depth first traverse issued
  774.      * source the specified node.
  775.      *
  776.      * @param source  The source node
  777.      * @param visited The visited nodes
  778.      * @param sort    The sort parameter
  779.      *
  780.      * @return The array
  781.      *
  782.      * @todo Do we change that to iterators? Change to private and add a method
  783.      * that return an iterator
  784.      */
  785.     private ArrayList<Node<N>>[] depthFirstSearch(Node<N> source, TreeSet<Node<N>> visited, ArrayList<Node<N>> sort) {
  786.         ArrayList<Node<N>> first = new ArrayList<Node<N>>();
  787.         ArrayList<Node<N>> last = new ArrayList<Node<N>>();
  788.         first.add(source);
  789.         visited.add(source);
  790.         ArrayList<Node<N>>[] arrayVisited = new ArrayList[2];
  791.         if (sort != null) {
  792.             // search according to a sort
  793.             for (Node<N> node : sort) {
  794.                 if (this.getSuccessorNodes(source).contains(node) && !visited.contains(node)) {
  795.                     arrayVisited = this.depthFirstSearch(node, visited, sort);
  796.                     visited.addAll(arrayVisited[0]);
  797.                     first.addAll(arrayVisited[0]);
  798.                     last.addAll(arrayVisited[1]);
  799.                 }
  800.             }
  801.         } else {
  802.             // classical search
  803.             for (Node<N> node : this.getSuccessorNodes(source)) {
  804.                 if (!visited.contains(node)) {
  805.                     arrayVisited = this.depthFirstSearch(node, visited, sort);
  806.                     visited.addAll(arrayVisited[0]);
  807.                     first.addAll(arrayVisited[0]);
  808.                     last.addAll(arrayVisited[1]);
  809.                 }
  810.             }
  811.         }
  812.         last.add(source);
  813.         arrayVisited[0] = first;
  814.         arrayVisited[1] = last;
  815.         return arrayVisited;
  816.     }

  817.     /**
  818.      * Returns a two cells array containing the first visited sort on the nodes,
  819.      * and the last visited sort on the nodes, by a depth first search.
  820.      *
  821.      * @return The array
  822.      */
  823.     private ArrayList<Node<N>>[] depthFirstSearch() {
  824.         TreeSet<Node<N>> visited = new TreeSet<Node<N>>();
  825.         ArrayList<Node<N>>[] arrayVisited = new ArrayList[2];
  826.         ArrayList<Node<N>> first = new ArrayList<Node<N>>();
  827.         ArrayList<Node<N>> last = new ArrayList<Node<N>>();
  828.         for (Node<N> node : this.nodes) {
  829.             if (!visited.contains(node)) {
  830.                 arrayVisited = this.depthFirstSearch(node, visited, null);
  831.                 visited.addAll(arrayVisited[0]);
  832.                 first.addAll(arrayVisited[0]);
  833.                 last.addAll(arrayVisited[1]);
  834.             }
  835.         }
  836.         arrayVisited[0] = first;
  837.         arrayVisited[1] = last;
  838.         return arrayVisited;
  839.     }

  840.     /**
  841.      * This class implements a sorted set of the edges.
  842.      *
  843.      * @param <N> Node content type
  844.      * @param <E> Edge content type
  845.      */
  846.     private class Edges<N, E> extends AbstractSet<Edge<N, E>> implements SortedSet<Edge<N, E>> {

  847.         /**
  848.          * The underlying graph.
  849.          */
  850.         private final ConcreteDGraph<N, E> graph;

  851.         /**
  852.          * Constructs a sorted set of the edges source a graph.
  853.          *
  854.          * @param graph A ConcreteDGraph
  855.          */
  856.         Edges(final ConcreteDGraph<N, E> graph) {
  857.             this.graph = graph;
  858.         }

  859.         /**
  860.          * Get the underlying graph.
  861.          *
  862.          * @return the graph
  863.          */
  864.         protected final ConcreteDGraph<N, E> getGraph() {
  865.             return this.graph;
  866.         }

  867.         /**
  868.          * Implements the SortedSet interface.
  869.          *
  870.          * @return the first edge
  871.          */
  872.         public final Edge<N, E> first() {
  873.             throw new UnsupportedOperationException();
  874.         }

  875.         /**
  876.          * Implements the SortedSet interface.
  877.          *
  878.          * @return the last edge
  879.          */
  880.         public final Edge<N, E> last() {
  881.             throw new UnsupportedOperationException();
  882.         }

  883.         /**
  884.          * Implements the SortedSet interface.
  885.          *
  886.          * @param edge the to edge
  887.          *
  888.          * @return The head set
  889.          *
  890.          * @throws UnsupportedOperationException
  891.          */
  892.         public final SortedSet<Edge<N, E>> headSet(final Edge<N, E> edge) {
  893.             throw new UnsupportedOperationException();
  894.         }

  895.         /**
  896.          * Implements the SortedSet interface.
  897.          *
  898.          * @param edge the source edge
  899.          *
  900.          * @return The tail set
  901.          *
  902.          * @throws UnsupportedOperationException
  903.          */
  904.         public final SortedSet<Edge<N, E>> tailSet(final Edge<N, E> edge) {
  905.             throw new UnsupportedOperationException();
  906.         }

  907.         /**
  908.          * Implements the SortedSet interface.
  909.          *
  910.          * @param fromEdge the source edge
  911.          * @param toEdge   the to edge
  912.          *
  913.          * @return The sub set
  914.          *
  915.          * @throws UnsupportedOperationException
  916.          */
  917.         public final SortedSet<Edge<N, E>> subSet(final Edge<N, E> fromEdge, final Edge<N, E> toEdge) {
  918.             throw new UnsupportedOperationException();
  919.         }

  920.         /**
  921.          * Implements the SortedSet interface.
  922.          *
  923.          * @return null
  924.          */
  925.         public final Comparator<? super Edge<N, E>> comparator() {
  926.             return null;
  927.         }

  928.         /**
  929.          * Implements the AbstractCollection class.
  930.          *
  931.          * @return the size of the collection
  932.          */
  933.         public final int size() {
  934.             return this.graph.sizeEdges();
  935.         }

  936.         /**
  937.          * Implements the AbstractCollection class.
  938.          *
  939.          * @return a new edges iterator
  940.          */
  941.         public final EdgesIterator iterator() {
  942.             return new EdgesIterator(this);
  943.         }

  944.         /**
  945.          * This class implements an iterator over the edges of a graph.
  946.          */
  947.         private class EdgesIterator implements Iterator<Edge<N, E>> {

  948.             /**
  949.              * The nodes iterator.
  950.              */
  951.             private final Iterator<Node<N>> nodesIterator;

  952.             /**
  953.              * The edges iterator for the current node.
  954.              */
  955.             private Iterator<Edge<N, E>> edgesIterator;

  956.             /**
  957.              * The edges object.
  958.              */
  959.             private final Edges<N, E> edges;

  960.             /**
  961.              * The hasNext flag.
  962.              */
  963.             private boolean hasNext;

  964.             /**
  965.              * Constructs the iterator source a set of edges.
  966.              *
  967.              * @param edges The edges.
  968.              */
  969.             EdgesIterator(final Edges<N, E> edges) {
  970.                 this.edges = edges;
  971.                 this.nodesIterator = edges.graph.nodes.iterator();
  972.                 this.prepareNext();
  973.             }

  974.             /**
  975.              * Prepare the next edge and the hasNext flag.
  976.              */
  977.             private void prepareNext() {
  978.                 this.hasNext = false;
  979.                 while (!this.hasNext && this.nodesIterator.hasNext()) {
  980.                     this.edgesIterator = this.edges.getGraph().successors.get(this.nodesIterator.next()).iterator();
  981.                     this.hasNext = this.edgesIterator.hasNext();
  982.                 }
  983.             }

  984.             /**
  985.              * The remove operation is not supported.
  986.              *
  987.              * @throws UnsupportedOperationException
  988.              */
  989.             @Override
  990.             public void remove() {
  991.                 throw new UnsupportedOperationException();
  992.             }

  993.             /**
  994.              * The next method returns the next edge.
  995.              *
  996.              * @return The next edge
  997.              */
  998.             public Edge<N, E> next() {
  999.                 Edge<N, E> edge = this.edgesIterator.next();
  1000.                 if (!this.edgesIterator.hasNext()) {
  1001.                     this.prepareNext();
  1002.                 }
  1003.                 return edge;
  1004.             }

  1005.             /**
  1006.              * The hasNext method return true if the iterator has a next edge.
  1007.              *
  1008.              * @return true if the iterator has a next edge
  1009.              */
  1010.             public boolean hasNext() {
  1011.                 return this.hasNext;
  1012.             }
  1013.         }
  1014.     }
  1015. }