java/com.sap.sse.common.test/META-INF/MANIFEST.MF
... ...
@@ -18,3 +18,4 @@ Require-Bundle: org.mockito.mockito-core;bundle-version="1.9.5",
18 18
net.bytebuddy.byte-buddy-agent;bundle-version="1.14.12"
19 19
Export-Package: com.sap.sse.common.test
20 20
Automatic-Module-Name: com.sap.sse.common.test
21
+Import-Package: com.sap.sse.testutils
java/com.sap.sse.common.test/src/com/sap/sse/common/test/KadaneExtremeSubsequenceFinderTest.java
... ...
@@ -3,17 +3,27 @@ package com.sap.sse.common.test;
3 3
import static org.junit.jupiter.api.Assertions.assertEquals;
4 4
import static org.junit.jupiter.api.Assertions.assertTrue;
5 5
6
+import java.io.IOException;
6 7
import java.util.Random;
7 8
import java.util.TreeSet;
9
+import java.util.logging.Logger;
8 10
11
+import org.junit.jupiter.api.AfterAll;
9 12
import org.junit.jupiter.api.Test;
10 13
11 14
import com.sap.sse.common.scalablevalue.KadaneExtremeSubsequenceFinder;
12 15
import com.sap.sse.common.scalablevalue.ScalableDouble;
16
+import com.sap.sse.testutils.Measurement;
17
+import com.sap.sse.testutils.MeasurementCase;
18
+import com.sap.sse.testutils.MeasurementXMLFile;
13 19
14 20
public abstract class KadaneExtremeSubsequenceFinderTest {
15 21
private static final double EPSILON = 0.00000001;
22
+ private static final Logger logger = Logger.getLogger(KadaneExtremeSubsequenceFinderTest.class.getName());
23
+
16 24
protected KadaneExtremeSubsequenceFinder<Double, Double, ScalableDouble> finder;
25
+ private static Random random = new Random();
26
+ private static final MeasurementXMLFile performanceReport = new MeasurementXMLFile(KadaneExtremeSubsequenceFinderTest.class);
17 27
18 28
@Test
19 29
public void testSimplePositiveSequence() {
... ...
@@ -137,42 +147,59 @@ public abstract class KadaneExtremeSubsequenceFinderTest {
137 147
}
138 148
139 149
@Test
140
- public void performanceTestWithRandomRemove() {
141
- final Random random = new Random();
150
+ public void performanceTestWithRandomRemove() throws IOException {
151
+ final MeasurementCase performanceMeasurement = performanceReport.addCase("PerformanceTestWithRandomRemove");
142 152
final int NODES = 10000;
143 153
for (int i=0; i<NODES; i++) {
144 154
finder.add(new ScalableDouble(random.nextDouble()-0.5));
145 155
}
146 156
assertEquals(NODES, finder.size());
157
+ finder.resetStats();
147 158
for (int i=0; i<NODES/2; i++) {
148 159
finder.remove(random.nextInt(finder.size()));
149 160
}
150 161
assertEquals(NODES-NODES/2, finder.size());
162
+ performanceMeasurement.addMeasurement(new Measurement("minChangePropagationCount", finder.getAverageMinChangePropagationSteps()));
163
+ performanceMeasurement.addMeasurement(new Measurement("maxChangePropagationCount", finder.getAverageMaxChangePropagationSteps()));
164
+ logger.info("Stats after random remove: " + finder.toString());
151 165
}
152 166
153 167
@Test
154
- public void performanceTestWithRemoveFromBeginning() {
155
- final Random random = new Random();
168
+ public void performanceTestWithRemoveFromBeginning() throws IOException {
169
+ final MeasurementCase performanceMeasurement = performanceReport.addCase("PerformanceTestWithRemoveFromBeginning");
156 170
final int NODES = 10000;
157 171
for (int i=0; i<NODES; i++) {
158 172
finder.add(new ScalableDouble(random.nextDouble()-0.5));
159 173
}
160 174
assertEquals(NODES, finder.size());
175
+ finder.resetStats();
161 176
for (int i=0; i<NODES/2; i++) {
162 177
finder.remove(0);
163 178
}
164 179
assertEquals(NODES-NODES/2, finder.size());
180
+ performanceMeasurement.addMeasurement(new Measurement("minChangePropagationCount", finder.getAverageMinChangePropagationSteps()));
181
+ performanceMeasurement.addMeasurement(new Measurement("maxChangePropagationCount", finder.getAverageMaxChangePropagationSteps()));
182
+ logger.info("Stats after removing from beginning: " + finder.toString());
165 183
}
166 184
167 185
@Test
168
- public void performanceTestWithPruneFromBeginning() {
169
- final Random random = new Random();
186
+ public void performanceTestWithPruneFromBeginning() throws IOException {
187
+ final MeasurementCase performanceMeasurement = performanceReport.addCase("PerformanceTestWithPruneFromBeginning");
170 188
final int NODES = 10000;
171 189
for (int i=0; i<NODES; i++) {
172 190
finder.add(new ScalableDouble(random.nextDouble()-0.5));
173 191
}
174 192
assertEquals(NODES, finder.size());
193
+ finder.resetStats();
175 194
finder.removeFirst(NODES/2);
176 195
assertEquals(NODES-NODES/2, finder.size());
196
+ performanceMeasurement.addMeasurement(new Measurement("minChangePropagationCount", finder.getAverageMinChangePropagationSteps()));
197
+ performanceMeasurement.addMeasurement(new Measurement("maxChangePropagationCount", finder.getAverageMaxChangePropagationSteps()));
198
+ logger.info("Stats after pruning from beginning: " + finder.toString());
199
+ }
200
+
201
+ @AfterAll
202
+ public static void writeMeasurements() throws IOException {
203
+ performanceReport.write();
177 204
}
178 205
}
java/com.sap.sse.common/src/com/sap/sse/common/scalablevalue/KadaneExtremeSubsequenceFinder.java
... ...
@@ -68,4 +68,20 @@ public interface KadaneExtremeSubsequenceFinder<ValueType, AveragesTo extends Co
68 68
* slightly different from how indices may be handled in some other from/to collection operations.
69 69
*/
70 70
int getEndIndexOfMinSumSequence();
71
+
72
+ /**
73
+ * @return statistics: average number of propagation steps when a change affected a minimum sum sub-sequence
74
+ */
75
+ int getAverageMinChangePropagationSteps();
76
+
77
+ /**
78
+ * @return statistics: average number of propagation steps when a change affected a maximum sum sub-sequence
79
+ */
80
+ int getAverageMaxChangePropagationSteps();
81
+
82
+ /**
83
+ * Resets the statistics on change propagation steps as returned by {@link #getAverageMinChangePropagationSteps()}
84
+ * and {@link #getAverageMaxChangePropagationSteps()}.
85
+ */
86
+ void resetStats();
71 87
}
java/com.sap.sse.common/src/com/sap/sse/common/scalablevalue/KadaneExtremeSubsequenceFinderLinkedNodesImpl.java
... ...
@@ -509,4 +509,29 @@ public class KadaneExtremeSubsequenceFinderLinkedNodesImpl<ValueType, AveragesTo
509 509
final Iterable<Node<ValueType, AveragesTo, T>> nodeIterable = ()->nodeIterator(nodeWhereBestMinSumSubSequenceEnds.getStartOfMinSumSubSequenceEndingHere(), nodeWhereBestMinSumSubSequenceEnds);
510 510
return Util.map(nodeIterable, node->node.getValue()).iterator();
511 511
}
512
+
513
+ @Override
514
+ public int getAverageMinChangePropagationSteps() {
515
+ return minChangePropagationsCount == 0 ? 0 : minChangePropagationStepsSum / minChangePropagationsCount;
516
+ }
517
+
518
+ @Override
519
+ public int getAverageMaxChangePropagationSteps() {
520
+ return maxChangePropagationsCount == 0 ? 0 : maxChangePropagationStepsSum / maxChangePropagationsCount;
521
+ }
522
+
523
+ @Override
524
+ public void resetStats() {
525
+ minChangePropagationStepsSum = 0;
526
+ minChangePropagationsCount = 0;
527
+ maxChangePropagationStepsSum = 0;
528
+ maxChangePropagationsCount = 0;
529
+ }
530
+
531
+ @Override
532
+ public String toString() {
533
+ return "KadaneExtremeSubsequenceFinderLinkedNodesImpl [size=" + size
534
+ + ", minChangePropagationStepsAvg=" + minChangePropagationStepsSum / minChangePropagationsCount
535
+ + ", maxChangePropagationStepsAvg=" + maxChangePropagationStepsSum / maxChangePropagationsCount + "]";
536
+ }
512 537
}