java/com.sap.sse.common.test/src/com/sap/sse/common/test/KadaneExtremeSubsequenceFinderTest.java
... ...
@@ -137,14 +137,42 @@ public abstract class KadaneExtremeSubsequenceFinderTest {
137 137
}
138 138
139 139
@Test
140
- public void performanceTest() {
140
+ public void performanceTestWithRandomRemove() {
141 141
final Random random = new Random();
142 142
final int NODES = 10000;
143 143
for (int i=0; i<NODES; i++) {
144 144
finder.add(new ScalableDouble(random.nextDouble()-0.5));
145 145
}
146
+ assertEquals(NODES, finder.size());
146 147
for (int i=0; i<NODES/2; i++) {
147 148
finder.remove(random.nextInt(finder.size()));
148 149
}
150
+ assertEquals(NODES-NODES/2, finder.size());
151
+ }
152
+
153
+ @Test
154
+ public void performanceTestWithRemoveFromBeginning() {
155
+ final Random random = new Random();
156
+ final int NODES = 10000;
157
+ for (int i=0; i<NODES; i++) {
158
+ finder.add(new ScalableDouble(random.nextDouble()-0.5));
159
+ }
160
+ assertEquals(NODES, finder.size());
161
+ for (int i=0; i<NODES/2; i++) {
162
+ finder.remove(0);
163
+ }
164
+ assertEquals(NODES-NODES/2, finder.size());
165
+ }
166
+
167
+ @Test
168
+ public void performanceTestWithPruneFromBeginning() {
169
+ final Random random = new Random();
170
+ final int NODES = 10000;
171
+ for (int i=0; i<NODES; i++) {
172
+ finder.add(new ScalableDouble(random.nextDouble()-0.5));
173
+ }
174
+ assertEquals(NODES, finder.size());
175
+ finder.removeFirst(NODES/2);
176
+ assertEquals(NODES-NODES/2, finder.size());
149 177
}
150 178
}
java/com.sap.sse.common/src/com/sap/sse/common/scalablevalue/KadaneExtremeSubsequenceFinder.java
... ...
@@ -41,7 +41,7 @@ public interface KadaneExtremeSubsequenceFinder<ValueType, AveragesTo extends Co
41 41
42 42
void remove(T t);
43 43
44
- // TODO bug6209: introduce remove(...) methods that allow "trimming" / "pruning" by removing elements from the first up to some specified element in one go
44
+ void removeFirst(int i);
45 45
46 46
ScalableValueWithDistance<ValueType, AveragesTo> getMinSum();
47 47
java/com.sap.sse.common/src/com/sap/sse/common/scalablevalue/KadaneExtremeSubsequenceFinderLinkedNodesImpl.java
... ...
@@ -34,6 +34,14 @@ public class KadaneExtremeSubsequenceFinderLinkedNodesImpl<ValueType, AveragesTo
34 34
private final TreeSet<Node<ValueType, AveragesTo, T>> nodesOrderedByMinSum;
35 35
36 36
private final TreeSet<Node<ValueType, AveragesTo, T>> nodesOrderedByMaxSum;
37
+
38
+ private int minChangePropagationStepsSum; // for internal stats
39
+
40
+ private int minChangePropagationsCount; // for internal stats
41
+
42
+ private int maxChangePropagationStepsSum; // for internal stats
43
+
44
+ private int maxChangePropagationsCount; // for internal stats
37 45
38 46
private static <ValueType, AveragesTo extends Comparable<AveragesTo>, T extends ComparableScalableValueWithDistance<ValueType, AveragesTo>> Integer compare(
39 47
final ScalableValueWithDistance<ValueType, AveragesTo> a,
... ...
@@ -334,20 +342,28 @@ public class KadaneExtremeSubsequenceFinderLinkedNodesImpl<ValueType, AveragesTo
334 342
* tells if changes to {@code node}'s maximum sum sub-sequences need propagation
335 343
*/
336 344
private void propagateChanges(Node<ValueType, AveragesTo, T> node, boolean changedMin, boolean changedMax) {
345
+ int minChangeCount = 0;
346
+ int maxChangeCount = 0;
337 347
Node<ValueType, AveragesTo, T> current = node.getNext();
338 348
while ((changedMin || changedMax) && current != null) {
339 349
if (changedMin) {
350
+ minChangeCount++;
340 351
nodesOrderedByMinSum.remove(current);
341 352
changedMin = current.updateMinFromPrevious();
342 353
nodesOrderedByMinSum.add(current);
343 354
}
344 355
if (changedMax) {
356
+ maxChangeCount++;
345 357
nodesOrderedByMaxSum.remove(current);
346 358
changedMax = current.updateMaxFromPrevious();
347 359
nodesOrderedByMaxSum.add(current);
348 360
}
349 361
current = current.getNext();
350 362
}
363
+ minChangePropagationStepsSum += minChangeCount;
364
+ minChangePropagationsCount++;
365
+ maxChangePropagationStepsSum += maxChangeCount;
366
+ maxChangePropagationsCount++;
351 367
}
352 368
353 369
private Node<ValueType, AveragesTo, T> getNode(int index) {
... ...
@@ -419,6 +435,30 @@ public class KadaneExtremeSubsequenceFinderLinkedNodesImpl<ValueType, AveragesTo
419 435
remove(node);
420 436
}
421 437
}
438
+
439
+ @Override
440
+ public void removeFirst(int howManyNodesToRemove) {
441
+ if (howManyNodesToRemove < 0) {
442
+ throw new IllegalArgumentException("Cannot remove a negative number of nodes: "+howManyNodesToRemove);
443
+ }
444
+ if (howManyNodesToRemove > size()) {
445
+ throw new IllegalArgumentException("Cannot remove more nodes than the sequence currently holds: "+howManyNodesToRemove+">"+size());
446
+ }
447
+ if (howManyNodesToRemove > 0) { // otherwise this is a no-op
448
+ final Node<ValueType, AveragesTo, T> lastNodeToRemove = getNode(howManyNodesToRemove-1);
449
+ first = lastNodeToRemove.getNext();
450
+ if (first != null) {
451
+ first.setPrevious(null);
452
+ if (first.updateThisFromPrevious()) {
453
+ propagateChanges(first);
454
+ }
455
+ } else {
456
+ assert howManyNodesToRemove == size();
457
+ last = null;
458
+ }
459
+ size -= howManyNodesToRemove;
460
+ }
461
+ }
422 462
423 463
@Override
424 464
public ScalableValueWithDistance<ValueType, AveragesTo> getMinSum() {