MATSIM
MultimodalNetworkCleaner.java
Go to the documentation of this file.
1 /* *********************************************************************** *
2  * project: org.matsim.*
3  * *
4  * *********************************************************************** *
5  * *
6  * copyright : (C) 2010 by the members listed in the COPYING, *
7  * LICENSE and WARRANTY file. *
8  * email : info at matsim dot org *
9  * *
10  * *********************************************************************** *
11  * *
12  * This program is free software; you can redistribute it and/or modify *
13  * it under the terms of the GNU General Public License as published by *
14  * the Free Software Foundation; either version 2 of the License, or *
15  * (at your option) any later version. *
16  * See also COPYING, LICENSE and WARRANTY file *
17  * *
18  * *********************************************************************** */
19 
20 package org.matsim.core.network.algorithms;
21 
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.HashMap;
25 import java.util.HashSet;
26 import java.util.Iterator;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Set;
30 import java.util.TreeMap;
31 
32 import org.apache.logging.log4j.LogManager;
33 import org.apache.logging.log4j.Logger;
34 import org.matsim.api.core.v01.Id;
38 
49 public final class MultimodalNetworkCleaner {
50 
51  private final static Logger log = LogManager.getLogger(MultimodalNetworkCleaner.class);
52 
53  private final Network network;
54 
55  private final Set<Id<Link>> removedLinks = new HashSet<>();
56  private final Set<Id<Link>> modifiedLinks = new HashSet<>();
57 
58  public MultimodalNetworkCleaner(final Network network) {
59  this.network = network;
60  }
61 
65  public void removeNodesWithoutLinks() {
66  List<Node> toBeRemoved = new ArrayList<>();
67  for (Node node : this.network.getNodes().values()) {
68  if ((node.getInLinks().size() == 0) && (node.getOutLinks().size() == 0)) {
69  toBeRemoved.add(node);
70  }
71  }
72  for (Node node : toBeRemoved) {
73  this.network.removeNode(node.getId());
74  }
75  }
76 
87  public void run(final Set<String> modes) {
88  run(modes, new HashSet<String>());
89  }
90 
111  public void run(final Set<String> cleaningModes, final Set<String> connectivityModes) {
112  final Set<String> combinedModes = new HashSet<>(cleaningModes);
113  combinedModes.addAll(connectivityModes);
114  final Map<Id<Link>, Link> visitedLinks = new TreeMap<>();
115  Map<Id<Link>, Link> biggestCluster = new TreeMap<>();
116 
117  log.info("running " + this.getClass().getName() + " algorithm for modes " + Arrays.toString(cleaningModes.toArray())
118  + " with connectivity modes " + Arrays.toString(connectivityModes.toArray()) + "...");
119 
120  // search the biggest cluster of nodes in the network
121  log.info(" checking " + this.network.getNodes().size() + " nodes and " +
122  this.network.getLinks().size() + " links for dead-ends...");
123  boolean stillSearching = true;
124  Iterator<? extends Link> iter = this.network.getLinks().values().iterator();
125  while (iter.hasNext() && stillSearching) {
126  Link startLink = iter.next();
127  if ((!visitedLinks.containsKey(startLink.getId())) && (intersectingSets(combinedModes, startLink.getAllowedModes()))) {
128  Map<Id<Link>, Link> cluster = this.findCluster(startLink, combinedModes);
129  visitedLinks.putAll(cluster);
130  if (cluster.size() > biggestCluster.size()) {
131  biggestCluster = cluster;
132  if (biggestCluster.size() >= (this.network.getLinks().size() - visitedLinks.size())) {
133  // stop searching here, because we cannot find a bigger cluster in the lasting nodes
134  stillSearching = false;
135  }
136  }
137  }
138  }
139  log.info(" The biggest cluster consists of " + biggestCluster.size() + " links.");
140  log.info(" done.");
141 
142  /* Remove the modes from all links not being part of the cluster. If a link has no allowed mode
143  * anymore after this, remove the link from the network.
144  */
145  List<Link> allLinks = new ArrayList<>(this.network.getLinks().values());
146  for (Link link : allLinks) {
147  if (!biggestCluster.containsKey(link.getId())) {
148  Set<String> reducedModes = new HashSet<>(link.getAllowedModes());
149  reducedModes.removeAll(cleaningModes);
150  link.setAllowedModes(reducedModes);
151  if (reducedModes.isEmpty()) {
152  this.network.removeLink(link.getId());
153  if ((link.getFromNode().getInLinks().size() + link.getFromNode().getOutLinks().size()) == 0) {
154  this.network.removeNode(link.getFromNode().getId());
155  }
156  if ((link.getToNode().getInLinks().size() + link.getToNode().getOutLinks().size()) == 0) {
157  this.network.removeNode(link.getToNode().getId());
158  }
159  this.removedLinks.add(link.getId());
160  }
161  if(!removedLinks.contains(link.getId())) modifiedLinks.add(link.getId());
162  }
163  }
164  log.info(" resulting network contains " + this.network.getNodes().size() + " nodes and " +
165  this.network.getLinks().size() + " links.");
166  log.info("done.");
167  }
168 
178  private Map<Id<Link>, Link> findCluster(final Link startLink, final Set<String> modes) {
179 
180  final Map<Id<Link>, DoubleFlagRole> linkRoles = new HashMap<>(this.network.getLinks().size());
181 
182  ArrayList<Node> pendingForward = new ArrayList<>();
183  ArrayList<Node> pendingBackward = new ArrayList<>();
184 
185  TreeMap<Id<Link>, Link> clusterLinks = new TreeMap<>();
186 
187  pendingForward.add(startLink.getToNode());
188  pendingBackward.add(startLink.getFromNode());
189 
190  // step through the network in forward mode
191  while (pendingForward.size() > 0) {
192  int idx = pendingForward.size() - 1;
193  Node currNode = pendingForward.remove(idx); // get the last element to prevent object shifting in the array
194  for (Link link : currNode.getOutLinks().values()) {
195  if (intersectingSets(modes, link.getAllowedModes())) {
196  DoubleFlagRole r = getDoubleFlag(link, linkRoles);
197  if (!r.forwardFlag) {
198  r.forwardFlag = true;
199  pendingForward.add(link.getToNode());
200  }
201  }
202  }
203  }
204 
205  // now step through the network in backward mode
206  while (pendingBackward.size() > 0) {
207  int idx = pendingBackward.size()-1;
208  Node currNode = pendingBackward.remove(idx); // get the last element to prevent object shifting in the array
209  for (Link link : currNode.getInLinks().values()) {
210  if (intersectingSets(modes, link.getAllowedModes())) {
211  DoubleFlagRole r = getDoubleFlag(link, linkRoles);
212  if (!r.backwardFlag) {
213  r.backwardFlag = true;
214  pendingBackward.add(link.getFromNode());
215  if (r.forwardFlag) {
216  // the node can be reached forward and backward, add it to the cluster
217  clusterLinks.put(link.getId(), link);
218  }
219  }
220  }
221  }
222  }
223 
224  return clusterLinks;
225  }
226 
230  public final Set<Id<Link>> getRemovedLinkIds() {
231  return removedLinks;
232  }
233 
237  public final Set<Id<Link>> getModifiedLinkIds() {
238  return modifiedLinks;
239  }
240 
253  private <T> boolean intersectingSets(final Set<T> setA, final Set<T> setB) {
254  for (T t : setA) {
255  if (setB.contains(t)) {
256  return true;
257  }
258  }
259  return false;
260  }
261 
262  private static DoubleFlagRole getDoubleFlag(final Link l, final Map<Id<Link>, DoubleFlagRole> linkRoles) {
263  DoubleFlagRole r = linkRoles.get(l.getId());
264  if (null == r) {
265  r = new DoubleFlagRole();
266  linkRoles.put(l.getId(), r);
267  }
268  return r;
269  }
270 
271  static class DoubleFlagRole {
272  boolean forwardFlag = false;
273  boolean backwardFlag = false;
274  }
275 
276 }
Map< Id< Node >, ? extends Node > getNodes()
Link removeLink(final Id< Link > linkId)
Node removeNode(final Id< Node > nodeId)
Map< Id< Link >, ? extends Link > getInLinks()
Map< Id< Link >, Link > findCluster(final Link startLink, final Set< String > modes)
Map< Id< Link >, ? extends Link > getLinks()
void run(final Set< String > cleaningModes, final Set< String > connectivityModes)
static DoubleFlagRole getDoubleFlag(final Link l, final Map< Id< Link >, DoubleFlagRole > linkRoles)
Map< Id< Link >, ? extends Link > getOutLinks()