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

rinde.sim.util.MapPreprocessor Maven / Gradle / Ivy

There is a newer version: 4.4.6
Show newest version
/**
 * 
 */
package rinde.sim.util;

import static java.util.Arrays.asList;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import rinde.sim.core.graph.Connection;
import rinde.sim.core.graph.ConnectionData;
import rinde.sim.core.graph.Graph;
import rinde.sim.core.graph.Graphs;
import rinde.sim.core.graph.LengthData;
import rinde.sim.core.graph.MultiAttributeData;
import rinde.sim.core.graph.MultimapGraph;
import rinde.sim.core.graph.PathNotFoundException;
import rinde.sim.core.graph.Point;
import rinde.sim.core.graph.TableGraph;
import rinde.sim.serializers.DotGraphSerializer;

import com.google.common.collect.Sets;

/**
 * @author Rinde van Lon ([email protected])
 * 
 */
@Deprecated
public class MapPreprocessor {

  private static  Graph hack(Graph graph) {
    final Graph newGraph = new MultimapGraph();
    newGraph.merge(graph);

    final HashSet connected = new HashSet();
    final HashSet neighbors = new HashSet();

    final Point root = graph.getNodes().iterator().next();
    connected.add(root);
    neighbors.addAll(graph.getOutgoingConnections(root));

    fixCluster(newGraph, connected, neighbors, new HashSet());
    return newGraph;
  }

  public static  Graph connect2(Graph graph) {
    final Graph newGraph = new MultimapGraph();
    newGraph.merge(graph);

    final HashSet connected = new HashSet();
    final HashSet neighbors = new HashSet();

    final Point root = graph.getNodes().iterator().next();
    connected.add(root);
    neighbors.addAll(graph.getOutgoingConnections(root));
    fixCluster(newGraph, connected, neighbors, new HashSet());

    Set unconnected;
    while (!(unconnected = Sets.difference(newGraph.getNodes(), connected))
        .isEmpty()) {
      final Point p = unconnected.iterator().next();
      System.out.println("unconnected: " + unconnected.size());
      final HashSet cluster = new HashSet(asList(p));
      fixCluster(newGraph, cluster,
          new HashSet(newGraph.getOutgoingConnections(p)), connected);
      // System.out.println("cluster: " + cluster);
      final Tuple pair = findClosestPair(cluster, connected);

      if (!isConnected(newGraph, cluster, connected)) {
        // System.out.println("not connection from cluster -> main");
        newGraph.addConnection(pair.getKey(), pair.getValue());
        newGraph.addConnection(pair.getValue(), pair.getKey());
      }

      connected.addAll(cluster);
    }

    // newGraph.put(findClosest(p, connected), p);
    // connected.add(p);
    // }

    //
    // if( neighbour n isConnectedWith(n, connectedSet) )
    // add to connected set
    // else
    // create connection from n to one of the connectedSet (maybe make one
    // of them bidirectional)
    // endwhile

    // traverse all unvisited nodes, create connection between each
    // unvisited node and one of the connected nodes.

    return newGraph;
  }

  private static  void fixCluster(Graph newGraph,
      HashSet connected, HashSet neighbors,
      HashSet otherClusters) {
    // System.out.println(">> fixCluster");
    while (!neighbors.isEmpty()) {
      final Point n = neighbors.iterator().next();
      assert n != null;
      // System.out.println(n);
      neighbors.remove(n);
      // if this point is also in a other cluster, we don't have to check
      // its neighbors
      if (!otherClusters.contains(n)) {
        for (final Point b : newGraph.getOutgoingConnections(n)) {
          if (b != null && !connected.contains(b) && !neighbors.contains(b)) {

            neighbors.add(b);
          }
        }
      }
      if (!isConnectedWith(newGraph, n, connected)) {
        assert n != null;
        assert !connected.isEmpty();
        assert !newGraph.isEmpty();
        newGraph.addConnection(n, findClosest(n, connected));// connect
                                                             // it
      }
      connected.add(n);
    }
  }

