1 package org.opentrafficsim.core.parameters;
2
3 import java.io.Serializable;
4 import java.util.ArrayList;
5 import java.util.Collections;
6 import java.util.HashMap;
7 import java.util.Iterator;
8 import java.util.LinkedHashMap;
9 import java.util.LinkedHashSet;
10 import java.util.List;
11 import java.util.Map;
12 import java.util.Set;
13
14 import org.djunits.unit.Unit;
15 import org.djunits.value.vdouble.scalar.AbstractDoubleScalarRel;
16 import org.opentrafficsim.base.parameters.ParameterException;
17 import org.opentrafficsim.base.parameters.ParameterType;
18 import org.opentrafficsim.base.parameters.ParameterTypeDouble;
19 import org.opentrafficsim.base.parameters.ParameterTypeNumeric;
20 import org.opentrafficsim.base.parameters.Parameters;
21 import org.opentrafficsim.core.gtu.GTUType;
22 import org.opentrafficsim.core.units.distributions.ContinuousDistDoubleScalar;
23
24 import nl.tudelft.simulation.jstats.distributions.DistContinuous;
25 import nl.tudelft.simulation.jstats.distributions.DistDiscrete;
26
27
28
29
30
31
32
33
34
35
36
37
38
39 public class ParameterFactoryByType implements ParameterFactory
40 {
41
42
43 private final Map<GTUType, Set<ParameterEntry<?>>> map = new HashMap<>();
44
45
46 private Map<GTUType, Map<ParameterType<?>, Map<ParameterType<?>, Correlation<?, ?>>>> correlations = new HashMap<>();
47
48
49 @Override
50 public void setValues(final Parameters parameters, final GTUType gtuType) throws ParameterException
51 {
52
53 Map<ParameterType<?>, ParameterEntry<?>> setType = new LinkedHashMap<>();
54 List<GTUType> gtuTypes = new ArrayList<>();
55 gtuTypes.add(gtuType);
56 GTUType parent = gtuType;
57 do
58 {
59 parent = parent.getParent();
60 gtuTypes.add(parent);
61 }
62 while (parent != null);
63 Collections.reverse(gtuTypes);
64 for (GTUType type : gtuTypes)
65 {
66 if (this.map.containsKey(type))
67 {
68 for (ParameterEntry<?> entry : this.map.get(type))
69 {
70 setType.put(entry.getParameterType(), entry);
71 }
72 }
73 }
74
75
76
77
78
79
80
81
82
83
84
85 Map<ParameterType<?>, Map<ParameterType<?>, Correlation<?, ?>>> remainingCorrelations = new LinkedHashMap<>();
86 Map<ParameterType<?>, Map<ParameterType<?>, Correlation<?, ?>>> allCorrelations = new LinkedHashMap<>();
87 for (GTUType type : gtuTypes)
88 {
89 if (this.correlations.containsKey(type))
90 {
91 Map<ParameterType<?>, Map<ParameterType<?>, Correlation<?, ?>>> map1 = this.correlations.get(type);
92 for (ParameterType<?> then : map1.keySet())
93 {
94 Map<ParameterType<?>, Correlation<?, ?>> map2a = map1.get(then);
95 Map<ParameterType<?>, Correlation<?, ?>> map2b = new LinkedHashMap<>(map2a);
96
97 map2b.keySet().retainAll(setType.keySet());
98 if (!map2b.isEmpty())
99 {
100 Map<ParameterType<?>, Correlation<?, ?>> map3 = remainingCorrelations.get(then);
101 if (map3 == null)
102 {
103 map3 = new LinkedHashMap<>();
104 remainingCorrelations.put(then, map3);
105 }
106 map3.putAll(map2b);
107 }
108 if (!map2a.isEmpty())
109 {
110 Map<ParameterType<?>, Correlation<?, ?>> map3 = allCorrelations.get(then);
111 if (map3 == null)
112 {
113 map3 = new LinkedHashMap<>();
114 allCorrelations.put(then, map3);
115 }
116 map3.putAll(map2a);
117 }
118 }
119 }
120 }
121
122
123 if (!setType.keySet().containsAll(allCorrelations.keySet()))
124 {
125 Set<ParameterType<?>> params = new LinkedHashSet<>(allCorrelations.keySet());
126 params.removeAll(setType.keySet());
127 throw new ParameterException("Parameters " + params
128 + " depend on a correlation, but are not added through addParameter() to set a base value.");
129 }
130 boolean altered = true;
131 while (altered)
132 {
133 altered = false;
134
135 Iterator<ParameterType<?>> iterator = setType.keySet().iterator();
136 while (iterator.hasNext())
137 {
138 ParameterType<?> parameterType = iterator.next();
139 ParameterEntry<?> entry = setType.get(parameterType);
140
141 if (!remainingCorrelations.containsKey(parameterType))
142 {
143 altered = true;
144 iterator.remove();
145 Object value = entry.getValue();
146 setParameter(parameterType, value, parameters, allCorrelations.get(parameterType));
147
148 Iterator<ParameterType<?>> it = remainingCorrelations.keySet().iterator();
149 while (it.hasNext())
150 {
151 Map<ParameterType<?>, Correlation<?, ?>> remMap = remainingCorrelations.get(it.next());
152 remMap.remove(parameterType);
153 if (remMap.isEmpty())
154 {
155 it.remove();
156 }
157 }
158 }
159 }
160 }
161 if (!altered && !remainingCorrelations.isEmpty())
162 {
163 throw new RuntimeException("Circular correlation between parameters.");
164 }
165
166 }
167
168
169
170
171
172
173
174
175
176
177 @SuppressWarnings("unchecked")
178 private <C, T> void setParameter(final ParameterType<?> parameterType, final Object value, final Parameters parameters,
179 final Map<ParameterType<?>, Correlation<?, ?>> correls)
180 {
181 T val = (T) value;
182 try
183 {
184 if (correls != null)
185 {
186 for (ParameterType<?> param : correls.keySet())
187 {
188 Correlation<C, T> correlation = (Correlation<C, T>) correls.get(param);
189 if (param == null)
190 {
191 val = correlation.correlate(null, val);
192 }
193 else
194 {
195 val = correlation.correlate(parameters.getParameter((ParameterType<C>) param), val);
196 }
197 }
198 }
199 parameters.setParameter((ParameterType<T>) parameterType, val);
200 }
201 catch (ParameterException exception)
202 {
203 throw new RuntimeException("Value out of bounds or dependent parameter not present.", exception);
204 }
205 }
206
207
208
209
210
211
212
213 public <T> void addParameter(final GTUType gtuType, final ParameterType<T> parameterType, final T value)
214 {
215 assureTypeInMap(gtuType);
216 this.map.get(gtuType).add(new FixedEntry<>(parameterType, value));
217 }
218
219
220
221
222
223
224
225
226 public <U extends Unit<U>, T extends AbstractDoubleScalarRel<U, T>> void addParameter(final GTUType gtuType,
227 final ParameterTypeNumeric<T> parameterType, final ContinuousDistDoubleScalar.Rel<T, U> distribution)
228 {
229 assureTypeInMap(gtuType);
230 this.map.get(gtuType).add(new DistributedEntry<>(parameterType, distribution));
231 }
232
233
234
235
236
237
238 public void addParameter(final GTUType gtuType, final ParameterType<Integer> parameterType, final DistDiscrete distribution)
239 {
240 assureTypeInMap(gtuType);
241 this.map.get(gtuType).add(new DistributedEntryInteger(parameterType, distribution));
242 }
243
244
245
246
247
248
249 public void addParameter(final GTUType gtuType, final ParameterType<Double> parameterType,
250 final DistContinuous distribution)
251 {
252 assureTypeInMap(gtuType);
253 this.map.get(gtuType).add(new DistributedEntryDouble(parameterType, distribution));
254 }
255
256
257
258
259
260
261
262 public <T> void addParameter(final ParameterType<T> parameterType, final T value)
263 {
264 addParameter(null, parameterType, value);
265 }
266
267
268
269
270
271
272 public void addParameter(final ParameterTypeDouble parameterType, final double value)
273 {
274 addParameter(null, parameterType, value);
275 }
276
277
278
279
280
281
282
283
284 public <U extends Unit<U>, T extends AbstractDoubleScalarRel<U, T>> void addParameter(
285 final ParameterTypeNumeric<T> parameterType, final ContinuousDistDoubleScalar.Rel<T, U> distribution)
286 {
287 addParameter(null, parameterType, distribution);
288 }
289
290
291
292
293
294
295 public void addParameter(final ParameterTypeDouble parameterType, final DistContinuous distribution)
296 {
297 addParameter(null, parameterType, distribution);
298 }
299
300
301
302
303
304
305
306
307
308
309
310 public <C, T> void addCorrelation(final GTUType gtuType, final ParameterType<C> first, final ParameterType<T> then,
311 final Correlation<C, T> correlation)
312 {
313 assureTypeInMap(gtuType);
314 Map<ParameterType<?>, Map<ParameterType<?>, Correlation<?, ?>>> map1 = this.correlations.get(gtuType);
315 Map<ParameterType<?>, Correlation<?, ?>> map2 = map1.get(then);
316 if (map2 == null)
317 {
318 map2 = new LinkedHashMap<>();
319 map1.put(then, map2);
320 }
321 map2.put(first, correlation);
322 }
323
324
325
326
327
328
329
330
331
332 public <C, T> void addCorrelation(final ParameterType<C> first, final ParameterType<T> then,
333 final Correlation<C, T> correlation)
334 {
335 addCorrelation(null, first, then, correlation);
336 }
337
338
339
340
341
342 private void assureTypeInMap(final GTUType gtuType)
343 {
344 if (!this.map.containsKey(gtuType))
345 {
346 this.map.put(gtuType, new LinkedHashSet<>());
347 this.correlations.put(gtuType, new LinkedHashMap<>());
348 }
349 }
350
351
352 @Override
353 public String toString()
354 {
355 return "ParameterFactoryByType [map=" + this.map + "]";
356 }
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371 private interface ParameterEntry<T>
372 {
373
374
375
376
377 T getValue();
378
379
380
381
382
383 ParameterType<T> getParameterType();
384 }
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399 private final class FixedEntry<T> implements ParameterEntry<T>, Serializable
400 {
401
402 private static final long serialVersionUID = 20170400L;
403
404
405 private final ParameterType<T> parameterType;
406
407
408 private final T value;
409
410
411
412
413
414 FixedEntry(final ParameterType<T> parameterType, final T value)
415 {
416 this.parameterType = parameterType;
417 this.value = value;
418 }
419
420
421 @Override
422 public T getValue()
423 {
424 return this.value;
425 }
426
427
428 @Override
429 public ParameterType<T> getParameterType()
430 {
431 return this.parameterType;
432 }
433
434
435 @Override
436 public String toString()
437 {
438 return "FixedEntry [parameterType=" + this.parameterType + ", value=" + this.value + "]";
439 }
440
441 }
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457 private final class DistributedEntry<U extends Unit<U>, T extends AbstractDoubleScalarRel<U, T>>
458 implements ParameterEntry<T>, Serializable
459 {
460
461 private static final long serialVersionUID = 20180203L;
462
463
464 private final ParameterType<T> parameterType;
465
466
467 private final ContinuousDistDoubleScalar.Rel<T, U> distribution;
468
469
470
471
472
473 DistributedEntry(final ParameterType<T> parameterType, final ContinuousDistDoubleScalar.Rel<T, U> distribution)
474 {
475 this.parameterType = parameterType;
476 this.distribution = distribution;
477 }
478
479
480 @Override
481 public T getValue()
482 {
483 return this.distribution.draw();
484 }
485
486
487 @Override
488 public ParameterType<T> getParameterType()
489 {
490 return this.parameterType;
491 }
492
493
494 @Override
495 public String toString()
496 {
497 return "DistributedEntry [parameterType=" + this.parameterType + ", distribution=" + this.distribution + "]";
498 }
499 }
500
501
502
503
504
505
506
507
508
509
510
511
512
513 private final class DistributedEntryDouble implements ParameterEntry<Double>, Serializable
514 {
515
516 private static final long serialVersionUID = 20180203L;
517
518
519 private final ParameterType<Double> parameterType;
520
521
522 private final DistContinuous distribution;
523
524
525
526
527
528 DistributedEntryDouble(final ParameterType<Double> parameterType, final DistContinuous distribution)
529 {
530 this.parameterType = parameterType;
531 this.distribution = distribution;
532 }
533
534
535 @Override
536 public Double getValue()
537 {
538 return this.distribution.draw();
539 }
540
541
542 @Override
543 public ParameterType<Double> getParameterType()
544 {
545 return this.parameterType;
546 }
547
548
549 @Override
550 public String toString()
551 {
552 return "DistributedEntryDouble [parameterType=" + this.parameterType + ", distribution=" + this.distribution + "]";
553 }
554 }
555
556
557
558
559
560
561
562
563
564
565
566
567
568 private final class DistributedEntryInteger implements ParameterEntry<Integer>, Serializable
569 {
570
571 private static final long serialVersionUID = 20180203L;
572
573
574 private final ParameterType<Integer> parameterType;
575
576
577 private final DistDiscrete distribution;
578
579
580
581
582
583 DistributedEntryInteger(final ParameterType<Integer> parameterType, final DistDiscrete distribution)
584 {
585 this.parameterType = parameterType;
586 this.distribution = distribution;
587 }
588
589
590 @Override
591 public Integer getValue()
592 {
593 return (int) this.distribution.draw();
594 }
595
596
597 @Override
598 public ParameterType<Integer> getParameterType()
599 {
600 return this.parameterType;
601 }
602
603
604 @Override
605 public String toString()
606 {
607 return "DistributedEntryInteger [parameterType=" + this.parameterType + ", distribution=" + this.distribution + "]";
608 }
609 }
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625 @FunctionalInterface
626 public interface Correlation<C, T>
627 {
628
629
630
631
632
633
634 T correlate(C first, T then);
635 }
636
637 }