1 package org.opentrafficsim.draw.egtf;
2
3 import java.util.LinkedHashMap;
4 import java.util.LinkedHashSet;
5 import java.util.Map;
6 import java.util.NavigableMap;
7 import java.util.Objects;
8 import java.util.Set;
9 import java.util.SortedMap;
10 import java.util.TreeMap;
11 import java.util.stream.IntStream;
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70 public class Egtf
71 {
72
73
74 private static final double DEFAULT_SIGMA = 300.0;
75
76
77 private static final double DEFAULT_TAU = 30.0;
78
79
80 private Kernel kernel;
81
82
83 private final double cCong;
84
85
86 private final double cFree;
87
88
89 private final double deltaV;
90
91
92 private final double vc;
93
94
95 private final Map<String, DataSource> dataSources = new LinkedHashMap<>();
96
97
98 private DataSource defaultDataSource = null;
99
100
101 private Map<Quantity<?, ?>, DataStream<?>> defaultDataStreams = null;
102
103
104 private boolean addingByQuantity;
105
106
107 private NavigableMap<Double, NavigableMap<Double, Map<DataStream<?>, Double>>> data = new TreeMap<>();
108
109
110 private boolean interrupted = false;
111
112
113 private Set<EgtfListener> listeners = new LinkedHashSet<>();
114
115
116
117
118 public Egtf()
119 {
120 this(-18.0, 80.0, 10.0, 80.0);
121 }
122
123
124
125
126
127
128
129
130 public Egtf(final double cCong, final double cFree, final double deltaV, final double vc)
131 {
132 this.cCong = cCong / 3.6;
133 this.cFree = cFree / 3.6;
134 this.deltaV = deltaV / 3.6;
135 this.vc = vc / 3.6;
136 setKernel();
137 }
138
139
140
141
142
143
144
145
146
147
148
149
150 @SuppressWarnings("parameternumber")
151 public Egtf(final double cCong, final double cFree, final double deltaV, final double vc, final double sigma,
152 final double tau, final double xMax, final double tMax)
153 {
154 this(cCong, cFree, deltaV, vc);
155 setKernelSI(sigma, tau, xMax, tMax);
156 }
157
158
159
160
161
162
163
164
165
166
167
168 public DataSource getDataSource(final String name)
169 {
170 if (this.defaultDataSource != null)
171 {
172 throw new IllegalStateException(
173 "Obtaining a (new) data source after data has been added without a data source is not allowed.");
174 }
175 return this.dataSources.computeIfAbsent(name, (
176 key
177 ) -> new DataSource(key));
178 }
179
180
181
182
183
184
185 public synchronized void clearDataBefore(final double time)
186 {
187 for (SortedMap<Double, Map<DataStream<?>, Double>> map : this.data.values())
188 {
189 map.subMap(Double.NEGATIVE_INFINITY, time).clear();
190 }
191 }
192
193
194
195
196
197
198
199
200
201 public synchronized void addPointDataSI(final Quantity<?, ?> quantity, final double location, final double time,
202 final double value)
203 {
204 this.addingByQuantity = true;
205 addPointDataSI(getDefaultDataStream(quantity), location, time, value);
206 this.addingByQuantity = false;
207 }
208
209
210
211
212
213
214
215
216
217 public synchronized void addPointDataSI(final DataStream<?> dataStream, final double location, final double time,
218 final double value)
219 {
220 checkNoQuantityData();
221 Objects.requireNonNull(dataStream, "Datastream may not be null.");
222 if (!Double.isNaN(value))
223 {
224 getSpacioTemporalData(getSpatialData(location), time).put(dataStream, value);
225 }
226 }
227
228
229
230
231
232
233
234
235
236 public synchronized void addVectorDataSI(final Quantity<?, ?> quantity, final double[] location, final double[] time,
237 final double[] values)
238 {
239 this.addingByQuantity = true;
240 addVectorDataSI(getDefaultDataStream(quantity), location, time, values);
241 this.addingByQuantity = false;
242 }
243
244
245
246
247
248
249
250
251
252 public synchronized void addVectorDataSI(final DataStream<?> dataStream, final double[] location, final double[] time,
253 final double[] values)
254 {
255 checkNoQuantityData();
256 Objects.requireNonNull(dataStream, "Datastream may not be null.");
257 Objects.requireNonNull(location, "Location may not be null.");
258 Objects.requireNonNull(time, "Time may not be null.");
259 Objects.requireNonNull(values, "Values may not be null.");
260 if (location.length != time.length || time.length != values.length)
261 {
262 throw new IllegalArgumentException(String.format("Unequal lengths: location %d, time %d, data %d.", location.length,
263 time.length, values.length));
264 }
265 for (int i = 0; i < values.length; i++)
266 {
267 if (!Double.isNaN(values[i]))
268 {
269 getSpacioTemporalData(getSpatialData(location[i]), time[i]).put(dataStream, values[i]);
270 }
271 }
272 }
273
274
275
276
277
278
279
280
281
282 public synchronized void addGridDataSI(final Quantity<?, ?> quantity, final double[] location, final double[] time,
283 final double[][] values)
284 {
285 this.addingByQuantity = true;
286 addGridDataSI(getDefaultDataStream(quantity), location, time, values);
287 this.addingByQuantity = false;
288 }
289
290
291
292
293
294
295
296
297
298 public synchronized void addGridDataSI(final DataStream<?> dataStream, final double[] location, final double[] time,
299 final double[][] values)
300 {
301 checkNoQuantityData();
302 Objects.requireNonNull(dataStream, "Datastream may not be null.");
303 Objects.requireNonNull(location, "Location may not be null.");
304 Objects.requireNonNull(time, "Time may not be null.");
305 Objects.requireNonNull(values, "Values may not be null.");
306 if (values.length != location.length)
307 {
308 throw new IllegalArgumentException(
309 String.format("%d locations while length of data is %d", location.length, values.length));
310 }
311 for (int i = 0; i < location.length; i++)
312 {
313 if (values[i].length != time.length)
314 {
315 throw new IllegalArgumentException(
316 String.format("%d times while length of data is %d", time.length, values[i].length));
317 }
318 Map<Double, Map<DataStream<?>, Double>> spatialData = getSpatialData(location[i]);
319 for (int j = 0; j < time.length; j++)
320 {
321 if (!Double.isNaN(values[i][j]))
322 {
323 getSpacioTemporalData(spatialData, time[j]).put(dataStream, values[i][j]);
324 }
325 }
326 }
327 }
328
329
330
331
332
333 private void checkNoQuantityData()
334 {
335 if (!this.addingByQuantity && this.defaultDataSource != null)
336 {
337 throw new IllegalStateException(
338 "Adding data with a data stream is not allowed after data has been added with a quantity.");
339 }
340 }
341
342
343
344
345
346
347
348 private DataStream<?> getDefaultDataStream(final Quantity<?, ?> quantity)
349 {
350 Objects.requireNonNull(quantity, "Quantity may not be null.");
351 if (!this.dataSources.isEmpty())
352 {
353 throw new IllegalStateException(
354 "Adding data with a quantity is not allowed after data has been added with a data stream.");
355 }
356 if (this.defaultDataSource == null)
357 {
358 this.defaultDataSource = new DataSource("default");
359 this.defaultDataStreams = new LinkedHashMap<>();
360 }
361 return this.defaultDataStreams.computeIfAbsent(quantity, (
362 key
363 ) -> this.defaultDataSource.addStreamSI(quantity, 1.0, 1.0));
364 }
365
366
367
368
369
370
371 private SortedMap<Double, Map<DataStream<?>, Double>> getSpatialData(final double location)
372 {
373 return this.data.computeIfAbsent(location, (
374 key
375 ) -> new TreeMap<>());
376 }
377
378
379
380
381
382
383
384
385 private Map<DataStream<?>, Double> getSpacioTemporalData(final Map<Double, Map<DataStream<?>, Double>> spatialData,
386 final double time)
387 {
388 return spatialData.computeIfAbsent(time, (
389 key
390 ) -> new LinkedHashMap<>());
391 }
392
393
394
395
396
397
398
399
400 public void setKernel()
401 {
402 setKernelSI(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, new ExpKernelShape(DEFAULT_SIGMA, DEFAULT_TAU));
403 }
404
405
406
407
408
409
410 public void setKernelSI(final double sigma, final double tau)
411 {
412 setKernelSI(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, sigma, tau);
413 }
414
415
416
417
418
419
420
421
422 public void setKernelSI(final double sigma, final double tau, final double xMax, final double tMax)
423 {
424 setKernelSI(xMax, tMax, new ExpKernelShape(sigma, tau));
425 }
426
427
428
429
430
431
432 public void setGaussKernelSI(final double sigma, final double tau)
433 {
434 setGaussKernelSI(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, sigma, tau);
435 }
436
437
438
439
440
441
442
443
444 public void setGaussKernelSI(final double sigma, final double tau, final double xMax, final double tMax)
445 {
446 setKernelSI(xMax, tMax, new GaussKernelShape(sigma, tau));
447 }
448
449
450
451
452
453
454
455 public synchronized void setKernelSI(final double xMax, final double tMax, final KernelShape shape)
456 {
457 this.kernel = new Kernel(xMax, tMax, shape);
458 }
459
460
461
462
463
464 final double getWaveSpeedCongestion()
465 {
466 return this.cCong;
467 }
468
469
470
471
472
473 final double getWaveSpeedFreeFlow()
474 {
475 return this.cFree;
476 }
477
478
479
480
481
482
483
484
485
486
487
488
489
490 public EgtfParallelListener filterParallelSI(final double[] location, final double[] time,
491 final Quantity<?, ?>... quantities)
492 {
493 Objects.requireNonNull(location, "Location may not be null.");
494 Objects.requireNonNull(time, "Time may not be null.");
495 EgtfParallelListener listener = new EgtfParallelListener();
496 addListener(listener);
497 new Thread(new Runnable()
498 {
499
500 @Override
501 public void run()
502 {
503 listener.setFilter(filterSI(location, time, quantities));
504 removeListener(listener);
505 }
506 }, "Egtf calculation thread").start();
507 return listener;
508 }
509
510
511
512
513
514
515
516
517
518
519
520
521
522 public EgtfParallelListener filterParallelFastSI(final double xMin, final double xStep, final double xMax,
523 final double tMin, final double tStep, final double tMax, final Quantity<?, ?>... quantities)
524 {
525 EgtfParallelListener listener = new EgtfParallelListener();
526 addListener(listener);
527 new Thread(new Runnable()
528 {
529
530 @Override
531 public void run()
532 {
533 listener.setFilter(filterFastSI(xMin, xStep, xMax, tMin, tStep, tMax, quantities));
534 removeListener(listener);
535 }
536 }, "Egtf calculation thread").start();
537 return listener;
538 }
539
540
541
542
543
544
545
546
547 @SuppressWarnings({"synthetic-access", "methodlength"})
548 public Filter filterSI(final double[] location, final double[] time, final Quantity<?, ?>... quantities)
549 {
550 Objects.requireNonNull(location, "Location may not be null.");
551 Objects.requireNonNull(time, "Time may not be null.");
552
553
554 Map<Quantity<?, ?>, double[][]> map = new LinkedHashMap<>();
555 for (Quantity<?, ?> quantity : quantities)
556 {
557 map.put(quantity, new double[location.length][time.length]);
558 }
559
560
561 for (int i = 0; i < location.length; i++)
562 {
563 double xGrid = location[i];
564
565
566 Map<Double, NavigableMap<Double, Map<DataStream<?>, Double>>> spatialData =
567 this.data.subMap(this.kernel.fromLocation(xGrid), true, this.kernel.toLocation(xGrid), true);
568
569
570 for (int j = 0; j < time.length; j++)
571 {
572 double tGrid = time[j];
573
574
575 if (notifyListeners((i + (double) j / time.length) / location.length))
576 {
577 return null;
578 }
579
580
581
582 Map<DataStream<?>, DualWeightedMean> zCongFree = new LinkedHashMap<>();
583
584
585 for (Map.Entry<Double, NavigableMap<Double, Map<DataStream<?>, Double>>> xEntry : spatialData.entrySet())
586 {
587 double dx = xEntry.getKey() - xGrid;
588 Map<Double, Map<DataStream<?>, Double>> temporalData =
589 xEntry.getValue().subMap(this.kernel.fromTime(tGrid), true, this.kernel.toTime(tGrid), true);
590
591 for (Map.Entry<Double, Map<DataStream<?>, Double>> tEntry : temporalData.entrySet())
592 {
593 double dt = tEntry.getKey() - tGrid;
594 Map<DataStream<?>, Double> pData = tEntry.getValue();
595
596 double phiCong = this.kernel.weight(this.cCong, dx, dt);
597 double phiFree = this.kernel.weight(this.cFree, dx, dt);
598
599
600 for (Map.Entry<DataStream<?>, Double> vEntry : pData.entrySet())
601 {
602 DataStream<?> stream = vEntry.getKey();
603 if (map.containsKey(stream.getQuantity()) || stream.getQuantity().isSpeed())
604 {
605 double v = vEntry.getValue();
606 DualWeightedMean zCongFreeOfStream = zCongFree.computeIfAbsent(stream, (
607 key
608 ) -> new DualWeightedMean());
609 zCongFreeOfStream.addCong(v, phiCong);
610 zCongFreeOfStream.addFree(v, phiFree);
611 }
612 }
613 }
614 }
615
616
617 Map<DataSource, Double> w = new LinkedHashMap<>();
618 for (Map.Entry<DataStream<?>, DualWeightedMean> streamEntry : zCongFree.entrySet())
619 {
620 DataStream<?> dataStream = streamEntry.getKey();
621 if (dataStream.getQuantity().isSpeed())
622 {
623 DualWeightedMean zCongFreeOfStream = streamEntry.getValue();
624 double u = Math.min(zCongFreeOfStream.getCong(), zCongFreeOfStream.getFree());
625 w.put(dataStream.getDataSource(),
626 .5 * (1.0 + Math.tanh((Egtf.this.vc - u) / Egtf.this.deltaV)));
627 continue;
628 }
629 }
630
631
632 Double wMean = null;
633 for (Map.Entry<Quantity<?, ?>, double[][]> qEntry : map.entrySet())
634 {
635 Quantity<?, ?> quantity = qEntry.getKey();
636 WeightedMean z = new WeightedMean();
637 for (Map.Entry<DataStream<?>, DualWeightedMean> zEntry : zCongFree.entrySet())
638 {
639 DataStream<?> dataStream = zEntry.getKey();
640 if (dataStream.getQuantity().equals(quantity))
641 {
642
643 double wCong;
644 if (!w.containsKey(dataStream.getDataSource()))
645 {
646
647 if (wMean == null)
648 {
649
650 for (Quantity<?, ?> prevQuant : quantities)
651 {
652 if (prevQuant.equals(quantity))
653 {
654
655 wMean = 0.0;
656 for (double ww : w.values())
657 {
658 wMean += ww / w.size();
659 }
660 break;
661 }
662 else if (prevQuant.isSpeed())
663 {
664 wMean = .5 * (1.0
665 + Math.tanh((Egtf.this.vc - map.get(prevQuant)[i][j]) / Egtf.this.deltaV));
666 break;
667 }
668 }
669 }
670 wCong = wMean;
671 }
672 else
673 {
674 wCong = w.get(dataStream.getDataSource());
675 }
676
677 double wfree = 1.0 - wCong;
678 DualWeightedMean zCongFreej = zEntry.getValue();
679 double zStream = wCong * zCongFreej.getCong() + wfree * zCongFreej.getFree();
680 double weight;
681 if (w.size() > 1)
682 {
683
684 double beta = wCong * zCongFreej.getDenominatorCong() + wfree * zCongFreej.getDenominatorFree();
685
686 double alpha = wCong / dataStream.getThetaCong() + wfree / dataStream.getThetaFree();
687 weight = alpha * beta;
688 }
689 else
690 {
691 weight = 1.0;
692 }
693 z.add(zStream, weight);
694 }
695 }
696 qEntry.getValue()[i][j] = z.get();
697 }
698 }
699 }
700 notifyListeners(1.0);
701
702 return new FilterDouble(location, time, map);
703 }
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722 @SuppressWarnings("methodlength")
723 public Filter filterFastSI(final double xMin, final double xStep, final double xMax, final double tMin, final double tStep,
724 final double tMax, final Quantity<?, ?>... quantities)
725 {
726 if (xMin > xMax || xStep <= 0.0 || tMin > tMax || tStep <= 0.0)
727 {
728 throw new IllegalArgumentException(
729 "Ill-defined grid. Make sure that xMax >= xMin, dx > 0, tMax >= tMin and dt > 0");
730 }
731 if (notifyListeners(0.0))
732 {
733 return null;
734 }
735
736
737 int n = 1 + (int) ((xMax - xMin) / xStep);
738 double[] location = new double[n];
739 IntStream.range(0, n).forEach(i -> location[i] = xMin + i * xStep);
740 n = 1 + (int) ((tMax - tMin) / tStep);
741 double[] time = new double[n];
742 IntStream.range(0, n).forEach(j -> time[j] = tMin + j * tStep);
743 Map<Quantity<?, ?>, double[][]> map = new LinkedHashMap<>();
744 Map<Quantity<?, ?>, double[][]> weights = new LinkedHashMap<>();
745 for (Quantity<?, ?> quantity : quantities)
746 {
747 map.put(quantity, new double[location.length][time.length]);
748 weights.put(quantity, new double[location.length][time.length]);
749 }
750
751
752 double xFrom = this.kernel.fromLocation(0.0);
753 xFrom = Double.isInfinite(xFrom) ? 2.0 * (xMin - xMax) : xFrom;
754 double xTo = this.kernel.toLocation(0.0);
755 xTo = Double.isInfinite(xTo) ? 2.0 * (xMax - xMin) : xTo;
756 double[] dx = equidistant(xFrom, xStep, xTo);
757 double tFrom = this.kernel.fromTime(0.0);
758 tFrom = Double.isInfinite(tFrom) ? 2.0 * (tMin - tMax) : tFrom;
759 double tTo = this.kernel.toTime(0.0);
760 tTo = Double.isInfinite(tTo) ? 2.0 * (tMax - tMin) : tTo;
761 double[] dt = equidistant(tFrom, tStep, tTo);
762 double[][] phiCong = new double[dx.length][dt.length];
763 double[][] phiFree = new double[dx.length][dt.length];
764 for (int i = 0; i < dx.length; i++)
765 {
766 for (int j = 0; j < dt.length; j++)
767 {
768 phiCong[i][j] = this.kernel.weight(this.cCong, dx[i], dt[j]);
769 phiFree[i][j] = this.kernel.weight(this.cFree, dx[i], dt[j]);
770 }
771 }
772
773
774 Map<DataStream<?>, double[][]> dataSum = new LinkedHashMap<>();
775 Map<DataStream<?>, double[][]> dataCount = new LinkedHashMap<>();
776
777 for (int i = 0; i < location.length; i++)
778 {
779
780 Map<Double, NavigableMap<Double, Map<DataStream<?>, Double>>> spatialData =
781 this.data.subMap(location[i] - 0.5 * xStep, true, location[i] + 0.5 * xStep, true);
782
783 for (int j = 0; j < time.length; j++)
784 {
785
786 for (NavigableMap<Double, Map<DataStream<?>, Double>> locationData : spatialData.values())
787 {
788 NavigableMap<Double, Map<DataStream<?>, Double>> temporalData =
789 locationData.subMap(time[j] - 0.5 * tStep, true, time[j] + 0.5 * tStep, true);
790 for (Map<DataStream<?>, Double> timeData : temporalData.values())
791 {
792 for (Map.Entry<DataStream<?>, Double> timeEntry : timeData.entrySet())
793 {
794 if (map.containsKey(timeEntry.getKey().getQuantity()) || timeEntry.getKey().getQuantity().isSpeed())
795 {
796 dataSum.computeIfAbsent(timeEntry.getKey(), (
797 key
798 ) -> new double[location.length][time.length])[i][j] += timeEntry.getValue();
799 dataCount.computeIfAbsent(timeEntry.getKey(), (
800 key
801 ) -> new double[location.length][time.length])[i][j]++;
802 }
803 }
804 }
805 }
806 }
807 }
808
809
810 double steps = quantities.length + 1;
811 double step = 0;
812
813 Map<DataSource, double[][]> w = new LinkedHashMap<>();
814 Map<DataSource, double[][]> zCongSpeed = new LinkedHashMap<>();
815 Map<DataSource, double[][]> zFreeSpeed = new LinkedHashMap<>();
816 Map<DataSource, double[][]> nCongSpeed = new LinkedHashMap<>();
817 Map<DataSource, double[][]> nFreeSpeed = new LinkedHashMap<>();
818 for (Map.Entry<DataStream<?>, double[][]> zEntry : dataSum.entrySet())
819 {
820 DataStream<?> dataStream = zEntry.getKey();
821 if (dataStream.getQuantity().isSpeed())
822 {
823
824 double[][] vCong = Convolution.convolution(phiCong, zEntry.getValue());
825 if (notifyListeners((step + 0.25) / steps))
826 {
827 return null;
828 }
829 double[][] vFree = Convolution.convolution(phiFree, zEntry.getValue());
830 if (notifyListeners((step + 0.5) / steps))
831 {
832 return null;
833 }
834 double[][] count = dataCount.get(dataStream);
835 double[][] nCong = Convolution.convolution(phiCong, count);
836 if (notifyListeners((step + 0.75) / steps))
837 {
838 return null;
839 }
840 double[][] nFree = Convolution.convolution(phiFree, count);
841 double[][] wSource = new double[vCong.length][vCong[0].length];
842 for (int i = 0; i < vCong.length; i++)
843 {
844 for (int j = 0; j < vCong[0].length; j++)
845 {
846 double u = Math.min(vCong[i][j] / nCong[i][j], vFree[i][j] / nFree[i][j]);
847 wSource[i][j] = .5 * (1.0 + Math.tanh((Egtf.this.vc - u) / Egtf.this.deltaV));
848 }
849 }
850 w.put(dataStream.getDataSource(), wSource);
851 zCongSpeed.put(dataStream.getDataSource(), vCong);
852 zFreeSpeed.put(dataStream.getDataSource(), vFree);
853 nCongSpeed.put(dataStream.getDataSource(), nCong);
854 nFreeSpeed.put(dataStream.getDataSource(), nFree);
855 }
856 }
857 step++;
858 if (notifyListeners(step / steps))
859 {
860 return null;
861 }
862
863
864 double[][] wMean = null;
865 for (Quantity<?, ?> quantity : quantities)
866 {
867
868 double[][] qData = map.get(quantity);
869 double[][] qWeights = weights.get(quantity);
870
871 Set<Map.Entry<DataStream<?>, double[][]>> zEntries = new LinkedHashSet<>();
872 for (Map.Entry<DataStream<?>, double[][]> zEntry : dataSum.entrySet())
873 {
874 if (zEntry.getKey().getQuantity().equals(quantity))
875 {
876 zEntries.add(zEntry);
877 }
878 }
879 double streamCounter = 0;
880 for (Map.Entry<DataStream<?>, double[][]> zEntry : zEntries)
881 {
882 DataStream<?> dataStream = zEntry.getKey();
883
884
885 double[][] wj;
886 if (!w.containsKey(dataStream.getDataSource()))
887 {
888
889 if (wMean == null)
890 {
891
892 for (Quantity<?, ?> prevQuant : quantities)
893 {
894 if (prevQuant.equals(quantity))
895 {
896
897 wMean = new double[location.length][time.length];
898 for (double[][] ww : w.values())
899 {
900 for (int i = 0; i < location.length; i++)
901 {
902 for (int j = 0; j < time.length; j++)
903 {
904 wMean[i][j] += ww[i][j] / w.size();
905 }
906 }
907 }
908 break;
909 }
910 else if (prevQuant.isSpeed())
911 {
912 wMean = new double[location.length][time.length];
913 double[][] v = map.get(prevQuant);
914 for (int i = 0; i < location.length; i++)
915 {
916 for (int j = 0; j < time.length; j++)
917 {
918 wMean[i][j] = .5 * (1.0 + Math.tanh((Egtf.this.vc - v[i][j]) / Egtf.this.deltaV));
919 }
920 }
921 break;
922 }
923 }
924 }
925 wj = wMean;
926 }
927 else
928 {
929 wj = w.get(dataStream.getDataSource());
930 }
931
932
933 double[][] zCong;
934 double[][] zFree;
935 double[][] nCong;
936 double[][] nFree;
937 if (dataStream.getQuantity().isSpeed())
938 {
939 zCong = zCongSpeed.get(dataStream.getDataSource());
940 zFree = zFreeSpeed.get(dataStream.getDataSource());
941 nCong = nCongSpeed.get(dataStream.getDataSource());
942 nFree = nFreeSpeed.get(dataStream.getDataSource());
943 }
944 else
945 {
946 zCong = Convolution.convolution(phiCong, zEntry.getValue());
947 if (notifyListeners((step + (streamCounter + 0.25) / zEntries.size()) / steps))
948 {
949 return null;
950 }
951 zFree = Convolution.convolution(phiFree, zEntry.getValue());
952 if (notifyListeners((step + (streamCounter + 0.5) / zEntries.size()) / steps))
953 {
954 return null;
955 }
956 double[][] count = dataCount.get(dataStream);
957 nCong = Convolution.convolution(phiCong, count);
958 if (notifyListeners((step + (streamCounter + 0.75) / zEntries.size()) / steps))
959 {
960 return null;
961 }
962 nFree = Convolution.convolution(phiFree, count);
963 }
964
965
966 for (int i = 0; i < location.length; i++)
967 {
968 for (int j = 0; j < time.length; j++)
969 {
970 double wCong = wj[i][j];
971 double wFree = 1.0 - wCong;
972 double value = wCong * zCong[i][j] / nCong[i][j] + wFree * zFree[i][j] / nFree[i][j];
973
974
975 double beta = wCong * nCong[i][j] + wFree * nFree[i][j];
976 double alpha = wCong / dataStream.getThetaCong() + wFree / dataStream.getThetaFree();
977 double weight = beta * alpha;
978 qData[i][j] += (value * weight);
979 qWeights[i][j] += weight;
980 }
981 }
982 streamCounter++;
983 if (notifyListeners((step + streamCounter / zEntries.size()) / steps))
984 {
985 return null;
986 }
987 }
988 for (int i = 0; i < location.length; i++)
989 {
990 for (int j = 0; j < time.length; j++)
991 {
992 qData[i][j] /= qWeights[i][j];
993 }
994 }
995 step++;
996 }
997
998 return new FilterDouble(location, time, map);
999 }
1000
1001
1002
1003
1004
1005
1006
1007
1008 private double[] equidistant(final double from, final double step, final double to)
1009 {
1010 int n1 = (int) (-from / step);
1011 int n2 = (int) (to / step);
1012 int n = n1 + n2 + 1;
1013 double[] array = new double[n];
1014 for (int i = 0; i < n; i++)
1015 {
1016 array[i] = i < n1 ? step * (-n1 + i) : step * (i - n1);
1017 }
1018 return array;
1019 }
1020
1021
1022
1023
1024
1025
1026
1027
1028 public final void interrupt()
1029 {
1030 this.interrupted = true;
1031 }
1032
1033
1034
1035
1036
1037 public final void addListener(final EgtfListener listener)
1038 {
1039 this.listeners.add(listener);
1040 }
1041
1042
1043
1044
1045
1046 public final void removeListener(final EgtfListener listener)
1047 {
1048 this.listeners.remove(listener);
1049 }
1050
1051
1052
1053
1054
1055
1056 private boolean notifyListeners(final double progress)
1057 {
1058 if (!this.listeners.isEmpty())
1059 {
1060 EgtfEvent event = new EgtfEvent(this, progress);
1061 for (EgtfListener listener : this.listeners)
1062 {
1063 listener.notifyProgress(event);
1064 }
1065 }
1066 return this.interrupted;
1067 }
1068
1069
1070
1071
1072
1073
1074
1075
1076 private class DualWeightedMean
1077 {
1078
1079 private double numeratorCong;
1080
1081
1082 private double numeratorFree;
1083
1084
1085 private double denominatorCong;
1086
1087
1088 private double denominatorFree;
1089
1090
1091
1092
1093
1094
1095 public void addCong(final double value, final double weight)
1096 {
1097 this.numeratorCong += value * weight;
1098 this.denominatorCong += weight;
1099 }
1100
1101
1102
1103
1104
1105
1106 public void addFree(final double value, final double weight)
1107 {
1108 this.numeratorFree += value * weight;
1109 this.denominatorFree += weight;
1110 }
1111
1112
1113
1114
1115
1116 public double getCong()
1117 {
1118 return this.numeratorCong / this.denominatorCong;
1119 }
1120
1121
1122
1123
1124
1125 public double getFree()
1126 {
1127 return this.numeratorFree / this.denominatorFree;
1128 }
1129
1130
1131
1132
1133
1134 public double getDenominatorCong()
1135 {
1136 return this.denominatorCong;
1137 }
1138
1139
1140
1141
1142
1143 public double getDenominatorFree()
1144 {
1145 return this.denominatorFree;
1146 }
1147
1148
1149 @Override
1150 public String toString()
1151 {
1152 return "DualWeightedMean [numeratorCong=" + this.numeratorCong + ", numeratorFree=" + this.numeratorFree
1153 + ", denominatorCong=" + this.denominatorCong + ", denominatorFree=" + this.denominatorFree + "]";
1154 }
1155
1156 }
1157
1158
1159
1160
1161 private class WeightedMean
1162 {
1163
1164 private double numerator;
1165
1166
1167 private double denominator;
1168
1169
1170
1171
1172
1173
1174 public void add(final double value, final double weight)
1175 {
1176 this.numerator += value * weight;
1177 this.denominator += weight;
1178 }
1179
1180
1181
1182
1183
1184 public double get()
1185 {
1186 return this.numerator / this.denominator;
1187 }
1188
1189
1190 @Override
1191 public String toString()
1192 {
1193 return "WeightedMean [numerator=" + this.numerator + ", denominator=" + this.denominator + "]";
1194 }
1195
1196 }
1197
1198
1199 @Override
1200 public String toString()
1201 {
1202 return "EGTF [kernel=" + this.kernel + ", cCong=" + this.cCong + ", cFree=" + this.cFree + ", deltaV=" + this.deltaV
1203 + ", vc=" + this.vc + ", dataSources=" + this.dataSources + ", data=" + this.data + ", interrupted="
1204 + this.interrupted + ", listeners=" + this.listeners + "]";
1205 }
1206
1207 }