  /**
   * @param n
   * @param set
   */
  private static Point findClosest(Point n, Set set) {
    double minDist = Double.POSITIVE_INFINITY;
    Point closest = null;
    for (final Point p : set) {
      assert p != null;
      final double dist = Point.distance(p, n);
      if (dist < minDist) {
        minDist = dist;
        closest = p;
      }
    }
    assert closest != null;
    return closest;
  }

  private static Tuple findClosestPair(Set set1,
      Set set2) {
    double minDist = Double.POSITIVE_INFINITY;
    Tuple closestPair = null;
    for (final Point p : set1) {
      final Point c = findClosest(p, set2);
      final double dist = Point.distance(p, c);
      if (dist < minDist) {
        minDist = dist;
        closestPair = new Tuple(p, c);
      }
    }
    return closestPair;
  }

  private static  boolean isConnected(Graph graph,
      Set set1, Set set2) {
    final HashSet visited = new HashSet();
    final HashSet queue = new HashSet();
    queue.addAll(set1);
    while (!queue.isEmpty()) {
      final Point b = queue.iterator().next();
      queue.remove(b);
      final Collection neighbours = graph.getOutgoingConnections(b);
      for (final Point n : neighbours) {
        if (set2.contains(n)) {
          return true;
        }
        if (!visited.contains(n)) {
          queue.add(n);
        }
      }
      visited.add(b);
    }
    return false;
  }

  /**
   * checks if it is possible to reach a point in set by following
   * the outgoing arcs in point p.
   * @param graph
   * @param p
   * @param set
   * @return
   */
  private static boolean isConnectedWith(Graph graph, Point p, Set set) {
    return isConnected(graph, new HashSet(asList(p)), set);
  }

  public static  Graph removeUnconnectedSubGraphs(
      Graph graph, E empty) {
    final Graph currentGraph = new TableGraph(empty);
    currentGraph.merge(graph);

    final List> result = findNotFullyConnectedNodes(currentGraph);
    int totalSize = 0;
    int biggestIndex = -1;
    int biggestSize = -1;
    for (int i = 0; i < result.size(); i++) {
      totalSize += result.get(i).size();
      if (result.get(i).size() > biggestSize) {
        biggestSize = result.get(i).size();
        biggestIndex = i;
      }
    }

    for (int i = 0; i < result.size(); i++) {
      if (i != biggestIndex) {
        System.out.println("removing: " + i + " " + result.size());
        for (final Point p : result.get(i)) {
          currentGraph.removeNode(p);
        }
      }
    }

    System.out.println("Removed " + (result.size() - 1)
        + " subgraphs, with total size "
        + (totalSize - currentGraph.getNumberOfNodes())
        + " nodes, resulting graph has: " + currentGraph.getNumberOfNodes()
        + " nodes.");
    System.out.println(totalSize);
    System.out.println(currentGraph.getNumberOfNodes());

    return currentGraph;
  }

  public static  Graph connect(Graph graph) {
    final Graph currentGraph = new MultimapGraph();
    currentGraph.merge(graph);

    List> result = findNotFullyConnectedNodes(currentGraph);

    boolean isFullyConnected = false;
    while (!isFullyConnected) {

      final Set unconnected = result.get(0);
      final Set connected = result.get(1);

      double minDist = Double.POSITIVE_INFINITY;
      Tuple connection = null;
      for (final Point u : unconnected) {
        for (final Point c : connected) {
          final double dist = Point.distance(u, c);
          if (dist < minDist) {
            minDist = dist;
            connection = new Tuple(u, c);
          }
        }
      }

      if (!currentGraph.hasConnection(connection.getKey(),
          connection.getValue())) {
        currentGraph.addConnection(connection.getKey(), connection.getValue());
      }
      if (!currentGraph.hasConnection(connection.getValue(),
          connection.getKey())) {
        currentGraph.addConnection(connection.getValue(), connection.getKey());
      }
      result = findNotFullyConnectedNodes(currentGraph);
      if (result.get(0).isEmpty()) {
        isFullyConnected = true;
      }
    }

    return currentGraph;
  }

