MATSIM
DisallowedNextLinksUtils.java
Go to the documentation of this file.
1 package org.matsim.core.network.turnRestrictions;
2 
3 import java.util.ArrayList;
4 import java.util.Collections;
5 import java.util.List;
6 import java.util.Map;
7 import java.util.Map.Entry;
8 
9 import org.apache.logging.log4j.LogManager;
10 import org.apache.logging.log4j.Logger;
11 import org.matsim.api.core.v01.Id;
16 
23 
24  private static final Logger LOG = LogManager.getLogger(DisallowedNextLinksUtils.class);
25 
27  throw new IllegalStateException("Utility class");
28  }
29 
39  public static boolean isValid(Network network) {
40 
41  Map<Id<Link>, ? extends Link> links = network.getLinks();
42  List<String> errors = links.entrySet().parallelStream()
43  .map(e -> {
44  DisallowedNextLinks disallowedNextLinks = NetworkUtils.getDisallowedNextLinks(e.getValue());
45  return disallowedNextLinks != null ? Map.entry(e.getKey(), disallowedNextLinks) : null;
46  })
47  .filter(e -> e != null)
48  .flatMap(e -> getErrors(links, e.getKey(), e.getValue()).stream())
49  .toList();
50 
51  errors.forEach(LOG::warn);
52  return errors.isEmpty();
53  }
54 
61  public static void clean(Network network) {
62  Map<Id<Link>, ? extends Link> links = network.getLinks();
63 
64  links.values().forEach(link -> {
65 
67  if (dnl == null) {
68  return;
69  }
70 
71  // remove link sequences for modes, that are not allowed on this link
72  for (Entry<String, List<List<Id<Link>>>> entry : dnl.getAsMap().entrySet()) {
73  final String mode = entry.getKey();
74  final int linkSequencesCount = entry.getValue().size();
75 
76  if (!link.getAllowedModes().contains(mode)) {
78  LOG.info("Link {}: Removed all {} disallowed next link sequences of mode {}"
79  + " because {} is not allowed", link.getId(), linkSequencesCount, mode, mode);
80  }
81  }
82 
83  // keep only valid link sequences
84  for (Entry<String, List<List<Id<Link>>>> entry : dnl.getAsMap().entrySet()) {
85  final String mode = entry.getKey();
86  final List<List<Id<Link>>> linkSequences = entry.getValue();
87 
88  // find valid link sequences
89  List<List<Id<Link>>> validLinkSequences = linkSequences.stream()
90  // links of sequence exist in network
91  .filter(linkIds -> linkIds.stream().allMatch(links::containsKey))
92  // links all have mode in allowed modes
93  .filter(linkIds -> linkIds.stream()
94  .map(links::get)
96  .allMatch(allowedModes -> allowedModes.contains(mode)))
97  .toList();
98 
99  // update mode with valid link sequences
100  final int invalidLinkSequencesCount = linkSequences.size() - validLinkSequences.size();
101  if (invalidLinkSequencesCount > 0) {
103  validLinkSequences.forEach(linkIds -> dnl.addDisallowedLinkSequence(mode, linkIds));
104  LOG.info("Link {}: Removed {} disallowed next link sequences for mode {}",
105  link.getId(), invalidLinkSequencesCount, mode);
106  }
107  }
108 
109  // remove attribute completely, if it contains no link sequences anymore.
110  if (dnl.isEmpty()) {
112  }
113 
114  });
115  }
116 
117  // Helpers
118 
119  private static List<String> getErrors(Map<Id<Link>, ? extends Link> links, Id<Link> linkId,
120  DisallowedNextLinks disallowedNextLinks) {
121 
122  List<String> errors = new ArrayList<>();
123 
124  Link link = links.get(linkId);
125  for (Entry<String, List<List<Id<Link>>>> entry : disallowedNextLinks.getAsMap().entrySet()) {
126  String mode = entry.getKey();
127  List<List<Id<Link>>> linkSequences = entry.getValue();
128 
129  for (List<Id<Link>> linkSequence : linkSequences) {
130  // check for (1) link sequences being a valid sequence and (2) links existing
131  errors.addAll(isNextLinkSequenceOf(links, link, linkSequence));
132 
133  // check for allowedModes on this and next links
134  errors.addAll(isInAllowedModes(links, mode, link, linkSequence));
135  }
136  }
137  return errors;
138  }
139 
140  private static List<String> isNextLinkSequenceOf(Map<Id<Link>, ? extends Link> links,
141  Link link, List<Id<Link>> nextLinkIds) {
142 
143  List<String> messages = new ArrayList<>();
144 
145  Link lastLink = link;
146  for (Id<Link> nextLinkId : nextLinkIds) {
147 
148  // all link ids in disallowedNextLinks need be subsequent links
149  if (!isNextLinkOf(lastLink, nextLinkId)) {
150  messages.add(String.format("Link %s had a next link sequence that is not valid sequence: %s",
151  link.getId(), nextLinkIds));
152  }
153  lastLink = links.get(nextLinkId);
154 
155  // all link ids in disallowedNextLinks need to exist
156  if (lastLink == null) {
157  messages.add(String.format("Link %s had a next link sequence with (a) missing link(s): %s",
158  link.getId(), nextLinkId));
159  }
160  }
161 
162  return messages;
163  }
164 
165  private static boolean isNextLinkOf(Link link, Id<Link> nextLinkId) {
166  Node toNode = link.getToNode();
167  return toNode.getOutLinks().get(nextLinkId) != null;
168  }
169 
170  private static List<String> isInAllowedModes(Map<Id<Link>, ? extends Link> links, String mode, Link link,
171  List<Id<Link>> nextLinkIds) {
172 
173  List<String> messages = new ArrayList<>();
174 
175  if (!link.getAllowedModes().contains(mode)) {
176  messages.add(String.format("Link %s does not allow mode %s",
177  link.getId(), mode));
178  }
179 
180  for (Id<Link> nextLinkId : nextLinkIds) {
181  Link nextLink = links.get(nextLinkId);
182  if (nextLink != null && !nextLink.getAllowedModes().contains(mode)) {
183  messages.add(String.format("Next link %s does not allow mode %s",
184  nextLink.getId(), mode));
185  }
186  }
187 
188  return messages;
189  }
190 
199  public static List<List<Id<Link>>> getDisallowedLinkIdSequences(Network network, String mode) {
200  return network.getLinks().values().stream()
201  .map(link -> {
203  List<List<Id<Link>>> disallowedLinkSequences = Collections.emptyList();
204  if (dnl != null) {
205  disallowedLinkSequences = dnl.getDisallowedLinkSequences(mode);
206  }
207  return Map.entry(link.getId(), disallowedLinkSequences);
208  })
209  .filter(e -> !e.getValue().isEmpty())
210  .map(e -> {
211  List<List<Id<Link>>> linkSequences = new ArrayList<>(e.getValue().size());
212  for (List<Id<Link>> disallowedNextLinks : e.getValue()) {
213  List<Id<Link>> linkIds = new ArrayList<>(disallowedNextLinks.size() + 1);
214  linkIds.add(e.getKey()); // add this link at start of link id sequence
215  linkIds.addAll(disallowedNextLinks);
216  linkSequences.add(linkIds);
217  }
218  return linkSequences;
219  })
220  .flatMap(List::stream)
221  .toList();
222  }
223 
224 }
static void removeDisallowedNextLinks(Link link)
static DisallowedNextLinks getDisallowedNextLinks(Link link)
Map< Id< Link >, ? extends Link > getLinks()
Map< Id< Link >, ? extends Link > getOutLinks()