java/com.sap.sse.common.test/src/com/sap/sse/common/test/KadaneExtremeSubarraysFinderTest.java
... ...
@@ -22,8 +22,48 @@ public class KadaneExtremeSubarraysFinderTest {
22 22
finder.add(new ScalableDouble(1));
23 23
finder.add(new ScalableDouble(2));
24 24
finder.add(new ScalableDouble(3));
25
- assertEquals(6.0, finder.getMaxSum(), EPSILON);
25
+ assertEquals(6.0, finder.getMaxSum().divide(1.0), EPSILON);
26 26
assertEquals(0, finder.getStartIndexInclusiveOfMaxSumSequence());
27 27
assertEquals(3, finder.getEndIndexExclusiveOfMaxSumSequence());
28 28
}
29
+
30
+ @Test
31
+ public void testSimplePositiveSequenceWithInsertInTheMiddle() {
32
+ finder.add(new ScalableDouble(1));
33
+ finder.add(new ScalableDouble(3));
34
+ finder.add(1, new ScalableDouble(2));
35
+ assertEquals(6.0, finder.getMaxSum().divide(1.0), EPSILON);
36
+ assertEquals(0, finder.getStartIndexInclusiveOfMaxSumSequence());
37
+ assertEquals(3, finder.getEndIndexExclusiveOfMaxSumSequence());
38
+ }
39
+
40
+ @Test
41
+ public void testSimpleSequenceWithPositiveAndNegative() {
42
+ finder.add(new ScalableDouble(1));
43
+ finder.add(new ScalableDouble(2));
44
+ finder.add(new ScalableDouble(3));
45
+ finder.add(new ScalableDouble(-4));
46
+ finder.add(new ScalableDouble(5));
47
+ finder.add(new ScalableDouble(6));
48
+ finder.add(new ScalableDouble(-5));
49
+ assertEquals(13.0, finder.getMaxSum().divide(1.0), EPSILON);
50
+ assertEquals(0, finder.getStartIndexInclusiveOfMaxSumSequence());
51
+ assertEquals(6, finder.getEndIndexExclusiveOfMaxSumSequence());
52
+ }
53
+
54
+ @Test
55
+ public void testSimplePositiveSequenceWithLaterNegativeInsertInTheMiddle() {
56
+ finder.add(new ScalableDouble(1));
57
+ finder.add(new ScalableDouble(2));
58
+ finder.add(new ScalableDouble(3));
59
+ finder.add(new ScalableDouble(4));
60
+ finder.add(new ScalableDouble(5));
61
+ assertEquals(15.0, finder.getMaxSum().divide(1.0), EPSILON);
62
+ assertEquals(0, finder.getStartIndexInclusiveOfMaxSumSequence());
63
+ assertEquals(6, finder.getEndIndexExclusiveOfMaxSumSequence());
64
+ finder.add(3, new ScalableDouble(-7));
65
+ assertEquals(9.0, finder.getMaxSum().divide(1.0), EPSILON);
66
+ assertEquals(4, finder.getStartIndexInclusiveOfMaxSumSequence());
67
+ assertEquals(6, finder.getEndIndexExclusiveOfMaxSumSequence());
68
+ }
29 69
}
java/com.sap.sse.common/src/com/sap/sse/common/scalablevalue/KadaneExtremeSubarraysFinder.java
... ...
@@ -4,6 +4,7 @@ import java.io.Serializable;
4 4
import java.util.Iterator;
5 5
import java.util.LinkedList;
6 6
import java.util.List;
7
+import java.util.ListIterator;
7 8
8 9
/**
9 10
* In a sequence of {@link ComparableScalableValueWithDistance} objects, tells the contiguous sub-sequence with the
... ...
@@ -90,23 +91,52 @@ implements Serializable, Iterable<T> {
90 91
91 92
public synchronized void add(int index, T t) {
92 93
sequence.add(index, t);
93
- if (index == 0) {
94
- maxSumEndingAt.add(index, t);
95
- // TODO update subsequent elements based on the change
94
+ final ScalableValueWithDistance<ValueType, AveragesTo> newMaxSumEndingAtIndex;
95
+ final ScalableValueWithDistance<ValueType, AveragesTo> sum = index == 0 ? null : t.add(maxSumEndingAt.get(index-1));
96
+ if (index == 0 || compare(t, sum) >= 0) {
97
+ newMaxSumEndingAtIndex = t; // one-element sum consisting of element at "index" is the maximum
96 98
} else {
97
- if (t.divide(1).compareTo(maxSumEndingAt.get(index-1).divide(1)) >= 0) {
98
- maxSumEndingAt.add(index, t); // one-element sum consisting of element at "index" is the maximum
99
+ newMaxSumEndingAtIndex = sum;
100
+ }
101
+ maxSumEndingAt.add(index, newMaxSumEndingAtIndex);
102
+ update(index+1, newMaxSumEndingAtIndex);
103
+ }
104
+
105
+ private int compare(final ScalableValueWithDistance<ValueType, AveragesTo> a, final ScalableValueWithDistance<ValueType, AveragesTo> b) {
106
+ return a.divide(1).compareTo(b.divide(1));
107
+ }
108
+
109
+ /**
110
+ * For each element in {@link #sequence} starting at index {@code i}, this method checks whether the {@link #maxSumEndingAt}{@code [i]}
111
+ * still is the maximum of {@link #maxSumEndingAt}{@code [i-1]+sequence[i]} and {@link #sequence}{@code [i]}. If yes, any change to
112
+ * elements with index less than {@code i} do not have to be carried forward any further. Otherwise, {@link #maxSumEndingAt}{@code [i]}
113
+ * is updated, and the process continues at {@code i+1} "recursively" (implemented iteratively, without recursion).
114
+ * @param newMaxSumEndingAtIndex
115
+ */
116
+ private void update(int i, ScalableValueWithDistance<ValueType, AveragesTo> maxSumEndingAtPreviousIndex) {
117
+ final ListIterator<T> sequenceIter = sequence.listIterator(i);
118
+ final ListIterator<ScalableValueWithDistance<ValueType, AveragesTo>> maxSumEndingAtIter = maxSumEndingAt.listIterator(i);
119
+ boolean finished = false;
120
+ while (sequenceIter.hasNext() && !finished) {
121
+ final T next = sequenceIter.next();
122
+ final ScalableValueWithDistance<ValueType, AveragesTo> nextMaxSumEndingAt = maxSumEndingAtIter.next();
123
+ final ScalableValueWithDistance<ValueType, AveragesTo> sum = next.add(maxSumEndingAtPreviousIndex);
124
+ final ScalableValueWithDistance<ValueType, AveragesTo> newMaxSumEndingAt = compare(next, sum) >= 0 ?
125
+ next : sum;
126
+ if (compare(nextMaxSumEndingAt, newMaxSumEndingAt) != 0) {
127
+ maxSumEndingAtIter.remove();
128
+ maxSumEndingAtIter.add(newMaxSumEndingAt);
129
+ maxSumEndingAtPreviousIndex = newMaxSumEndingAt;
99 130
} else {
100
- maxSumEndingAt.add(index, t.add(maxSumEndingAt.get(index-1)));
101
- // TODO
131
+ finished = true; // no more changes to propagate
102 132
}
103 133
}
104
- // TODO update all structures, sums, indices, and invariants
105 134
}
106
-
135
+
107 136
public synchronized void remove(int index) {
108 137
sequence.remove(index);
109
- // TODO update all structures, sums, indices, and invariants
138
+ final ScalableValueWithDistance<ValueType, AveragesTo> maxSumEndingAtIndex = maxSumEndingAt.remove(index);
139
+ update(index+1, maxSumEndingAtIndex);
110 140
}
111 141
112 142
public synchronized void add(T t) {