  private static  Set unseenNeighbours(
      Graph g, Set seen, Set current) {
    final HashSet set = new HashSet();
    for (final Point p : current) {
      set.addAll(g.getIncomingConnections(p));
      set.addAll(g.getOutgoingConnections(p));
    }
    set.removeAll(seen);
    return set;
  }

  private static  boolean isConnected(Graph g,
      Point from, Point to, Set subgraph) {

    Point cur = from;
    final Set seen = new HashSet();

    while (true) {
      seen.add(cur);
      final Set ns = new HashSet(g.getOutgoingConnections(cur));

      ns.retainAll(subgraph);
      ns.removeAll(seen);

      if (ns.contains(to)) {
        return true;
      } else if (ns.isEmpty()) {
        return false;
      } else if (ns.size() == 1) {
        cur = ns.iterator().next();
      } else {
        throw new RuntimeException("not expected..");
      }

    }

  }

  public static  double getLength(Graph g,
      Point from, Point to) {
    final E connectionData = g.connectionData(from, to);
    if (connectionData == null || Double.isNaN(connectionData.getLength())) {
      return Point.distance(from, to);
    } else {
      return connectionData.getLength();
    }
  }

  public static  Graph simplify(Graph g, E empty) {
    final TableGraph newGraph = new TableGraph(empty);
    newGraph.merge(g);
    boolean working = true;

    // int iterations = 0;
    while (working) {
      // System.out.println("starting iteration: " + iterations);
      // iterations++;
      boolean edit = false;
      // System.out.println(newGraph.getConnections());

      final HashSet> connections = new HashSet>(
          newGraph.getConnections());
      final HashSet> removeList = new HashSet>();
      for (final Connection connection : connections) {
        if (removeList.contains(connection)) {
          continue;
        }
        final Point left = connection.from;
        final Point right = connection.to;

        final ContractType type = isContractable(newGraph, left, right);
        // System.out.println(type + " " + left + " " + right);
        if (type == ContractType.NO) {
          continue;
        } else {
          // double length = getLength(newGraph, left, right);

          final E removeEdgeData = newGraph.connectionData(left, right);
          final double removeLength = newGraph.connectionLength(left, right);
          removeList.add(newGraph.getConnection(left, right));
          newGraph.removeConnection(left, right);

          final Point removeNode = (type == ContractType.RIGHT) ? right : left;
          final Point mergeNode = (type == ContractType.RIGHT) ? left : right;

          // System.out.println("remove: " + removeNode);
          // System.out.println("merge into: " + mergeNode);
          for (final Point outgoing : newGraph
              .getOutgoingConnections(removeNode)) {
            if (!outgoing.equals(mergeNode)) {
              final E edgeData = newGraph.connectionData(removeNode, outgoing);
              final double edgeLength = newGraph.connectionLength(removeNode,
                  outgoing);
              // double newLength = length + getLength(newGraph,
              // removeNode, outgoing);

              if (!newGraph.hasConnection(mergeNode, outgoing)) {
                newGraph.addConnection(
                    mergeNode,
                    outgoing,
                    mergeEdgeData(empty, removeEdgeData, removeLength,
                        edgeData, edgeLength));
              }
              // if (clazz.equals(LengthEdgeData.class)) {
              // newGraph.addConnection(mergeNode, outgoing, (E)
              // new LengthEdgeData(newLength));
              // } else if
              // (clazz.equals(MultiAttributeEdgeData.class)) {
              // throw new UnsupportedOperationException();
              // TODO Merge the MultiAttributeEdgeData object
              // here!
              // MultiAttributeEdgeData maed =
              // (MultiAttributeEdgeData)
              // newGraph.connectionData(removeNode, outgoing);
              //
              // if(!Double.isNaN(maed.getMaxSpeed())){
              //
              // }
              // newGraph.addConnection(mergeNode, outgoing, (E)
              // new MultiAttributeEdgeData(newLength));
              // } else {
              // throw new UnsupportedOperationException();
              // }
            }
          }
          for (final Point incoming : newGraph
              .getIncomingConnections(removeNode)) {
            if (!incoming.equals(mergeNode)) {
              final E edgeData = newGraph.connectionData(incoming, removeNode);
              final double edgeLength = newGraph.connectionLength(incoming,
                  removeNode);

              // double newLength = length + getLength(newGraph,
              // incoming, removeNode);
              if (!newGraph.hasConnection(incoming, mergeNode)) {
                newGraph.addConnection(
                    incoming,
                    mergeNode,
                    mergeEdgeData(empty, edgeData, edgeLength, removeEdgeData,
                        removeLength));
              }
              // if (clazz.equals(LengthEdgeData.class)) {
              //
              // } else {
              // throw new UnsupportedOperationException();
              // }

              // newGraph.addConnection(incoming, mergeNode, new
              // LengthEdgeData(newLength));
            }
          }

          final Collection in = newGraph
              .getIncomingConnections(removeNode);
          for (final Point p : in) {
            removeList.add(newGraph.getConnection(p, removeNode));
          }
          final Collection out = newGraph
              .getOutgoingConnections(removeNode);
          for (final Point p : out) {
            removeList.add(newGraph.getConnection(removeNode, p));
          }

          newGraph.removeNode(removeNode);
          edit = true;
          // break;
        }
      }
      if (!edit) {
        working = false;
      }
    }
    return newGraph;
  }

