Skip to content

Commit d1e822c

Browse files
authored
[PR] Merge pull request #67 from CSC207-2022F-UofT/progress-speed-test
Test progress speed classes
2 parents 550ae90 + 23498a5 commit d1e822c

File tree

4 files changed

+166
-8
lines changed

4 files changed

+166
-8
lines changed

src/main/java/org/hydev/mcpm/client/interaction/ProgressSpeedCalculator.java

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package org.hydev.mcpm.client.interaction;
22

33
import org.hydev.mcpm.utils.Pair;
4+
import org.hydev.mcpm.utils.arrays.FixedWindowSum;
5+
import org.hydev.mcpm.utils.arrays.SlidingWindow;
46

57
import java.util.ArrayDeque;
68
import java.util.Queue;
@@ -16,30 +18,40 @@
1618
* @since 2022-11-19
1719
*/
1820
public class ProgressSpeedCalculator implements ProgressSpeedBoundary {
19-
private final Queue<Pair<Long, Long>> queue = new ArrayDeque<>();
21+
private final FixedWindowSum windowSum;
2022
private final long window;
2123
private final long start;
2224

2325
private long total = 0; // total to calculate inc in setProgress
2426
private long sum = 0; // sliding window sum
2527

2628
/**
29+
* Construct a ProgressSpeedCalculator with a window size.
2730
*
2831
* @param window Time length of the window to calculate speed over, in nanoseconds
2932
*/
3033
public ProgressSpeedCalculator(long window) {
31-
start = System.nanoTime();
34+
this(window, new SlidingWindow().setWindowSize(window));
35+
}
36+
37+
/**
38+
* Construct a ProgressSpeedCalculator with the specified FixedWindowSum to calculate speed.
39+
* Window speed should be in nanoseconds.
40+
*
41+
* @param window window size of the given windowSum
42+
* @param windowSum the FixedWindowSum used to calculate speed
43+
*/
44+
public ProgressSpeedCalculator(long window, FixedWindowSum windowSum) {
3245
this.window = window;
46+
start = System.nanoTime();
47+
this.windowSum = windowSum;
3348
}
3449

3550

3651
@Override
3752
public double getSpeed() {
3853
long time = System.nanoTime();
39-
while (!queue.isEmpty() && queue.peek().k() < time - window) { // remove all elements that are too old
40-
var e = queue.remove();
41-
sum -= e.v(); // update sliding window sum
42-
}
54+
long sum = windowSum.sum(time);
4355
long dt = Math.min(window, time - start);
4456
return sum / (dt / 1e9);
4557
}
@@ -55,7 +67,6 @@ public void setProgress(long progress) {
5567

5668
@Override
5769
public void incProgress(long inc) {
58-
queue.add(new Pair<>(System.nanoTime(), inc));
59-
sum += inc;
70+
windowSum.add(System.nanoTime(), inc);
6071
}
6172
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package org.hydev.mcpm.utils.arrays;
2+
3+
/**
4+
* A data structure supporting appending of index-value pairs
5+
* and querying the sum of all values in a fixed window size.
6+
* This only supports addition non-decreasing index pairs, and queries of non-increasing indices,
7+
* and queries of a fixed window size.
8+
*
9+
* @author Peter (https://github.com/MstrPikachu)
10+
* @since 2022-11-21
11+
*/
12+
public interface FixedWindowSum {
13+
14+
/**
15+
* Set the size of the window. After creating an instance, start by calling this and only call it at most once.
16+
*
17+
* @param window size of the window
18+
* @return this object for fluent access
19+
*/
20+
FixedWindowSum setWindowSize(long window);
21+
22+
/**
23+
* Add an index-value pair to the window.
24+
*
25+
* @param index the index of the pair
26+
* @param val value to add to data structure
27+
*/
28+
void add(long index, long val);
29+
30+
/**
31+
* Query the sum of all values that have an index within the window size (exclusive)
32+
* that ends at the index of the most recent addition / query.
33+
*
34+
* @return the result of the query
35+
*/
36+
long sum();
37+
38+
/**
39+
* Query the sum of all values that have an index within the window size (exclusive) that ends at the given index.
40+
*
41+
* @param index the given index
42+
* @return the result of the query
43+
*/
44+
long sum(long index);
45+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package org.hydev.mcpm.utils.arrays;
2+
3+
import org.hydev.mcpm.utils.Pair;
4+
5+
import java.util.ArrayDeque;
6+
import java.util.Queue;
7+
8+
/**
9+
* An implementation of FixedWindowSum using a queue.
10+
*
11+
* @author Peter (https://github.com/MstrPikachu)
12+
* @since 2022-11-21
13+
*/
14+
public class SlidingWindow implements FixedWindowSum {
15+
private long sum;
16+
private long window;
17+
private final Queue<Pair<Long, Long>> queue = new ArrayDeque<>();
18+
19+
@Override
20+
public FixedWindowSum setWindowSize(long window) {
21+
this.window = window;
22+
return this;
23+
}
24+
25+
@Override
26+
public void add(long index, long inc) {
27+
queue.add(new Pair<>(index, inc));
28+
sum += inc; // increase sum after adding a new value
29+
restore(index);
30+
}
31+
32+
@Override
33+
public long sum() {
34+
return sum;
35+
}
36+
37+
@Override
38+
public long sum(long index) {
39+
restore(index);
40+
return sum;
41+
}
42+
43+
/**
44+
* Restore the invariant that all values in the queue are within the window
45+
*
46+
* @param index index of the newest query/insert
47+
*/
48+
private void restore(long index) {
49+
// remove values outside the window, O(1) amortized
50+
while (!queue.isEmpty() && queue.peek().getKey() < index - window) {
51+
var element = queue.poll(); // remove the oldest value if it is outside the window
52+
sum -= element.getValue(); // decrement sum after removing values
53+
}
54+
}
55+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package org.hydev.mcpm.utils.arrays;
2+
3+
import org.hydev.mcpm.utils.Pair;
4+
import org.junit.jupiter.api.Test;
5+
6+
import java.util.ArrayList;
7+
import java.util.Random;
8+
9+
import static org.junit.jupiter.api.Assertions.*;
10+
11+
class SlidingWindowTest {
12+
13+
ArrayList<Pair<Long, Long>> arr;
14+
SlidingWindow slidingWindow;
15+
long window;
16+
17+
18+
long naiveSum(long index) {
19+
long ret = 0;
20+
for (int i = arr.size() - 1; i >= 0; i--) {
21+
if (arr.get(i).getKey() < index - window)
22+
break;
23+
ret += arr.get(i).getValue();
24+
}
25+
return ret;
26+
}
27+
28+
@Test
29+
void testAll() {
30+
Random r = new Random();
31+
for (int window = 1; window <= 5001; window += 5) {
32+
this.window = window;
33+
long cur = 0;
34+
arr = new ArrayList<>();
35+
slidingWindow = new SlidingWindow();
36+
slidingWindow.setWindowSize(window);
37+
for (int i = 0; i < 1000; i++) {
38+
long x = r.nextLong();
39+
int ind = Math.abs(r.nextInt());
40+
cur += ind;
41+
arr.add(new Pair<>(cur, x));
42+
slidingWindow.add(cur, x);
43+
assertEquals(slidingWindow.sum(cur), naiveSum(cur));
44+
}
45+
}
46+
}
47+
}

0 commit comments

Comments
 (0)