e92ecc676a1803da8b61e671d5071786749cf477
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() { |