java/com.sap.sse.common.test/src/com/sap/sse/common/test/KadaneExtremeSubsequenceFinderLinkedListTest.java
... ...
@@ -1,12 +0,0 @@
1
-package com.sap.sse.common.test;
2
-
3
-import org.junit.jupiter.api.BeforeEach;
4
-
5
-import com.sap.sse.common.scalablevalue.KadaneExtremeSubsequenceFinderLinkedListImpl;
6
-
7
-public class KadaneExtremeSubsequenceFinderLinkedListTest extends KadaneExtremeSubsequenceFinderTest {
8
- @BeforeEach
9
- public void setUp() {
10
- finder = new KadaneExtremeSubsequenceFinderLinkedListImpl<>();
11
- }
12
-}
java/com.sap.sse.common/src/com/sap/sse/common/scalablevalue/KadaneExtremeSubsequenceFinderLinkedListImpl.java
... ...
@@ -1,286 +0,0 @@
1
-package com.sap.sse.common.scalablevalue;
2
-
3
-import java.io.Serializable;
4
-import java.util.Iterator;
5
-import java.util.LinkedList;
6
-import java.util.List;
7
-import java.util.ListIterator;
8
-
9
-/**
10
- * This implementation uses {@link LinkedList}s to implement the full sequence and the max/min sum and start indices
11
- * collection. This requires index manipulations when elements are inserted to or removed from anywhere but the end of
12
- * the sequence.
13
- *
14
- * @author Axel Uhl (d043530)
15
- *
16
- */
17
-public class KadaneExtremeSubsequenceFinderLinkedListImpl<ValueType, AveragesTo extends Comparable<AveragesTo>, T extends ComparableScalableValueWithDistance<ValueType, AveragesTo>>
18
-implements KadaneExtremeSubsequenceFinder<ValueType, AveragesTo, T>, Serializable, Iterable<T> {
19
- private static final long serialVersionUID = 2109193559337714286L;
20
-
21
- /**
22
- * The elements constituting the full sequence in which to find the contiguous sub-sequences
23
- */
24
- private final List<T> sequence;
25
-
26
- /**
27
- * The element at index <tt>i</tt> holds the maximum value of the sum of any contiguous sub-sequence ending at index
28
- * <tt>i</tt>. Outside of {@code synchronized} blocks it holds as many elements as {@link #sequence}. The element
29
- * at index {@code i} is computed as {@code maxSumEndingAt.get(i-1)+sequence.get(i), max(sequence.get(i))}. This covers
30
- * the two cases extending the complete induction. Either, the sequence with the maximum sum ending at index {@code i}
31
- * includes prior elements; or the single element {@code sequence.get(i)} is greater than the sum of it and the maximum
32
- * sum ending at the previous element {@code i-1}.
33
- */
34
- private final List<ScalableValueWithDistance<ValueType, AveragesTo>> maxSumEndingAt;
35
-
36
- /**
37
- * Indices of the first element in {@link #sequence} of the contiguous sub-sequence having the maximum sum
38
- * ending at the {@link #sequence} index that corresponds with the index of the element in this list. Example:
39
- * if the contiguous sub-sequence in {@link #sequence} ending at the element before index 5 with the maximum
40
- * sum starts at index 1, then {@link #startIndexOfMaxSumSequence}{@code .get(5)==1}.
41
- */
42
- private List<Integer> startIndexOfMaxSumSequence;
43
-
44
- /**
45
- * Index of the element in {@link #sequence} at which the contiguous sub-sequence ends that has the maximum sum
46
- * of all such sub-sequences. This means that {@link #maxSumEndingAt}{@code .get(}{@link #endIndexOfMaxSumSequence})
47
- * is minimal across all elements in {@link #maxSumEndingAt}.
48
- */
49
- private int endIndexOfMaxSumSequence;
50
-
51
- /**
52
- * See {@code #maxSumEndingAt}, only for the minimum.
53
- */
54
- private final List<ScalableValueWithDistance<ValueType, AveragesTo>> minSumEndingAt;
55
-
56
- /**
57
- * Indices of the first element in {@link #sequence} of the contiguous sub-sequence having the minimum sum
58
- * ending at the {@link #sequence} index that corresponds with the index of the element in this list. Example:
59
- * if the contiguous sub-sequence in {@link #sequence} ending at the element before index 5 with the minimum
60
- * sum starts at index 1, then {@link #startIndexOfMaxSumSequence}{@code .get(5)==1}.
61
- */
62
- private List<Integer> startIndexOfMinSumSequence;
63
-
64
- /**
65
- * Index of the element in {@link #sequence} at which the contiguous sub-sequence ends that has the minimum sum
66
- * of all such sub-sequences. This means that {@link #minSumEndingAt}{@code .get(}{@link #endIndexOfMinSumSequence})
67
- * is minimal across all elements in {@link #minSumEndingAt}.
68
- */
69
- private int endIndexOfMinSumSequence;
70
-
71
- public KadaneExtremeSubsequenceFinderLinkedListImpl() {
72
- sequence = new LinkedList<>();
73
- maxSumEndingAt = new LinkedList<>();
74
- minSumEndingAt = new LinkedList<>();
75
- startIndexOfMaxSumSequence = new LinkedList<>();
76
- endIndexOfMaxSumSequence = -1;
77
- startIndexOfMinSumSequence = new LinkedList<>();
78
- endIndexOfMinSumSequence = -1;
79
- }
80
-
81
- @Override
82
- public synchronized void add(int index, T t) {
83
- final ScalableValueWithDistance<ValueType, AveragesTo> oldMaxSum = getMaxSum();
84
- final ScalableValueWithDistance<ValueType, AveragesTo> oldMinSum = getMinSum();
85
- final boolean insertingIntoMaxSumSequence = index <= endIndexOfMaxSumSequence && index > startIndexOfMaxSumSequence.get(endIndexOfMaxSumSequence);
86
- final boolean insertingIntoMinSumSequence = index <= endIndexOfMinSumSequence && index > startIndexOfMinSumSequence.get(endIndexOfMinSumSequence);
87
- sequence.add(index, t);
88
- final ScalableValueWithDistance<ValueType, AveragesTo> newMaxSumEndingAtIndex;
89
- final ScalableValueWithDistance<ValueType, AveragesTo> sumWithMax = index == 0 ? null : t.add(maxSumEndingAt.get(index-1));
90
- if (index == 0 || compare(t, sumWithMax) >= 0) {
91
- newMaxSumEndingAtIndex = t; // one-element sum consisting of element at "index" is the maximum
92
- startIndexOfMaxSumSequence.add(index, index);
93
- } else {
94
- newMaxSumEndingAtIndex = sumWithMax;
95
- startIndexOfMaxSumSequence.add(index, startIndexOfMaxSumSequence.get(index-1));
96
- }
97
- maxSumEndingAt.add(index, newMaxSumEndingAtIndex);
98
- if (oldMaxSum == null || compare(newMaxSumEndingAtIndex, oldMaxSum) > 0) {
99
- endIndexOfMaxSumSequence = index;
100
- }
101
- final ScalableValueWithDistance<ValueType, AveragesTo> newMinSumEndingAtIndex;
102
- final ScalableValueWithDistance<ValueType, AveragesTo> sumWithMin = index == 0 ? null : t.add(minSumEndingAt.get(index-1));
103
- if (index == 0 || compare(t, sumWithMin) <= 0) {
104
- newMinSumEndingAtIndex = t; // one-element sum consisting of element at "index" is the minimum
105
- startIndexOfMinSumSequence.add(index, index);
106
- } else {
107
- newMinSumEndingAtIndex = sumWithMin;
108
- startIndexOfMinSumSequence.add(index, startIndexOfMinSumSequence.get(index-1));
109
- }
110
- minSumEndingAt.add(index, newMinSumEndingAtIndex);
111
- if (oldMinSum == null || compare(newMinSumEndingAtIndex, oldMinSum) < 0) {
112
- endIndexOfMinSumSequence = index;
113
- }
114
- if (index < sequence.size()) {
115
- update(index+1, newMaxSumEndingAtIndex, newMinSumEndingAtIndex);
116
- }
117
- if (insertingIntoMaxSumSequence) { // TODO probably also check whether a "positive" value was inserted; in this case, max can only grow further, and sub-sequence indices will stay unchanged
118
- updateMax();
119
- }
120
- if (insertingIntoMinSumSequence) { // TODO probably also check whether a "negative" value was inserted; in this case, min can only shrink further, and sub-sequence indices will stay unchanged
121
- updateMin();
122
- }
123
- }
124
-
125
- private void updateMin() {
126
- // TODO Auto-generated method stub
127
-
128
- }
129
-
130
- private void updateMax() {
131
- // TODO Auto-generated method stub
132
-
133
- }
134
-
135
- private int compare(final ScalableValueWithDistance<ValueType, AveragesTo> a, final ScalableValueWithDistance<ValueType, AveragesTo> b) {
136
- return a.divide(1).compareTo(b.divide(1));
137
- }
138
-
139
- /**
140
- * For each element in {@link #sequence} starting at index {@code i}, this method checks whether the {@link #maxSumEndingAt}{@code [i]}
141
- * still is the maximum of {@link #maxSumEndingAt}{@code [i-1]+sequence[i]} and {@link #sequence}{@code [i]}. If yes, any change to
142
- * elements with index less than {@code i} do not have to be carried forward any further. Otherwise, {@link #maxSumEndingAt}{@code [i]}
143
- * is updated, and the process continues at {@code i+1} "recursively" (implemented iteratively, without recursion).
144
- */
145
- private void update(int i, ScalableValueWithDistance<ValueType, AveragesTo> maxSumEndingAtPreviousIndex, ScalableValueWithDistance<ValueType, AveragesTo> newMinSumEndingAtIndex) {
146
- final ListIterator<T> sequenceIter = sequence.listIterator(i);
147
- final ListIterator<ScalableValueWithDistance<ValueType, AveragesTo>> maxSumEndingAtIter = maxSumEndingAt.listIterator(i);
148
- final ListIterator<ScalableValueWithDistance<ValueType, AveragesTo>> minSumEndingAtIter = minSumEndingAt.listIterator(i);
149
- final ListIterator<Integer> startIndexOfMaxSumSequenceIter = startIndexOfMaxSumSequence.listIterator(i);
150
- final ListIterator<Integer> startIndexOfMinSumSequenceIter = startIndexOfMinSumSequence.listIterator(i);
151
- boolean finishedMax = false;
152
- boolean finishedMin = false;
153
- while (sequenceIter.hasNext() && (!finishedMax || !finishedMin)) {
154
- final T next = sequenceIter.next();
155
- if (!finishedMax) {
156
- final ScalableValueWithDistance<ValueType, AveragesTo> nextMaxSumEndingAt = maxSumEndingAtIter.next();
157
- startIndexOfMaxSumSequenceIter.next();
158
- final ScalableValueWithDistance<ValueType, AveragesTo> sum = next.add(maxSumEndingAtPreviousIndex);
159
- final boolean nextGreaterOrEqualsThanSum = compare(next, sum) >= 0;
160
- final ScalableValueWithDistance<ValueType, AveragesTo> newMaxSumEndingAt = nextGreaterOrEqualsThanSum ? next : sum;
161
- if (compare(nextMaxSumEndingAt, newMaxSumEndingAt) != 0) {
162
- maxSumEndingAtIter.remove();
163
- maxSumEndingAtIter.add(newMaxSumEndingAt);
164
- maxSumEndingAtPreviousIndex = newMaxSumEndingAt;
165
- startIndexOfMaxSumSequenceIter.remove();
166
- startIndexOfMaxSumSequenceIter.add(nextGreaterOrEqualsThanSum ? i : startIndexOfMaxSumSequence.get(i-1));
167
- if (compare(newMaxSumEndingAt, getMaxSum()) > 0) { // FIXME getMaxSum() cannot be asked while we are still updating; indices may have moved left (remove) or right (add)!
168
- endIndexOfMaxSumSequence = i;
169
- }
170
- } else {
171
- finishedMax = true; // no more changes to propagate
172
- }
173
- }
174
- if (!finishedMin) {
175
- final ScalableValueWithDistance<ValueType, AveragesTo> nextMinSumEndingAt = minSumEndingAtIter.next();
176
- startIndexOfMinSumSequenceIter.next();
177
- final ScalableValueWithDistance<ValueType, AveragesTo> sum = next.add(maxSumEndingAtPreviousIndex);
178
- final boolean nextLessOrEqualsThanSum = compare(next, sum) <= 0;
179
- final ScalableValueWithDistance<ValueType, AveragesTo> newMinSumEndingAt = nextLessOrEqualsThanSum ? next : sum;
180
- if (compare(nextMinSumEndingAt, newMinSumEndingAt) != 0) {
181
- minSumEndingAtIter.remove();
182
- minSumEndingAtIter.add(newMinSumEndingAt);
183
- maxSumEndingAtPreviousIndex = newMinSumEndingAt;
184
- startIndexOfMinSumSequenceIter.remove();
185
- startIndexOfMinSumSequenceIter.add(nextLessOrEqualsThanSum ? i : startIndexOfMinSumSequence.get(i-1));
186
- if (compare(newMinSumEndingAt, getMinSum()) < 0) {
187
- endIndexOfMinSumSequence = i;
188
- }
189
- } else {
190
- finishedMin = true; // no more changes to propagate
191
- }
192
- }
193
- i++;
194
- }
195
- }
196
-
197
- @Override
198
- public synchronized void remove(int index) {
199
- sequence.remove(index);
200
- final ScalableValueWithDistance<ValueType, AveragesTo> maxSumEndingAtIndex = maxSumEndingAt.remove(index);
201
- startIndexOfMaxSumSequence.remove(index);
202
- if (endIndexOfMaxSumSequence > index) {
203
- endIndexOfMaxSumSequence--;
204
- } else if (endIndexOfMaxSumSequence == index) {
205
- // TODO but if endIndexOfMaxSumSequence == index, we have deleted the last element of the max sum sequence and need to re-evaluate
206
- }
207
- if (endIndexOfMinSumSequence > index) {
208
- endIndexOfMinSumSequence--;
209
- } else if (endIndexOfMinSumSequence == index) {
210
- // TODO but if endIndexOfMinSumSequence == index, we have deleted the last element of the min sum sequence and need to re-evaluate
211
- }
212
- final ScalableValueWithDistance<ValueType, AveragesTo> minSumEndingAtIndex = minSumEndingAt.remove(index);
213
- startIndexOfMinSumSequence.remove(index);
214
- update(index+1, maxSumEndingAtIndex, minSumEndingAtIndex);
215
- }
216
-
217
- @Override
218
- public synchronized void add(T t) {
219
- add(sequence.size(), t);
220
- }
221
-
222
- @Override
223
- public synchronized void remove(T t) {
224
- remove(sequence.indexOf(t));
225
- }
226
-
227
- @Override
228
- public ScalableValueWithDistance<ValueType, AveragesTo> getMaxSum() {
229
- return endIndexOfMaxSumSequence == -1 ? null : maxSumEndingAt.get(endIndexOfMaxSumSequence);
230
- }
231
-
232
- @Override
233
- public ScalableValueWithDistance<ValueType, AveragesTo> getMinSum() {
234
- return endIndexOfMinSumSequence == -1 ? null : minSumEndingAt.get(endIndexOfMinSumSequence);
235
- }
236
-
237
- @Override
238
- public int getStartIndexOfMaxSumSequence() {
239
- return startIndexOfMaxSumSequence.isEmpty() ? -1 : startIndexOfMaxSumSequence.get(endIndexOfMaxSumSequence);
240
- }
241
-
242
- /**
243
- * @return the index into {@link #sequence} holding the last element of the contiguous sub-sequence that has the
244
- * maximal sum; note that pointing <em>to</em> and not <em>after</em> the last element of that sequence is
245
- * slightly different from how indices may be handled in some other from/to collection operations.
246
- */
247
- @Override
248
- public int getEndIndexOfMaxSumSequence() {
249
- return endIndexOfMaxSumSequence;
250
- }
251
-
252
- @Override
253
- public int getStartIndexOfMinSumSequence() {
254
- return startIndexOfMinSumSequence.isEmpty() ? -1 : startIndexOfMinSumSequence.get(endIndexOfMinSumSequence);
255
- }
256
-
257
- /**
258
- * @return the index into {@link #sequence} holding the last element of the contiguous sub-sequence that has the
259
- * minimal sum; note that pointing <em>to</em> and not <em>after</em> the last element of that sequence is
260
- * slightly different from how indices may be handled in some other from/to collection operations.
261
- */
262
- @Override
263
- public int getEndIndexOfMinSumSequence() {
264
- return endIndexOfMinSumSequence;
265
- }
266
-
267
- @Override
268
- public Iterator<T> iterator() {
269
- return sequence.iterator();
270
- }
271
-
272
- @Override
273
- public Iterator<T> getSubSequenceWithMaxSum() {
274
- return sequence.subList(getStartIndexOfMaxSumSequence(), getEndIndexOfMaxSumSequence()+1).iterator();
275
- }
276
-
277
- @Override
278
- public Iterator<T> getSubSequenceWithMinSum() {
279
- return sequence.subList(getStartIndexOfMinSumSequence(), getEndIndexOfMinSumSequence()+1).iterator();
280
- }
281
-
282
- @Override
283
- public int size() {
284
- return sequence.size();
285
- }
286
-}