Package bgu.bio.adt.graphs

Source Code of bgu.bio.adt.graphs.FlexibleUndirectedGraph

package bgu.bio.adt.graphs;

import gnu.trove.list.array.TIntArrayList;

import java.util.ArrayList;

import bgu.bio.io.file.json.JSONArray;
import bgu.bio.io.file.json.JSONException;
import bgu.bio.io.file.json.JSONObject;

/**
* A class representing a <b>undirected</b> graph using array lists
*
* @author milon
*/
public class FlexibleUndirectedGraph {
  /**
   * Holds the amount of nodes in the graph
   */
  protected int nodeNum;

  /**
   * Holds the amount of edges in a graph
   */
  protected int edgeNum;

  /**
   * Information on outgoing edges in the graph
   */
  private ArrayList<TIntArrayList> adjLists;

  /**
   * Maximal out degree in the graph
   */
  private int maxDegree;

  public FlexibleUndirectedGraph() {
    this.adjLists = new ArrayList<TIntArrayList>();
    nodeNum = 0;
    edgeNum = 0;
    maxDegree = 0;
  }

  /**
   * Add Node to the end of the list
   */
  /**
   * @return the id of the new node
   */
  public int addNode() {
    if (this.adjLists.size() == this.nodeNum) {
      this.adjLists.add(new TIntArrayList());
    }
    this.nodeNum++;
    if (maxDegree < 0) {
      maxDegree = 0;
    }
    return this.nodeNum;
  }

  /**
   * Add an edge between two nodes
   *
   * @param u
   *            first node
   * @param v
   *            second node
   */
  public void addEdge(int u, int v) {
    if (u >= this.nodeNum || v >= this.nodeNum) {
      throw new IndexOutOfBoundsException(
          "Node index isn't in the current graph");
    }
    final TIntArrayList uList = this.adjLists.get(u);
    final TIntArrayList vList = this.adjLists.get(v);

    uList.add(v);
    vList.add(u);

    // check if the new edge turns the current node to the one with the
    // maximum degree
    if (this.maxDegree < uList.size()) {
      this.maxDegree = uList.size();
    }
    if (this.maxDegree < vList.size()) {
      this.maxDegree = vList.size();
    }
    this.edgeNum++;
  }

  /**
   * Remove an edge between two nodes
   *
   * @param u
   *            first node
   * @param v
   *            second node
   */
  public void removeEdge(int u, int v) {
    final TIntArrayList uList = this.adjLists.get(u);
    if (uList.size() == 1) {
      uList.resetQuick();
    } else {
      int index = this.getNeighborIx(u, v);
      // switch the out edge in the list
      uList.set(index, uList.get(uList.size() - 1));
      uList.removeAt(index);
    }
    final TIntArrayList vList = this.adjLists.get(v);
    if (vList.size() == 1) {
      vList.resetQuick();
    } else {
      int index = this.getNeighborIx(v, u);
      // switch the out edge in the list
      vList.set(index, vList.get(vList.size() - 1));
      vList.removeAt(index);
    }
    edgeNum--;
    calcMaxDeg();
  }

  /**
   * Removes all the nodes
   *
   * @param u
   */
  public void detachNode(int u) {
    while (deg(u) > 0) {
      removeEdge(u, getNeighbor(u, 0));
    }
  }

  /**
   * Return the number of nodes in the graph
   *
   * @return the number of nodes in the graph
   */
  public int getNodeNum() {
    return nodeNum;
  }

  /**
   * Return the degree of a node
   *
   * @param nodeIx
   *            the node ix
   * @return the number of adjacent nodes
   */
  public int deg(int nodeIx) {
    return adjLists.get(nodeIx).size();
  }

  /**
   * Gets the neighbor given an index in the list.
   *
   * @param node
   *            the node index
   * @param neighborIx
   *            the neighbor index in the list
   * @return the neighbor id
   */
  public int getNeighbor(int node, int neighborIx) {
    return adjLists.get(node).get(neighborIx);
  }

  /**
   * Gets the neighbor index in the out adjacent list.
   *
   * @param node
   *            the node
   * @param neighbor
   *            the neighbor id
   * @return the neighbor index in the list of the node
   */
  public int getNeighborIx(int node, int neighbor) {
    final TIntArrayList is = adjLists.get(node);
    for (int ix = 0; ix < is.size(); ++ix) {
      if (is.get(ix) == neighbor) {
        return ix;
      }
    }
    return -1;
  }

  /**
   * Return the number of edges in the graph
   *
   * @return the number of the edges in the graph
   */
  public int getEdgeNum() {
    return this.edgeNum;
  }

  /**
   * Return the maximal degree in the graph
   *
   * @return the maximal degree in the graph
   */
  public int getMaxDeg() {
    return maxDegree;
  }

  private void calcMaxDeg() {
    this.maxDegree = -1;
    for (int i = 0; i < this.adjLists.size(); i++) {
      if (this.adjLists.get(i).size() > maxDegree) {
        maxDegree = this.adjLists.get(i).size();
      }
    }
  }