  // TODO also check if input values are valid!!
  // TODO do something with maxSpeed!!
  @SuppressWarnings("unchecked")
  static  E mergeEdgeData(E empty, E e1, double l1,
      E e2, double l2) {
    if (empty instanceof LengthData) {
      return (E) new LengthData(l1 + l2);
    } else if (empty instanceof MultiAttributeData) {
      return (E) new MultiAttributeData(l1 + l2);
    }
    throw new IllegalArgumentException("EdgeData objects are of unknown type");
  }

  enum ContractType {
    BOTH, LEFT, RIGHT, NO
  }

  // TODO fix this method to also take the EdgeData into account
  static ContractType isContractable(Graph g,
      Point node1, Point node2) {
    final boolean n12 = g.getOutgoingConnections(node1).contains(node2);
    final boolean n21 = g.getOutgoingConnections(node2).contains(node1);

    if (!(n12 || n21)) {
      throw new IllegalArgumentException(
          "There is no connection between the nodes.");
    }
    final boolean bidi1 = n12 && n21;
    boolean bidi0 = false, bidi2 = false;

    final Set outgoing1 = new HashSet(
        g.getOutgoingConnections(node1));
    final Set incoming1 = new HashSet(
        g.getIncomingConnections(node1));
    outgoing1.remove(node2);
    incoming1.remove(node2);

    final Set outgoing2 = new HashSet(
        g.getOutgoingConnections(node2));
    final Set incoming2 = new HashSet(
        g.getIncomingConnections(node2));
    outgoing2.remove(node1);
    incoming2.remove(node1);

    final Set neighbors1 = new HashSet();
    neighbors1.addAll(outgoing1);
    neighbors1.addAll(incoming1);

    if (neighbors1.size() == 1) {
      final Point node0 = neighbors1.iterator().next();
      bidi0 = outgoing1.contains(node0) && incoming1.contains(node0);
    }

    final Set neighbors2 = new HashSet();
    neighbors2.addAll(outgoing2);
    neighbors2.addAll(incoming2);

    if (neighbors2.size() == 1) {
      final Point node3 = neighbors2.iterator().next();
      bidi2 = outgoing2.contains(node3) && incoming2.contains(node3);
    }

    if (neighbors1.size() != 1 && neighbors2.size() != 1) {
      return ContractType.NO;
    } else if (neighbors1.size() == 1 && neighbors2.size() == 1) {
      final boolean sameneigh = neighbors1.iterator().next()
          .equals(neighbors2.iterator().next());

      if (sameneigh) {
        if (!bidi0 && !bidi1 && !bidi2) {
          return ContractType.BOTH;
        }
        return ContractType.NO;
      }

      if ((bidi0 == bidi1) && (bidi1 == bidi2)) {
        return ContractType.BOTH;
      } else if ((bidi0 == bidi1) && (bidi1 != bidi2)) {
        return ContractType.LEFT;
      } else if ((bidi0 != bidi1) && (bidi1 == bidi2)) {
        return ContractType.RIGHT;
      } else {
        return ContractType.NO;
      }
    } else if (neighbors1.size() == 1 && neighbors2.size() != 1) {
      return bidi0 == bidi1 ? ContractType.LEFT : ContractType.NO;
    } else if (neighbors1.size() != 1 && neighbors2.size() == 1) {
      return bidi1 == bidi2 ? ContractType.RIGHT : ContractType.NO;
    }

    throw new IllegalStateException("Unexpected node configuration..");
  }

