private void zoomOut() {
      int M = communities.size();
      LinkedList<Edge>[] newTopology = new LinkedList[M];
      int index = 0;
      nodeCommunities = new Community[M];
      nodeConnectionsWeight = new HashMap[M];
      nodeConnectionsCount = new HashMap[M];
      HashMap<Integer, Community> newInvMap = new HashMap<>();
      for (int i = 0; i < communities.size(); i++) { // Community com : mCommunities) {
        Community com = communities.get(i);
        nodeConnectionsWeight[index] = new HashMap<>();
        nodeConnectionsCount[index] = new HashMap<>();
        newTopology[index] = new LinkedList<>();
        nodeCommunities[index] = new Community(com);
        Set<Community> iter = com.connectionsWeight.keySet();
        double weightSum = 0;

        Community hidden = new Community(structure);
        for (Integer nodeInt : com.nodes) {
          Community oldHidden = invMap.get(nodeInt);
          hidden.nodes.addAll(oldHidden.nodes);
        }
        newInvMap.put(index, hidden);
        for (Community adjCom : iter) {
          int target = communities.indexOf(adjCom);
          double weight = com.connectionsWeight.get(adjCom);
          if (target == index) {
            weightSum += 2. * weight;
          } else {
            weightSum += weight;
          }
          Edge e = new Edge(index, target, weight);
          newTopology[index].add(e);
        }
        weights[index] = weightSum;
        nodeCommunities[index].seed(index);

        index++;
      }
      communities.clear();

      for (int i = 0; i < M; i++) {
        Community com = nodeCommunities[i];
        communities.add(com);
        for (Edge e : newTopology[i]) {
          nodeConnectionsWeight[i].put(
              nodeCommunities[e.getTarget()],
              Double.parseDouble(e.getProperty("weight").toString()));
          nodeConnectionsCount[i].put(nodeCommunities[e.getTarget()], 1);
          com.connectionsWeight.put(
              nodeCommunities[e.getTarget()],
              Double.parseDouble(e.getProperty("weight").toString()));
          com.connectionsCount.put(nodeCommunities[e.getTarget()], 1);
        }
      }

      N = M;
      topology = newTopology;
      invMap = newInvMap;
    }
    private void addNodeTo(int node, Community to) {
      to.add(node);
      nodeCommunities[node] = to;

      for (Edge e : topology[node]) {
        int neighbor;
        neighbor = e.getTarget();

        // Remove Node Connection to this community
        Double neighEdgesTo = nodeConnectionsWeight[neighbor].get(to);
        if (neighEdgesTo == null) {
          nodeConnectionsWeight[neighbor].put(
              to, Double.parseDouble(e.getProperty("weight").toString()));
        } else {
          nodeConnectionsWeight[neighbor].put(
              to, neighEdgesTo + Double.parseDouble(e.getProperty("weight").toString()));
        }
        Integer neighCountEdgesTo = nodeConnectionsCount[neighbor].get(to);
        if (neighCountEdgesTo == null) {
          nodeConnectionsCount[neighbor].put(to, 1);
        } else {
          nodeConnectionsCount[neighbor].put(to, neighCountEdgesTo + 1);
        }

        Community adjCom = nodeCommunities[neighbor];
        Double wEdgesto = adjCom.connectionsWeight.get(to);
        if (wEdgesto == null) {
          adjCom.connectionsWeight.put(to, Double.parseDouble(e.getProperty("weight").toString()));
        } else {
          adjCom.connectionsWeight.put(
              to, wEdgesto + Double.parseDouble(e.getProperty("weight").toString()));
        }

        Integer cEdgesto = adjCom.connectionsCount.get(to);
        if (cEdgesto == null) {
          adjCom.connectionsCount.put(to, 1);
        } else {
          adjCom.connectionsCount.put(to, cEdgesto + 1);
        }

        Double nodeEdgesTo = nodeConnectionsWeight[node].get(adjCom);
        if (nodeEdgesTo == null) {
          nodeConnectionsWeight[node].put(
              adjCom, Double.parseDouble(e.getProperty("weight").toString()));
        } else {
          nodeConnectionsWeight[node].put(
              adjCom, nodeEdgesTo + Double.parseDouble(e.getProperty("weight").toString()));
        }

        Integer nodeCountEdgesTo = nodeConnectionsCount[node].get(adjCom);
        if (nodeCountEdgesTo == null) {
          nodeConnectionsCount[node].put(adjCom, 1);
        } else {
          nodeConnectionsCount[node].put(adjCom, nodeCountEdgesTo + 1);
        }

        if (to != adjCom) {
          Double comEdgesto = to.connectionsWeight.get(adjCom);
          if (comEdgesto == null) {
            to.connectionsWeight.put(
                adjCom, Double.parseDouble(e.getProperty("weight").toString()));
          } else {
            to.connectionsWeight.put(
                adjCom, comEdgesto + Double.parseDouble(e.getProperty("weight").toString()));
          }

          Integer comCountEdgesto = to.connectionsCount.get(adjCom);
          if (comCountEdgesto == null) {
            to.connectionsCount.put(adjCom, 1);
          } else {
            to.connectionsCount.put(adjCom, comCountEdgesto + 1);
          }
        }
      }
    }
    private void removeNodeFrom(int node, Community from) {

      Community community = nodeCommunities[node];
      for (Edge e : topology[node]) {
        int neighbor = e.getTarget();

        ////////
        // Remove Node Connection to this community
        Double edgesTo = nodeConnectionsWeight[neighbor].get(community);
        int countEdgesTo = nodeConnectionsCount[neighbor].get(community);
        if (countEdgesTo - 1 == 0) {
          nodeConnectionsWeight[neighbor].remove(community);
          nodeConnectionsCount[neighbor].remove(community);
        } else {
          nodeConnectionsWeight[neighbor].put(
              community, edgesTo - Double.parseDouble(e.getProperty("weight").toString()));
          nodeConnectionsCount[neighbor].put(community, countEdgesTo - 1);
        }

        ///////////////////
        // Remove Adjacency Community's connection to this community
        Community adjCom = nodeCommunities[neighbor];
        Double oEdgesto = adjCom.connectionsWeight.get(community);
        int oCountEdgesto = adjCom.connectionsCount.get(community);
        if (oCountEdgesto - 1 == 0) {
          adjCom.connectionsWeight.remove(community);
          adjCom.connectionsCount.remove(community);
        } else {
          adjCom.connectionsWeight.put(
              community, oEdgesto - Double.parseDouble(e.getProperty("weight").toString()));
          adjCom.connectionsCount.put(community, oCountEdgesto - 1);
        }

        if (node == neighbor) {
          continue;
        }

        if (adjCom != community) {
          Double comEdgesto = community.connectionsWeight.get(adjCom);
          Integer comCountEdgesto = community.connectionsCount.get(adjCom);
          if (comCountEdgesto - 1 == 0) {
            community.connectionsWeight.remove(adjCom);
            community.connectionsCount.remove(adjCom);
          } else {
            community.connectionsWeight.put(
                adjCom, comEdgesto - Double.parseDouble(e.getProperty("weight").toString()));
            community.connectionsCount.put(adjCom, comCountEdgesto - 1);
          }
        }

        Double nodeEgesTo = nodeConnectionsWeight[node].get(adjCom);
        Integer nodeCountEgesTo = nodeConnectionsCount[node].get(adjCom);
        if (nodeCountEgesTo - 1 == 0) {
          nodeConnectionsWeight[node].remove(adjCom);
          nodeConnectionsCount[node].remove(adjCom);
        } else {
          nodeConnectionsWeight[node].put(
              adjCom, nodeEgesTo - Double.parseDouble(e.getProperty("weight").toString()));
          nodeConnectionsCount[node].put(adjCom, nodeCountEgesTo - 1);
        }
      }
      from.remove(node);
    }