  /**
   * Check if the given nodes are connected in the graph
   *
   * @param u
   *            first node
   * @param v
   *            second node
   * @return true if and only if u is connected to v
   */
  public boolean isNeighbours(int u, int v) {
    final TIntArrayList adj = adjLists.get(u);
    for (int i = 0; i < adj.size(); i++) {
      if (adj.get(i) == v) {
        return true;
      }
    }
    return false;
  }

  public void clear() {
    for (int i = 0; i < nodeNum; i++) {
      this.adjLists.get(i).resetQuick();
    }
    this.maxDegree = 0;
    this.nodeNum = 0;
    this.edgeNum = 0;
  }

  /**
   * Calculate the degeneracy of the graph
   *
   * @return the degeneracy of the given graph
   */
  public int degeneracy() {
    return degeneracy(null);
  }

  /**
   * Calculate the degeneracy of the graph
   *
   * @param list
   *            if the list is not null it will contain the degeneracy order
   *            of the nodes
   * @return the degeneracy of the given graph
   */
  public int degeneracy(TIntArrayList list) {
    int deg = 0;
    TIntArrayList[] dArray = new TIntArrayList[maxDegree + 1];
    int[] currentDeg = new int[nodeNum];
    for (int i = 0; i < dArray.length; i++) {
      dArray[i] = new TIntArrayList();
    }
    // add the initial degree of each node, ordered by id
    for (int i = 0; i < nodeNum; i++) {
      dArray[deg(i)].add(i);
      currentDeg[i] = deg(i);
    }

    int nodesLeft = nodeNum;
    int i = 0;
    while (nodesLeft > 0) {
      while (dArray[i].size() == 0) {
        i++;
      }
      int min = i;
      final int v = dArray[i].removeAt(dArray[i].size() - 1);
      if (list != null) {
        list.add(v);
      }
      currentDeg[v] = -1; // remove information on the node
      // decrease the degree of all the neighbors of node
      TIntArrayList adj = adjLists.get(v);
      deg = Math.max(deg, i);
      for (int ind = 0; ind < adj.size(); ind++) {
        final int w = adj.get(ind);
        // only check the node if it wasn't removed
        if (currentDeg[w] != -1) {
          // TODO: make the removal faster
          dArray[currentDeg[w]].remove(w);
          currentDeg[w] = currentDeg[w] - 1;
          if (currentDeg[w] < min) {
            min = currentDeg[w];
          }
          dArray[currentDeg[w]].add(w);
        }
      }
      nodesLeft--;
      i = min;
    }

    if (list != null) {
      list.reverse();
    }

    return deg;
  }

  /**
   * Return a representation of the graph in Graphviz format
   *
   * @return String representation of the graph in Graphviz format
   */
  public String toDOTFormat() {
    StringBuilder sb = new StringBuilder();
    sb.append("graph graphname {\n");
    for (int i = 0; i < nodeNum; i++) {
      sb.append("n" + i + ";\n");
    }
    for (int i = 0; i < nodeNum; i++) {
      TIntArrayList outList = this.adjLists.get(i);
      for (int oInd = 0; oInd < outList.size(); oInd++) {
        if (i < outList.get(oInd)) {
          sb.append("n" + i + " -- n" + outList.get(oInd) + ";\n");
        }
      }
    }
    sb.append("}\n");
    return sb.toString();
  }

  public String toGMLFormat() {
    StringBuilder sb = new StringBuilder();
    sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<graphml xmlns=\"http://graphml.graphdrawing.org/xmlns\" "
        + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
        + "xsi:schemaLocation=\"http://graphml.graphdrawing.org/xmlns "
        + "http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd\">\n");

    sb.append("<graph id=\"G\" edgedefault=\"undirected\">\n");
    for (int i = 0; i < nodeNum; i++) {
      sb.append("<node id=\"n" + i + "\"/>\n");
    }
    int edge = 0;
    for (int i = 0; i < nodeNum; i++) {
      TIntArrayList outList = this.adjLists.get(i);
      for (int oInd = 0; oInd < outList.size(); oInd++) {
        if (i < outList.get(oInd)) {
          sb.append("<edge id=\"e" + edge + "\" source=\"n" + i
              + "\" target=\"n" + outList.get(oInd) + "\"/>\n");
          edge++;
        }
      }
    }

