This is an automated email from the ASF dual-hosted git repository. leirui pushed a commit to branch research/area-visualization in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit 98cdae627c79981b57c75de2eceec1913d99d1f9 Author: Lei Rui <[email protected]> AuthorDate: Thu Jan 23 02:56:14 2025 +0800 Add --- .../java/org/apache/iotdb/db/query/eBUG/Point.java | 20 ++ .../org/apache/iotdb/db/query/eBUG/Polyline.java | 4 + .../java/org/apache/iotdb/db/query/eBUG/Test1.java | 6 +- .../java/org/apache/iotdb/db/query/eBUG/eBUG.java | 175 +++++------ .../eBUG/eBUG_circulateArrayForEliminated.java | 325 +++++++++++++++++++++ 5 files changed, 439 insertions(+), 91 deletions(-) diff --git a/server/src/main/java/org/apache/iotdb/db/query/eBUG/Point.java b/server/src/main/java/org/apache/iotdb/db/query/eBUG/Point.java index 77ebdb4cb39..70aa19ea531 100644 --- a/server/src/main/java/org/apache/iotdb/db/query/eBUG/Point.java +++ b/server/src/main/java/org/apache/iotdb/db/query/eBUG/Point.java @@ -4,10 +4,30 @@ public class Point { double x, y, z; +// public boolean eliminated; // 滞后e个淘汰点 for eBUG usage + public Point prev; // 指向T'_max{0,k-e}里当前点的前一个点 for eBUG usage + public Point next; // 指向T'_max{0,k-e}里当前点的后一个点 for eBUG usage + // 注意Triangle里的prev&next用于最新状态下存在三角形之间的连接关系, + // 而这里Point的prev&next用于滞后e个淘汰点(也就是最近的e个淘汰点先不施加)状态下的未淘汰点之间的连接关系 + public Point(double x, double y) { this.x = x; this.y = y; this.z = Double.POSITIVE_INFINITY; // effective area + + // for eBUG usage +// this.eliminated = false; + this.prev = null; + this.next = null; + } + + public void markEliminated() { +// eliminated = true; + + // to avoid traversing each point between pa to pb, + // instead only traversing at most e most recently eliminated points lagged + prev.next = next; + next.prev = prev; } @Override diff --git a/server/src/main/java/org/apache/iotdb/db/query/eBUG/Polyline.java b/server/src/main/java/org/apache/iotdb/db/query/eBUG/Polyline.java index bed14731832..1ddfe2ebbe1 100644 --- a/server/src/main/java/org/apache/iotdb/db/query/eBUG/Polyline.java +++ b/server/src/main/java/org/apache/iotdb/db/query/eBUG/Polyline.java @@ -8,6 +8,10 @@ public class Polyline { private List<Point> vertices = new ArrayList<>(); public void addVertex(Point point) { +// if (!vertices.isEmpty()) { //before adding this point +// vertices.get(vertices.size() - 1).next = point; +// point.prev = vertices.get(vertices.size() - 1); +// } vertices.add(point); } diff --git a/server/src/main/java/org/apache/iotdb/db/query/eBUG/Test1.java b/server/src/main/java/org/apache/iotdb/db/query/eBUG/Test1.java index 56e73cc17e0..28b0eebd53e 100644 --- a/server/src/main/java/org/apache/iotdb/db/query/eBUG/Test1.java +++ b/server/src/main/java/org/apache/iotdb/db/query/eBUG/Test1.java @@ -43,11 +43,7 @@ public class Test1 { } System.out.println("---------------------------------"); -// List<Point> results = new ArrayList<>(); - // 计算运行时间 -// int eParam = 10; -// for (int eParam = 0; eParam < 2 * n; eParam += 1000) { - int eParam = 2; + int eParam = 1000000; long startTime = System.currentTimeMillis(); List<Point> results = buildEffectiveArea(polyline, eParam, false); // 输出结果 diff --git a/server/src/main/java/org/apache/iotdb/db/query/eBUG/eBUG.java b/server/src/main/java/org/apache/iotdb/db/query/eBUG/eBUG.java index 77e21a27067..906bc4e2366 100644 --- a/server/src/main/java/org/apache/iotdb/db/query/eBUG/eBUG.java +++ b/server/src/main/java/org/apache/iotdb/db/query/eBUG/eBUG.java @@ -29,56 +29,35 @@ import static org.apache.iotdb.db.query.eBUG.Tool.triArea; public class eBUG { - public static List<Point> findEliminated(Polyline lineToSimplify, int[] recentEliminated, - int pa_idx, int pi_idx, int pb_idx) { - // 复杂度分析 记c=b-a。 - // 如果e<c,那么从最近淘汰的e个点里寻找位于pa~pb之间的,找到的点和pa pi pb一起按照时间戳递增排序,后面鞋带公式计算面积:O(e+eloge) - // 否则e>=c,直接取T[a:b],已经排序号了,后面鞋带公式计算面积:O(c) - - // 性质:最近淘汰的那一个点一定是位于pa~pb之间,因为正是这个点的淘汰才使得pi的significance要更新! - - // pi: the point whose significance needs updating + public static List<Point> findEliminated(Polyline lineToSimplify, int pa_idx, int pb_idx) { // pa: left adjacent non-eliminated point of pi // pb: right adjacent non-eliminated point of pi - // return a list of points, containing pa,p,pb and points between pa&pa from the e most recently eliminated points, - // order by time in ascending order + // return a list of points, T'_max{0,k-e}[a:b] order by time in ascending order - Point pa = lineToSimplify.get(pa_idx); - Point pi = lineToSimplify.get(pi_idx); - Point pb = lineToSimplify.get(pb_idx); + // 性质:最近淘汰的那一个点一定是位于pa~pb之间,因为正是这个点的淘汰才使得pi的significance要更新!至于其他全局更早淘汰的点则不一定位于a:b之间 + // pa,xxx,pi,xxx,pb + // when e=0,遍历点数就是3 + // when e>0,遍历点数大于等于4、小于等于e+3 List<Point> res = new ArrayList<>(); - - // TODO note: here may happen because e=c=0 or just 0<c<=e - if (recentEliminated.length >= (pb_idx - pa_idx - 2)) { // e >= the total number of eliminated points in this region -// System.out.println("[c=(b-a-2)]<=e, use T directly"); // worst case下, k=c - res = lineToSimplify.getVertices().subList(pa_idx, pb_idx + 1); // 左闭右开 - return res; // 已经按照时间戳递增 + Point start = lineToSimplify.get(pa_idx); + Point end = lineToSimplify.get(pb_idx); +// int cnt = 0; + while (start != end) { // Point类里增加prev&next指针,这样T'_max{0,k-e}里点的连接关系就有了,这样从Pa开始沿着指针,遍历点数一定不超过e+3 + res.add(start); + start = start.next; // when e=0, only traversing three points pa pi pb +// cnt += 1; } - - // TODO note: here may happen because c>e=0 or c>e>0. the latter needs search among recentEliminated and sort by timestamp - // 从最近淘汰的e个点里寻找位于pa~pb之间的点,找到的有可能小于e个点 -// System.out.println("k>=[c=(b-a-2)]>e, search among e"); - res.add(pa); // 注意pa pi pb已经按照时间戳递增 - res.add(pi); - res.add(pb); - - // 包括了c>e=0的情况 - for (int idx : recentEliminated) { // e points - if (idx == 0) { // init, not filled by real eliminated points yet - break; - } - Point p = lineToSimplify.get(idx); - if (p.x > pa.x && p.x < pb.x) { - res.add(p); - } - } - - // 按照时间戳递增排序,这是为了后面计算total areal displacement需要 - if (recentEliminated.length > 0) { // 否则e=0,不需要排序pa pi pb三个点 - res.sort(Comparator.comparingDouble(p -> p.x)); // 按时间戳排序 这样的话时间复杂度变成e*log(e) - } - + res.add(end); +// cnt += 1; +// System.out.println(cnt); // 3<=cnt<=e+3 + +// for (int i = pa_idx; i <= pb_idx; i++) { // 左闭右闭 +// Point p = lineToSimplify.get(i); +// if (!p.eliminated) { +// res.add(p); +// } +// } return res; } @@ -90,8 +69,12 @@ public class eBUG { List<Point> results = lineToSimplify.getVertices(); // 浅复制 // 用循环数组来记录最近淘汰的点 - int[] recentEliminated = new int[e]; // init 0 points to the first point, skipped in findEliminated - int recentEliminatedIdx = 0; // index in the array, circulate +// int[] recentEliminated = new int[e]; // init 0 points to the first point, skipped in findEliminated +// int recentEliminatedIdx = 0; // index in the array, circulate + + // 存储的是点的引用,这样可以修改原来序列里点的淘汰状态 + // 存储的是距离当前最新状态的滞后的尚未施加、待施加的e个淘汰点 + LinkedList<Point> laggedEliminatedPoints = new LinkedList<>(); int total = lineToSimplify.size(); if (total < 3) { @@ -102,10 +85,21 @@ public class eBUG { Triangle[] triangles = new Triangle[nTriangles]; // 创建所有三角形并计算初始面积 +// lineToSimplify.get(0).eliminated = false; // 初始化点的状态 for eBUG usage + lineToSimplify.get(0).prev = null; + lineToSimplify.get(0).next = lineToSimplify.get(1); +// lineToSimplify.get(total - 1).eliminated = false; // 初始化点的状态 for eBUG usage + lineToSimplify.get(total - 1).next = null; + lineToSimplify.get(total - 1).prev = lineToSimplify.get(total - 2); for (int i = 1; i < total - 1; i++) { int index1 = i - 1, index2 = i, index3 = i + 1; double area = triArea(lineToSimplify.get(index1), lineToSimplify.get(index2), lineToSimplify.get(index3)); triangles[i - 1] = new Triangle(index1, index2, index3, area); + + // 初始化点的状态 for eBUG usage +// lineToSimplify.get(i).eliminated = false; + lineToSimplify.get(i).prev = lineToSimplify.get(i - 1); + lineToSimplify.get(i).next = lineToSimplify.get(i + 1); } // 设置三角形的前后关系 @@ -138,12 +132,18 @@ public class eBUG { if (debug) { System.out.println("(1) eliminate " + lineToSimplify.get(tri.indices[1])); } - if (e > 0) { // otherwise e=0 - recentEliminated[recentEliminatedIdx] = tri.indices[1]; - recentEliminatedIdx = (recentEliminatedIdx + 1) % e; // 0~e-1 circulate + if (e > 0) { + if (laggedEliminatedPoints.size() == e) { + // 已经有e个滞后淘汰点了,为了把最近淘汰点加入,得先把最老的淘汰点施加上去 + Point removedPoint = laggedEliminatedPoints.removeFirst(); // 取出最早加入的淘汰点 复杂度1 + removedPoint.markEliminated(); // 注意是引用,所以改的内容后面可以看到 + } + laggedEliminatedPoints.addLast(lineToSimplify.get(tri.indices[1])); // 加入最新的淘汰点,滞后在这里先不施加 + } else { // e=0 没有滞后 立即标记删除 T'_k + lineToSimplify.get(tri.indices[1]).markEliminated(); } if (debug) { - System.out.println("the e most recently eliminated points:" + Arrays.toString(recentEliminated)); + System.out.println("the e most recently eliminated points (lagged):" + laggedEliminatedPoints); } // 更新当前点的重要性(z 轴存储effective area,这是一个单调增的指标) @@ -172,12 +172,10 @@ public class eBUG { tri.prev.indices[2] = tri.indices[2]; // e parameter - List<Point> pointsForSig = findEliminated(lineToSimplify, recentEliminated, - tri.prev.indices[0], - tri.prev.indices[1], - tri.prev.indices[2]); // TODO complexity ? + List<Point> pointsForSig = findEliminated(lineToSimplify, tri.prev.indices[0], tri.prev.indices[2]); if (debug) { System.out.println("(2) update point on the left " + lineToSimplify.get(tri.prev.indices[1])); + System.out.println("3<=cnt<=e+3. cnt=" + pointsForSig.size()); for (Point point : pointsForSig) { System.out.println("\t" + point); } @@ -221,12 +219,10 @@ public class eBUG { tri.next.indices[0] = tri.indices[0]; // e parameter - List<Point> pointsForSig = findEliminated(lineToSimplify, recentEliminated, - tri.next.indices[0], - tri.next.indices[1], - tri.next.indices[2]); // TODO complexity + List<Point> pointsForSig = findEliminated(lineToSimplify, tri.next.indices[0], tri.next.indices[2]); if (debug) { System.out.println("(2) updating point on the right " + lineToSimplify.get(tri.next.indices[1])); + System.out.println("3<=cnt<=e+3. cnt=" + pointsForSig.size()); for (Point point : pointsForSig) { System.out.println("\t" + point); } @@ -259,45 +255,52 @@ public class eBUG { public static void main(String[] args) { - int eParam = 2000_0000; - try (PrintWriter writer = new PrintWriter(new File("exp_varyN_e" + eParam + ".csv"))) { - for (int n = 100_0000; n < 2000_0000; n += 200_0000) { // 超过两千万就都变得慢多了,感觉可能是内存有限的原因,而不是算法复杂度 - // TODO 注意 要有一个点是n=300w - - Polyline polyline = new Polyline(); - int seed = 1; - Random rand = new Random(seed); // TODO 注意seed在每轮里重设 - for (int i = 0; i < n; i++) { - double v = rand.nextInt(1000000); - polyline.addVertex(new Point(i, v)); - } +// int eParam = 0; + int[] eParamList = {0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 20, 30, 40, 50, 100, 200, 500, 1000, 2000, 5000, + 10000, 50000, 10_0000, 50_0000, 100_0000, 200_0000, 300_0000, + 500_0000, 800_0000, 1000_0000, + 1500_0000, 2000_0000, 2500_0000, 3000_0000}; + for (int eParam : eParamList) { + try (PrintWriter writer = new PrintWriter(new File("exp_varyN_e" + eParam + ".csv"))) { + for (int n = 100_0000; n < 2000_0000; n += 200_0000) { // 超过两千万就都变得慢多了,感觉可能是内存有限的原因,而不是算法复杂度 + // TODO 注意 要有一个点是n=300w + + Polyline polyline = new Polyline(); + int seed = 1; + Random rand = new Random(seed); // TODO 注意seed在每轮里重设 + for (int i = 0; i < n; i++) { + double v = rand.nextInt(1000000); + polyline.addVertex(new Point(i, v)); + } - long startTime = System.currentTimeMillis(); - List<Point> results = buildEffectiveArea(polyline, eParam, false); - long endTime = System.currentTimeMillis(); + long startTime = System.currentTimeMillis(); + List<Point> results = buildEffectiveArea(polyline, eParam, false); + long endTime = System.currentTimeMillis(); - System.out.println("n=" + n + ", e=" + eParam + ", Time taken to reduce points: " + (endTime - startTime) + "ms"); - writer.println(n + "," + eParam + "," + (endTime - startTime)); - System.out.println(results.size()); + System.out.println("n=" + n + ", e=" + eParam + ", Time taken to reduce points: " + (endTime - startTime) + "ms"); + writer.println(n + "," + eParam + "," + (endTime - startTime)); + System.out.println(results.size()); - // clear - polyline.clear(); - results.clear(); - polyline = null; - results = null; - System.gc(); +// // clear +// polyline.clear(); +// results.clear(); +// polyline = null; +// results = null; +// System.gc(); + } + } catch (FileNotFoundException e) { + throw new RuntimeException(e); } - } catch (FileNotFoundException e) { - throw new RuntimeException(e); } // int n = 300_0000; +// // int seed = 1; // Random rand = new Random(seed); // TODO 注意seed在每轮里重设 // Polyline polyline = new Polyline(); // 注意:如果是固定n变化e实验,这个数据要一次性生成,不然每次随机不一样 // for (int i = 0; i < n; i++) { // double v = rand.nextInt(1000000); -// polyline.addVertex(new Point(i, v)); +// polyline.addVertex(new Point(i, v)); // point的状态会在buildEffectiveArea里重置的,所以在下面的e遍历里可以复用这一份数据 // } // // try (PrintWriter writer = new PrintWriter(new File("exp_varyE_n" + n + ".csv"))) { @@ -314,7 +317,7 @@ public class eBUG { // System.out.println(results.size()); // // // clear 注意不能把原始数据清除,还要接着用 -// System.gc(); +//// System.gc(); // } // } catch (FileNotFoundException e) { // throw new RuntimeException(e); diff --git a/server/src/main/java/org/apache/iotdb/db/query/eBUG/eBUG_circulateArrayForEliminated.java b/server/src/main/java/org/apache/iotdb/db/query/eBUG/eBUG_circulateArrayForEliminated.java new file mode 100644 index 00000000000..38e9c96ad4e --- /dev/null +++ b/server/src/main/java/org/apache/iotdb/db/query/eBUG/eBUG_circulateArrayForEliminated.java @@ -0,0 +1,325 @@ +///* +// * Licensed to the Apache Software Foundation (ASF) under one +// * or more contributor license agreements. See the NOTICE file +// * distributed with this work for additional information +// * regarding copyright ownership. The ASF licenses this file +// * to you under the Apache License, Version 2.0 (the +// * "License"); you may not use this file except in compliance +// * with the License. You may obtain a copy of the License at +// * +// * http://www.apache.org/licenses/LICENSE-2.0 +// * +// * Unless required by applicable law or agreed to in writing, +// * software distributed under the License is distributed on an +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// * KIND, either express or implied. See the License for the +// * specific language governing permissions and limitations +// * under the License. +// */ +// +//package org.apache.iotdb.db.query.eBUG; +// +//import java.io.File; +//import java.io.FileNotFoundException; +//import java.io.PrintWriter; +//import java.util.*; +// +//import static org.apache.iotdb.db.query.eBUG.Tool.total_areal_displacement; +//import static org.apache.iotdb.db.query.eBUG.Tool.triArea; +// +// +//public class eBUG_circulateArrayForEliminated { +// public static List<Point> findEliminated(Polyline lineToSimplify, int[] recentEliminated, +// int pa_idx, int pi_idx, int pb_idx) { +// // 复杂度分析 记c=b-a。 +// // 如果e<c,那么从最近淘汰的e个点里寻找位于pa~pb之间的,找到的点和pa pi pb一起按照时间戳递增排序,后面鞋带公式计算面积:O(e+eloge) +// // 否则e>=c,直接取T[a:b],已经排序号了,后面鞋带公式计算面积:O(c) +// +// // 性质:最近淘汰的那一个点一定是位于pa~pb之间,因为正是这个点的淘汰才使得pi的significance要更新! +// +// // pi: the point whose significance needs updating +// // pa: left adjacent non-eliminated point of pi +// // pb: right adjacent non-eliminated point of pi +// // return a list of points, containing pa,p,pb and points between pa&pa from the e most recently eliminated points, +// // order by time in ascending order +// +// Point pa = lineToSimplify.get(pa_idx); +// Point pi = lineToSimplify.get(pi_idx); +// Point pb = lineToSimplify.get(pb_idx); +// +// List<Point> res = new ArrayList<>(); +// +// // TODO note: here may happen because e=c=0 or just 0<c<=e +// if (recentEliminated.length >= (pb_idx - pa_idx - 2)) { // e >= the total number of eliminated points in this region +//// System.out.println("[c=(b-a-2)]<=e, use T directly"); // worst case下, k=c +// res = lineToSimplify.getVertices().subList(pa_idx, pb_idx + 1); // 左闭右开 +// return res; // 已经按照时间戳递增 +// } +// +// // TODO note: here may happen because c>e=0 or c>e>0. the latter needs search among recentEliminated and sort by timestamp +// // 从最近淘汰的e个点里寻找位于pa~pb之间的点,找到的有可能小于e个点 +//// System.out.println("k>=[c=(b-a-2)]>e, search among e"); +// res.add(pa); // 注意pa pi pb已经按照时间戳递增 +// res.add(pi); +// res.add(pb); +// +// // 包括了c>e=0的情况 +// for (int idx : recentEliminated) { // e points +// if (idx == 0) { // init, not filled by real eliminated points yet +// break; +// } +// Point p = lineToSimplify.get(idx); +// if (p.x > pa.x && p.x < pb.x) { +// res.add(p); +// } +// } +// +// // 按照时间戳递增排序,这是为了后面计算total areal displacement需要 +// if (recentEliminated.length > 0) { // 否则e=0,不需要排序pa pi pb三个点 +// res.sort(Comparator.comparingDouble(p -> p.x)); // 按时间戳排序 这样的话时间复杂度变成e*log(e) +// } +// +// return res; +// } +// +// public static List<Point> buildEffectiveArea(Polyline lineToSimplify, int e, boolean debug) { +// if (e < 0) { +// throw new IllegalArgumentException("Parameter e must be non-negative."); +// } +// +// List<Point> results = lineToSimplify.getVertices(); // 浅复制 +// +// // 用循环数组来记录最近淘汰的点 +// int[] recentEliminated = new int[e]; // init 0 points to the first point, skipped in findEliminated +// int recentEliminatedIdx = 0; // index in the array, circulate +// +// int total = lineToSimplify.size(); +// if (total < 3) { +// return results; // 不足 3 个点无法形成三角形 +// } +// +// int nTriangles = total - 2; +// Triangle[] triangles = new Triangle[nTriangles]; +// +// // 创建所有三角形并计算初始面积 +// for (int i = 1; i < total - 1; i++) { +// int index1 = i - 1, index2 = i, index3 = i + 1; +// double area = triArea(lineToSimplify.get(index1), lineToSimplify.get(index2), lineToSimplify.get(index3)); +// triangles[i - 1] = new Triangle(index1, index2, index3, area); +// } +// +// // 设置三角形的前后关系 +// for (int i = 0; i < nTriangles; i++) { // TODO 这个可以和上一个循环合并吗??好像不可以 +// triangles[i].prev = (i == 0 ? null : triangles[i - 1]); +// triangles[i].next = (i == nTriangles - 1 ? null : triangles[i + 1]); +// } +// +// // 使用优先队列构建 minHeap +// PriorityQueue<Triangle> triangleHeap = new PriorityQueue<>(Comparator.comparingDouble(t -> t.area)); +// Collections.addAll(triangleHeap, triangles); // complexity TODO O(n) or O(nlogn)? +// +// double previousEA = -1; +// while (!triangleHeap.isEmpty()) { +// // 注意peek只需要直接访问该位置的元素,不涉及任何重排或堆化操作 +// // 而poll是删除堆顶元素,需要重新堆化以维护堆的性质,复杂度是O(logk),k是当前堆的大小 +// Triangle tri = triangleHeap.poll(); // O(logn) +// +// // 如果该三角形已经被删除,跳过. Avoid using heap.remove(x) as it is O(n) complexity +// // 而且除了heap里,已经没有其他节点会和它关联了,所有的connections关系已经迁移到新的角色替代节点上 +// if (tri.isDeleted) { +// if (debug) { +// System.out.println(">>>bottom-up, remaining " + triangleHeap.size() + " triangles (including those marked for removal)"); +// } +// continue; +// } +// +// // 真正的淘汰点 +// // 记录最近淘汰的点,注意不要重复记录也就是在上面执行之后再确认淘汰 +// if (debug) { +// System.out.println("(1) eliminate " + lineToSimplify.get(tri.indices[1])); +// } +// if (e > 0) { // otherwise e=0 +// recentEliminated[recentEliminatedIdx] = tri.indices[1]; +// recentEliminatedIdx = (recentEliminatedIdx + 1) % e; // 0~e-1 circulate +// } +// if (debug) { +// System.out.println("the e most recently eliminated points:" + Arrays.toString(recentEliminated)); +// } +// +// // 更新当前点的重要性(z 轴存储effective area,这是一个单调增的指标) +// if (tri.area > previousEA) { +// previousEA = tri.area; +// } +// results.get(tri.indices[1]).z = previousEA; // dominated significance +// if (debug) { +// System.out.println(Arrays.toString(tri.indices) + ", Dominated Sig=" + previousEA); +// } +// +// // 更新相邻三角形 +// if (tri.prev != null) { +// // 标记为失效点,同时new一个新的对象接管它的一切数据和前后连接关系,然后更新前后连接关系、更新significance、加入heap使其排好序 +// +// // 1. 处理旧的tri.prev被标记删除的事情(角色替代) +// // triangleHeap.remove(tri.prev); // Avoid using heap.remove(x) as it is O(n) complexity! +// tri.prev.markDeleted(); // O(1) 这个点标记为废掉,前后关联都砍断,但是不remove因为那太耗时,只要heap poll到它就跳过就可以 +// +// Triangle newPre = new Triangle(tri.prev); // deep copy and inherit connection +// // tri.prev = newPre; // can omit, because already done by new Triangle(tri.prev) +// +// // 2. 处理pi被淘汰引起tri.prev被更新的事情 +// // 前一个三角形连到后一个三角形 +// tri.prev.next = tri.next; // ATTENTION!!!: 这里的tri.next后面可能会因为处理旧的tri.next被标记删除的事情被换掉!到时候要重新赋值! +// tri.prev.indices[2] = tri.indices[2]; +// +// // e parameter +// List<Point> pointsForSig = findEliminated(lineToSimplify, recentEliminated, +// tri.prev.indices[0], +// tri.prev.indices[1], +// tri.prev.indices[2]); // TODO complexity ? +// if (debug) { +// System.out.println("(2) update point on the left " + lineToSimplify.get(tri.prev.indices[1])); +// for (Point point : pointsForSig) { +// System.out.println("\t" + point); +// } +// } +// List<Point> baseLine = new ArrayList<>(); +// baseLine.add(pointsForSig.get(0)); +// baseLine.add(pointsForSig.get(pointsForSig.size() - 1)); // 直接连接左右两边最近的未被淘汰的点 +// double sig = total_areal_displacement(pointsForSig, baseLine, false); +// tri.prev.area = sig; +// +// if (debug) { +// System.out.println("sig=" + sig); +// double tmpTri = triArea(lineToSimplify.get(tri.prev.indices[0]), +// lineToSimplify.get(tri.prev.indices[1]), +// lineToSimplify.get(tri.prev.indices[2])); +// System.out.println("\t" + "tri=" + tmpTri + ", " + ((tmpTri > sig) ? "over-estimated" : "equal/less-estimated")); +// } +// +// // 重新加入堆 +// // 在 Java 的 PriorityQueue 中,修改元素的属性不会自动更新堆的顺序 +// // 所以必须通过add来显式重新插入修改后的元素 +// triangleHeap.add(tri.prev); // O(logn) 注意加入的是一个新的对象isDeleted=false +// } +// +// if (tri.next != null) { +// // 标记为失效点,同时new一个新的对象接管它的一切数据和前后连接关系,然后更新前后连接关系、更新significance、加入heap使其排好序 +// +// // 1. 处理旧的tri.next被标记删除的事情(角色替代) +// // triangleHeap.remove(tri.next); // Avoid using heap.remove(x) as it is O(n) complexity +// tri.next.markDeleted(); // O(1) 这个点标记为废掉,前后关联都砍断,但是不remove因为那太耗时,只有poll到它就跳过就可以 +// +// Triangle newNext = new Triangle(tri.next); // deep copy and inherit connection +// // tri.next = newNext; // omit, because already done by new Triangle(tri.prev) +// +// if (tri.prev != null) { +// tri.prev.next = tri.next; // ATTENTION!!!: 这里的tri.next已经被换掉!所以之前的要重新赋值! +// } +// +// // 2. 处理pi被淘汰引起tri.next被更新的事情 +// tri.next.prev = tri.prev; // 注意此时tri.prev已经是替代后的节点,tri.next也是,从而被标记为废点的前后关联真正砍断 +// tri.next.indices[0] = tri.indices[0]; +// +// // e parameter +// List<Point> pointsForSig = findEliminated(lineToSimplify, recentEliminated, +// tri.next.indices[0], +// tri.next.indices[1], +// tri.next.indices[2]); // TODO complexity +// if (debug) { +// System.out.println("(2) updating point on the right " + lineToSimplify.get(tri.next.indices[1])); +// for (Point point : pointsForSig) { +// System.out.println("\t" + point); +// } +// } +// List<Point> baseLine = new ArrayList<>(); +// baseLine.add(pointsForSig.get(0)); +// baseLine.add(pointsForSig.get(pointsForSig.size() - 1)); // 直接连接左右两边最近的未被淘汰的点 +// double sig = total_areal_displacement(pointsForSig, baseLine, false); +// tri.next.area = sig; +// +// if (debug) { +// System.out.println("sig=" + sig); +// double tmpTri = triArea(lineToSimplify.get(tri.next.indices[0]), +// lineToSimplify.get(tri.next.indices[1]), +// lineToSimplify.get(tri.next.indices[2])); +// System.out.println("\t" + "tri=" + tmpTri + ", " + ((tmpTri > sig) ? "over-estimated" : "equal/less-estimated")); +// } +// +// // 重新加入堆 +// // 在 Java 的 PriorityQueue 中,修改元素的属性不会自动更新堆的顺序 +// // 所以必须通过add 来显式重新插入修改后的元素 +// triangleHeap.add(tri.next); // 注意加入的是一个新的对象isDeleted=false +// } +// if (debug) { +// System.out.println(">>>bottom-up, remaining " + triangleHeap.size() + " triangles (including those marked for removal)"); +// } +// } +// return results; // 注意这就是lineToSimplify.getVertices() +// } +// +// public static void main(String[] args) { +// +// int eParam = 2000_0000; +// try (PrintWriter writer = new PrintWriter(new File("exp_varyN_e" + eParam + ".csv"))) { +// for (int n = 100_0000; n < 2000_0000; n += 200_0000) { // 超过两千万就都变得慢多了,感觉可能是内存有限的原因,而不是算法复杂度 +// // TODO 注意 要有一个点是n=300w +// +// Polyline polyline = new Polyline(); +// int seed = 1; +// Random rand = new Random(seed); // TODO 注意seed在每轮里重设 +// for (int i = 0; i < n; i++) { +// double v = rand.nextInt(1000000); +// polyline.addVertex(new Point(i, v)); +// } +// +// long startTime = System.currentTimeMillis(); +// List<Point> results = buildEffectiveArea(polyline, eParam, false); +// long endTime = System.currentTimeMillis(); +// +// System.out.println("n=" + n + ", e=" + eParam + ", Time taken to reduce points: " + (endTime - startTime) + "ms"); +// writer.println(n + "," + eParam + "," + (endTime - startTime)); +// System.out.println(results.size()); +// +// // clear +// polyline.clear(); +// results.clear(); +// polyline = null; +// results = null; +// System.gc(); +// } +// } catch (FileNotFoundException e) { +// throw new RuntimeException(e); +// } +// +//// int n = 300_0000; +//// int seed = 1; +//// Random rand = new Random(seed); // TODO 注意seed在每轮里重设 +//// Polyline polyline = new Polyline(); // 注意:如果是固定n变化e实验,这个数据要一次性生成,不然每次随机不一样 +//// for (int i = 0; i < n; i++) { +//// double v = rand.nextInt(1000000); +//// polyline.addVertex(new Point(i, v)); +//// } +//// +//// try (PrintWriter writer = new PrintWriter(new File("exp_varyE_n" + n + ".csv"))) { +//// int[] eParamList = {0, 1, 2, 10, 1000, 10000, 10_0000, 30_0000, 50_0000, 60_0000, 80_0000, 100_0000, 150_0000, 200_0000}; +//// for (int eParam : eParamList) { +//// eParam *= 3; // TODO 注意 因为n=300w而不是100w +//// +//// long startTime = System.currentTimeMillis(); +//// List<Point> results = buildEffectiveArea(polyline, eParam, false); +//// long endTime = System.currentTimeMillis(); +//// +//// System.out.println("n=" + n + ", e=" + eParam + ", Time taken to reduce points: " + (endTime - startTime) + "ms"); +//// writer.println(n + "," + eParam + "," + (endTime - startTime)); +//// System.out.println(results.size()); +//// +//// // clear 注意不能把原始数据清除,还要接着用 +//// System.gc(); +//// } +//// } catch (FileNotFoundException e) { +//// throw new RuntimeException(e); +//// } +// +// System.out.println("finish"); +// } +//}
