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