    sb.append("</graph>");
    sb.append("</graphml>\n");
    return sb.toString();
  }

  public String toXGMMLFormat() {
    StringBuilder sb = new StringBuilder();
    sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n");
    sb.append("<graph label=\"graph\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" "
        + "xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\" "
        + "xmlns:cy=\"http://www.cytoscape.org\" xmlns=\"http://www.cs.rpi.edu/XGMML\"  directed=\"0\">\n");
    for (int i = 0; i < nodeNum; i++) {
      sb.append("<node id=\"n" + i + "\" label=\"n" + i + "\">\n");
      sb.append("\t<att name=\"size\" type=\"integer\" value=\"1\"/>\n");
      // + "<att name=\"confirmed\" type=\"boolean\" value=\"true\"/>");
      sb.append("</node>\n");
    }
    int edge = 0;
    for (int i = 0; i < nodeNum; i++) {
      TIntArrayList outList = this.adjLists.get(i);
      for (int oInd = 0; oInd < outList.size(); oInd++) {
        if (i < outList.get(oInd)) {
          sb.append("<edge label=\"d\" id=\"e" + edge
              + "\" source=\"n" + i + "\" target=\"n"
              + outList.get(oInd) + "\"/>\n");
          edge++;
        }
      }
    }

    sb.append("</graph>\n");
    return sb.toString();
  }

  /**
   * Copy the current graph into the given {@link FlexibleUndirectedGraph}.
   * The given graph is cleared before the copy using {@link #clear()}.
   *
   * @param other
   *            the graph that we want to copy the information to.
   */
  public void copyTo(FlexibleUndirectedGraph other) {
    other.clear();
    for (int i = 0; i < nodeNum; i++) {
      other.addNode();
    }
    for (int u = 0; u < nodeNum; u++) {
      TIntArrayList adj = this.adjLists.get(u);
      for (int d = 0; d < adj.size(); d++) {
        final int v = adj.get(d);
        if (u < v) {
          other.addEdge(u, v);
        }
      }
    }
  }

  /**
   * Calculate the density of the graph
   *
   * @return the density of the graph
   */
  public double density() {
    return (2.0 * this.edgeNum) / (this.nodeNum * (this.nodeNum - 1));
  }

  /**
   * Split the current graph <V,E> into two subgraphs G<sub>1</sub> and
   * G<sub>2</sub> according to group W, both subgraphs contains all the nodes
   * in V but G<sub>1</sub> contains E<sub>1</sub>&#8838;E for each edge (u,v)
   * in E<sub>1</sub> which both u,v&#8712W;. G<sub>1</sub> contains only
   * edges (u,v) from E where both u,v&#8712(V\W)
   *
   * @param list
   *            - assume that the list is ordered (for searching)
   * @param graph1
   *            - an empty {@link FlexibleUndirectedGraph}.
   * @param graph2
   *            - an empty {@link FlexibleUndirectedGraph}.
   */
  public void split(TIntArrayList list, FlexibleUndirectedGraph graph1,
      FlexibleUndirectedGraph graph2) {
    for (int i = 0; i < nodeNum; i++) {
      graph1.addNode();
      graph2.addNode();
    }
    for (int u = 0; u < nodeNum; u++) {
      boolean firstInG1 = list != null ? list.binarySearch(u) >= 0 : true;
      boolean firstInG2 = !firstInG1;
      TIntArrayList adj = adjLists.get(u);
      for (int d = 0; d < adj.size(); d++) {
        final int v = adj.get(d);
        if (u < v) {
          boolean secondInG1 = list != null ? list.binarySearch(v) >= 0
              : true;
          boolean secondInG2 = !secondInG1;
          if (firstInG1 && secondInG1) {
            graph1.addEdge(u, v);
          } else if (firstInG2 && secondInG2) {
            graph2.addEdge(u, v);
          }
        }
      }
    }
  }

  public JSONObject toJSON() throws JSONException {
    JSONObject jsonObject = new JSONObject();
    jsonObject.put("nodes", this.getNodeNum());
    JSONArray array = new JSONArray();
    for (int i = 0; i < nodeNum; i++) {
      JSONArray inner = new JSONArray();
      TIntArrayList adj = adjLists.get(i);
      for (int d = 0; d < adj.size(); d++) {
        if (adj.get(d) > i) {
          inner.put(adj.get(d));
        }
      }
      array.put(inner);
    }
    jsonObject.put("edges", array);
    return jsonObject;
  }

  public static FlexibleUndirectedGraph fromJSON(JSONObject json)
      throws JSONException {
    FlexibleUndirectedGraph graph = new FlexibleUndirectedGraph();
    for (int i = 0; i < json.getInt("nodes"); i++) {
      graph.addNode();
    }
    JSONArray edges = json.getJSONArray("edges");
    for (int i = 0; i < graph.getNodeNum(); i++) {
      JSONArray current = edges.getJSONArray(i);
      for (int x = 0; x < current.length(); x++) {
        graph.addEdge(i, current.getInt(x));
      }
    }
    return graph;
  }

  public String stats() {
    StringBuilder sb = new StringBuilder();
    sb.append("Density = " + density());
    sb.append("\tNodes = " + nodeNum);
    sb.append("\tEdges = " + edgeNum);
    sb.append("\tMaxDegree = " + maxDegree);
    sb.append("\tDegeneracy = " + degeneracy());
    return sb.toString();
  }
}
TOP

Related Classes of bgu.bio.adt.graphs.FlexibleUndirectedGraph

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.