|
|
@@ -0,0 +1,179 @@
|
|
|
+package com.huimv.guowei.admin.timer;
|
|
|
+
|
|
|
+
|
|
|
+import java.util.List;
|
|
|
+
|
|
|
+public class Pipe {
|
|
|
+ private final int pipeWidth, pipLength, threshold;
|
|
|
+ private int index;
|
|
|
+ private final boolean log = false;
|
|
|
+ private final List<Integer> data;
|
|
|
+
|
|
|
+ public Pipe(List<Integer> data) {
|
|
|
+ this.index = 0;
|
|
|
+ this.data = data;
|
|
|
+ this.pipeWidth = 40; // stable range
|
|
|
+ this.pipLength = 6; // stable window length
|
|
|
+ this.threshold = 100; // sudden change threshold
|
|
|
+ this.run();
|
|
|
+ }
|
|
|
+
|
|
|
+ public Pipe(List<Integer> data, int width, int length, int thresh) {
|
|
|
+ this.index = 0;
|
|
|
+ this.data = data;
|
|
|
+ this.pipeWidth = width;
|
|
|
+ this.pipLength = length;
|
|
|
+ this.threshold = thresh;
|
|
|
+ this.run();
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void show(List<Integer> data, String tag) {
|
|
|
+ System.out.println(tag + data);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void show(String tag) {
|
|
|
+ System.out.println(tag + this.data);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void run() {
|
|
|
+ while (this.index < this.data.size()) {
|
|
|
+ this.index = nextSudden();
|
|
|
+ if (this.index == -1) break;
|
|
|
+ int last = lastStable(), next = nextStable();
|
|
|
+ if (last == -1) {
|
|
|
+ if (next == -1) {
|
|
|
+ smoothAfter(this.index);
|
|
|
+ break;
|
|
|
+ } else {
|
|
|
+ int value = stableValue(false, next);
|
|
|
+ for (; this.index < next; this.index++) {
|
|
|
+ if (this.log) System.out.printf("update1: data[%d]=%d -> %d\n", this.index, this.data.get(this.index), value);
|
|
|
+ this.data.set(this.index, value);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ int value1 = stableValue(true, last);
|
|
|
+ if (next == -1) {
|
|
|
+ for (; this.index < this.data.size(); this.index++) {
|
|
|
+ if (this.log) System.out.printf("update2: data[%d]=%d -> %d\n", this.index, this.data.get(this.index), value1);
|
|
|
+ this.data.set(this.index, value1);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ } else {
|
|
|
+ int value2 = stableValue(false, next);
|
|
|
+ if (Math.abs(value1 - this.data.get(this.index)) < Math.abs(value2 - this.data.get(this.index))) {
|
|
|
+ for (int i = last + this.pipLength; i <= this.index; ++i) {
|
|
|
+ if (this.log) System.out.printf("update3: data[%d]=%d -> %d\n", i, this.data.get(i), value1);
|
|
|
+ this.data.set(i, value1);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ for (; this.index < next; this.index++) {
|
|
|
+ if (this.log) System.out.printf("update4: data[%d]=%d -> %d\n", this.index, this.data.get(this.index), value2);
|
|
|
+ this.data.set(this.index, value2);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private int nextSudden() {
|
|
|
+ if (this.log) System.out.printf("find sudden from %d\n", this.index);
|
|
|
+ for (int start = this.index, end = this.data.size() - 1; start < end; start++) {
|
|
|
+ if (Math.abs(this.data.get(start) - this.data.get(start + 1)) > this.threshold) {
|
|
|
+ if (this.log) System.out.printf("data[%d]=%d, data[%d]=%d, sudden found\n", start, this.data.get(start), start + 1, this.data.get(start + 1));
|
|
|
+ return start + 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ private int nextStable() {
|
|
|
+ int start = this.index + 1, end = this.index + this.pipLength;
|
|
|
+ while (end < this.data.size()) {
|
|
|
+ boolean stable = true;
|
|
|
+ for (int i = start; i < end; i++) {
|
|
|
+ if (Math.abs(this.data.get(i) - this.data.get(i + 1)) > this.pipeWidth) {
|
|
|
+ stable = false;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (stable) return start;
|
|
|
+ else {
|
|
|
+ start++;
|
|
|
+ end++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ private int lastStable() {
|
|
|
+ int start = this.index - this.pipLength, end = this.index - 1;
|
|
|
+ while (start >= 0) {
|
|
|
+ boolean stable = true;
|
|
|
+ for (int i = start; i < end; i++) {
|
|
|
+ if (Math.abs(this.data.get(i) - this.data.get(i + 1)) > this.pipeWidth) {
|
|
|
+ stable = false;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (stable) return start;
|
|
|
+ else {
|
|
|
+ start--;
|
|
|
+ end--;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ private Integer stableValue(boolean last, int start) {
|
|
|
+ if (last) return this.data.get(start + this.pipLength - 1);
|
|
|
+ else return this.data.get(start);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void smoothAfter(int start) {
|
|
|
+ for (; start < this.data.size(); ++start) {
|
|
|
+ if (this.log) System.out.printf("data[%d]=%d -> %d\n", start, this.data.get(start), windowAvg(start));
|
|
|
+ this.data.set(start, windowAvg(start));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private int windowAvg(int start) {
|
|
|
+ int end = start + this.pipLength;
|
|
|
+ if (end > this.data.size()) {
|
|
|
+ end = this.data.size();
|
|
|
+ start = end - this.pipLength;
|
|
|
+ }
|
|
|
+ int sum = 0;
|
|
|
+ while (start != end) sum += this.data.get(start++);
|
|
|
+ return sum / this.pipLength;
|
|
|
+ }
|
|
|
+
|
|
|
+ public int calcWeightLoss(final int hold) {
|
|
|
+ int sum = 0, pos1 = 0, pos2;
|
|
|
+ while (true) {
|
|
|
+ pos2 = nextAdd(pos1, hold);
|
|
|
+ if (pos2 == -1) {
|
|
|
+ int tmp = this.data.get(pos1) - this.data.get(this.data.size() - 1);
|
|
|
+ sum += Math.max(tmp, 0);
|
|
|
+ if (this.log) System.out.printf("data[%d]=%d - data[tail]=%d = %d, sum = %d\n", pos1, this.data.get(pos1), this.data.get(this.data.size() - 1), tmp, sum);
|
|
|
+ break;
|
|
|
+ } else {
|
|
|
+ int tmp = this.data.get(pos1) - this.data.get(pos2);
|
|
|
+ sum += Math.max(tmp, 0);
|
|
|
+ if (this.log) System.out.printf("data[%d]=%d - data[%d]=%d = %d, sum = %d\n", pos1, this.data.get(pos1), pos2, this.data.get(pos2), tmp, sum);
|
|
|
+ pos1 = pos2 + 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return sum;
|
|
|
+ }
|
|
|
+
|
|
|
+ private int nextAdd(int start, int hold) {
|
|
|
+ for (; start < this.data.size() - 1; start++) {
|
|
|
+ if (this.data.get(start + 1) - this.data.get(start) > hold) {
|
|
|
+ return start;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+}
|