  public static  List> findNotFullyConnectedNodes(
      Graph graph) {
    if (graph == null || graph.isEmpty()) {
      throw new IllegalArgumentException(
          "Graph may not be null and must contain at least one node.");
    }
    // just get a 'random' starting point
    return findNotFullyConnectedNodes(graph,
        new ArrayList(graph.getNodes()).get(0));
  }

  public static  List> findNotFullyConnectedNodes(
      Graph graph, Point root) {

    final HashSet fullyConnectedSet = new HashSet();
    final HashSet neighbours = new HashSet();
    final HashSet notConnectedSet = new HashSet();

    fullyConnectedSet.add(root);
    neighbours.addAll(graph.getOutgoingConnections(root));

    while (!neighbours.isEmpty()) {
      List path = null;
      final Point current = neighbours.iterator().next();
      neighbours.remove(current);
      if (graph.containsNode(current)) {
        try {
          path = Graphs.shortestPathEuclideanDistance(graph, current, root);
        } catch (final PathNotFoundException e) {/*
                                                  * this is intentionally empty
                                                  */}
      }

      if (path == null) {
        notConnectedSet.add(current);
      } else {
        for (final Point p : path) {
          fullyConnectedSet.add(p);
          if (neighbours.contains(p)) {
            neighbours.remove(p);
          }
          for (final Point q : graph.getOutgoingConnections(p)) {
            if (!fullyConnectedSet.contains(q)) {
              neighbours.add(q);
            }
          }
        }
      }
    }
    for (final Point p : graph.getNodes()) {
      if (!fullyConnectedSet.contains(p)) {
        notConnectedSet.add(p);
      }
    }

    return new ArrayList>(asList(notConnectedSet, fullyConnectedSet));
  }

  // when executing there should be two folders at the same level as this
  // class (or jar):
  // 1. osm-files/
  // 2. dot-files/
  // when calling main("brussels") a file named brussels.osm is expected in
  // osm-files. All .dot output is written in dot-files.
  public static void main2(String[] args) throws FileNotFoundException,
      IOException {
    final DotGraphSerializer serializer = DotGraphSerializer
        .getMultiAttributeGraphSerializer();

    final String name = "leuven";// args[0];// "wroclaw";
    final String file = "/Users/rindevanlon/Downloads/temp.osm";

    System.out.println(name);
    final Graph g = OSM.parse(file);// "osm-files/" + name +
                                                        // ".osm");
    serializer.write(g, "dot-files/" + name + "-raw.dot");
    System.out.println(g);

    final long startRead = System.currentTimeMillis();
    final Graph g2 = serializer.read("dot-files/" + name
        + "-raw.dot");
    System.out.println("loading took: "
        + (System.currentTimeMillis() - startRead));
    Graph graph = new TableGraph(
        MultiAttributeData.EMPTY);
    graph.merge(g2);
    System.out.println("(V,E) = (" + graph.getNumberOfNodes() + ","
        + graph.getNumberOfConnections() + ")");

    // final long startSimplify = System.currentTimeMillis();
    // graph = MapPreprocessor.simplify(graph, MultiAttributeData.EMPTY);
    // System.out.println("simplifying took: "
    // + (System.currentTimeMillis() - startSimplify));

    final long startFix = System.currentTimeMillis();
    graph = MapPreprocessor.removeUnconnectedSubGraphs(graph,
        MultiAttributeData.EMPTY);
    System.out.println("fixing took: "
        + (System.currentTimeMillis() - startFix));
    serializer.write(graph, "dot-files/" + name + "-simple.dot");
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy