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 364f0d8d0b6f2780e69203b5a5240be3bc3b337b
Author: Lei Rui <[email protected]>
AuthorDate: Mon Jan 27 21:53:44 2025 +0800

    dp
---
 server/pom.xml                                     |  10 +-
 server/sample_eBUG-jar-with-dependencies.jar       | Bin 38715994 -> 38716020 
bytes
 .../java/org/apache/iotdb/db/query/eBUG/DP.java    | 286 +++++++++
 .../java/org/apache/iotdb/db/query/eBUG/Tool.java  | 712 +++++++++++----------
 .../java/org/apache/iotdb/db/query/eBUG/eBUG.java  |  44 +-
 5 files changed, 694 insertions(+), 358 deletions(-)

diff --git a/server/pom.xml b/server/pom.xml
index 66ccebdb43a..b0b6be3c539 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -281,13 +281,13 @@
             <plugin>
                 <artifactId>maven-assembly-plugin</artifactId>
                 <configuration>
-                    <finalName>sample_fsw</finalName>
-                    <!--                    
<finalName>sample_eBUG</finalName>-->
-                    <!--                    
<finalName>sample_BUL2</finalName>-->
+                    <!--                    
<finalName>sample_fsw</finalName>-->
+                    <finalName>sample_eBUG</finalName>
+                    <!--                                        
<finalName>sample_BUL2</finalName>-->
                     <archive>
                         <manifest>
-                            
<mainClass>org.apache.iotdb.db.query.eBUG.sample_FSW</mainClass>
-                            <!--                            
<mainClass>org.apache.iotdb.db.query.eBUG.sample_eBUG</mainClass>-->
+                            <!--                            
<mainClass>org.apache.iotdb.db.query.eBUG.sample_FSW</mainClass>-->
+                            
<mainClass>org.apache.iotdb.db.query.eBUG.sample_eBUG</mainClass>
                             <!--                            
<mainClass>org.apache.iotdb.db.query.eBUG.sample_bottomUpL2</mainClass>-->
                         </manifest>
                     </archive>
diff --git a/server/sample_eBUG-jar-with-dependencies.jar 
b/server/sample_eBUG-jar-with-dependencies.jar
index a37acfd0590..0df972fa4a5 100644
Binary files a/server/sample_eBUG-jar-with-dependencies.jar and 
b/server/sample_eBUG-jar-with-dependencies.jar differ
diff --git a/server/src/main/java/org/apache/iotdb/db/query/eBUG/DP.java 
b/server/src/main/java/org/apache/iotdb/db/query/eBUG/DP.java
new file mode 100644
index 00000000000..a6a9647fb4b
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/query/eBUG/DP.java
@@ -0,0 +1,286 @@
+package org.apache.iotdb.db.query.eBUG;
+
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.*;
+
+// Some public references about dynamic programming:
+// https://justinwillmert.com/articles/2014/bellman-k-segmentation-algorithm/
+// https://github.com/CrivelliLab/Protein-Structure-DL
+
+public class DP { // Dynamic-Programming
+
+    // Enum to represent error types
+    public enum ERROR {
+        L1, L2, L_infy, area
+    }
+
+    // precomputing error measures of all possible segments, e.g., ad2 table
+    public static double[][] prepareCostTable(List<Point> points, ERROR 
errorType, boolean debug) {
+        int N = points.size();
+        double[][] dists = new double[N][N]; // 默认0,对角线元素已经都是0了
+
+        // 外层循环i:range长度=right boundary-left boundary
+        // 内层循环j: 矩阵逐行
+        for (int i = 1; i < N; i++) { // TODO
+            for (int j = 0; j < N - i; j++) {
+                // j = left boundary, r = right boundary, 左闭右闭
+                int r = i + j; // r<N
+                if (debug) {
+                    System.out.println(">>>> i=" + i + ", j=" + j + ", r=" + 
r);
+                }
+
+                // lx=j,rx=r, 从lx=j到rx=r(左闭右闭)的linear 
interpolation(即连接lx和rx点)的errorType类型的误差
+                double mc = joint_segment_error(points, j, r, errorType);
+                dists[j][r] = mc;
+                if (debug) {
+                    System.out.println("dists=");
+                    Tool.printArray(dists);
+                    System.out.println("---------------------");
+                }
+            }
+        }
+        return dists;
+    }
+
+    // 注意k是分段数,不是采点数
+    public static List<Point> dynamic_programming(List<Point> points, int k, 
ERROR errorType, boolean debug) {
+        int N = points.size();
+
+        // 预计算dists(即ad2 table),dists[i][j]代表对子序列i:j左闭右闭直接连接pi和pj的近似误差
+        double[][] dists = prepareCostTable(points, errorType, debug);
+        if (debug) {
+            Tool.printArray(dists);
+            System.out.println("----------------------------------");
+        }
+
+        // 创建dp table。kSegDist[i][j]代表把子序列T[0:j]左闭右闭分成i段(java从0开始计数)的最小误差
+        double[][] kSegDist = new double[k][N];
+        // Initialize the case k=1 directly from the pre-computed distances
+        // 注意java从0开始,所以是0 index第一行代表分段数1
+        System.arraycopy(dists[0], 0, kSegDist[0], 0, kSegDist[0].length);
+        if (debug) {
+            System.out.println("k_seg_dist=");
+            Tool.printArray(kSegDist);
+        }
+
+        // 创建path table。记录子问题的解。kSegPath[i][j]代表把T[0:j]分成i段这个问题的最优子问题的位置
+        // 子问题是把T[0:kSegPath[i][j]]分成i-1段,以及最后一段T[kSegPath[i][j]:end]
+        int[][] kSegPath = new int[k][N];
+        // 第一行只分一段,所以不管终点是哪个(列),左边的闭合起点都是0
+        // 虽然java数组默认初始是0,但是这里还是显式赋值
+        Arrays.fill(kSegPath[0], 0);
+        if (debug) {
+            System.out.println("k_seg_path=");
+            Tool.printArray(kSegPath);
+        }
+
+        // 外层循环i:分段数,注意python从0开始,所以实际含义是2~k个分段数
+        for (int i = 1; i < k; i++) {
+            // 内层循环j:从第一个点开始到j终点(闭合)的序列
+            // 所以含义是:找到从第一个点开始到j终点(闭合)的序列的分成(i+1)段的最佳分段方案(误差最小)
+            for (int j = 0; j < N; j++) {
+                // 动态规划
+                // 注意linear interpolation不需要单点成为一个分段的情况
+                // TODO 误差类型
+                // TODO ghost修复
+                // 从0:j的序列分成i段的问题:遍历所有可能的子问题组合解
+                if (debug) {
+                    System.out.println(">>>分段数i+1" + (i + 1) + ",end pos j=" + 
j);
+                }
+                double[] choices = new double[j + 1]; // java从0开始
+                for (int xtmp = 0; xtmp < j + 1; xtmp++) {
+                    if (errorType == ERROR.L_infy) {
+                        choices[xtmp] = Math.max(kSegDist[i - 1][xtmp], 
dists[xtmp][j]);
+                    } else {
+                        choices[xtmp] = kSegDist[i - 1][xtmp] + dists[xtmp][j];
+                    }
+                }
+                if (debug) {
+                    for (int xtmp = 0; xtmp < j + 1; xtmp++) {  // 遍历从 0 到 j 
的每个元素
+                        if (errorType == ERROR.L_infy) {
+                            System.out.printf("  max((k_seg_dist[%d, %d] = 
%f), (dists[%d, %d] = %f)) --> %f%n",
+                                    i - 1, xtmp, kSegDist[i - 1][xtmp],
+                                    xtmp, j, dists[xtmp][j],
+                                    Math.max(kSegDist[i - 1][xtmp], 
dists[xtmp][j]));
+                        } else {
+                            System.out.printf("  (k_seg_dist[%d, %d] = %f) + 
(dists[%d, %d] = %f) --> %f%n",
+                                    i - 1, xtmp, kSegDist[i - 1][xtmp],
+                                    xtmp, j, dists[xtmp][j],
+                                    kSegDist[i - 1][xtmp] + dists[xtmp][j]);
+                        }
+                    }
+                }
+
+                int bestIndex = getIndexOfMin(choices);
+                double bestVal = choices[bestIndex];
+
+                // Store the sub-problem solution
+                kSegPath[i][j] = bestIndex;
+
+                kSegDist[i][j] = bestVal;
+
+                if (debug) {
+                    System.out.println("kSegDist[" + i + "][" + j + "] = " + 
bestVal);
+                    System.out.println("kSegDist=");
+                    Tool.printArray(kSegDist);
+                    System.out.println("kSegPath=");
+                    Tool.printArray(kSegPath);
+                }
+            }
+        }
+
+        // 开始回溯构建采样结果
+        List<Point> sDs = new ArrayList<>(); // k+1个采样点
+        List<Integer> sDs_idx = new ArrayList<>();
+        int rhs = N - 1;
+        sDs.add(points.get(rhs)); // 全局尾点
+        sDs_idx.add(rhs);
+
+        for (int i = k - 1; i >= 0; i--) {
+            int lhs = kSegPath[i][rhs];
+            sDs.add(points.get(lhs));
+            sDs_idx.add(lhs);
+            rhs = lhs;
+        }
+
+        // 反转列表
+        Collections.reverse(sDs);
+        Collections.reverse(sDs_idx);
+
+        if (debug) {
+            System.out.println(sDs);
+            System.out.println(">>>>>ad2[][]=");
+            Tool.printArray(dists);
+            System.out.println(">>>>>dp[][]=");
+            Tool.printTransposeArray(kSegDist);
+            System.out.println(">>>>>path[][]=");
+            Tool.printTransposeArray(kSegPath);
+            System.out.println(error(points, sDs_idx, errorType));
+        }
+
+        return sDs;
+    }
+
+    // Helper method to get index of minimum value
+    private static int getIndexOfMin(double[] array) {
+        double minVal = array[0];
+        int minIndex = 0;
+        for (int i = 1; i < array.length; i++) {
+            if (array[i] < minVal) {
+                minVal = array[i];
+                minIndex = i;
+            }
+        }
+        return minIndex;
+    }
+
+    // Method to calculate joint segment error based on error type
+    private static double joint_segment_error(List<Point> points, int lx, int 
rx, ERROR errorType) {
+        // 默认joint=true, residual=true,即使用linear interpolation近似分段
+        // lx~rx 左闭右闭
+        if (errorType != ERROR.area) {
+            double x1 = points.get(lx).x;
+            double y1 = points.get(lx).y;
+            double x2 = points.get(rx).x;
+            double y2 = points.get(rx).y;
+
+            // linear interpolation:
+            double k = (y2 - y1) / (x2 - x1);
+            double b = (y1 * x2 - y2 * x1) / (x2 - x1);
+
+            double tmp = 0;
+            if (errorType == ERROR.L2) {
+                for (int i = lx; i <= rx; i++) {
+                    double e = (k * points.get(i).x + b - points.get(i).y) * 
(k * points.get(i).x + b - points.get(i).y);
+                    tmp += e;
+                }
+            } else if (errorType == ERROR.L1) {
+                for (int i = lx; i <= rx; i++) {
+                    double e = Math.abs(k * points.get(i).x + b - 
points.get(i).y);
+                    tmp += e;
+                }
+            } else if (errorType == ERROR.L_infy) {
+                for (int i = lx; i <= rx; i++) {
+                    double e = Math.abs(k * points.get(i).x + b - 
points.get(i).y); // 注意绝对值
+                    if (e > tmp) {
+                        tmp = e;
+                    }
+                }
+            }
+            return tmp;
+        } else { // AD
+            List<Point> linearInterpolation = new ArrayList<>();
+            linearInterpolation.add(points.get(lx));
+            linearInterpolation.add(points.get(rx));
+            return Tool.total_areal_displacement(points.subList(lx, rx + 1), 
// 注意lx,rx左闭右闭
+                    linearInterpolation, false);
+        }
+    }
+
+    public static double error(List<Point> points, List<Integer> sampledIdx, 
ERROR errorType) {
+        double res = 0;
+        for (int i = 0; i < sampledIdx.size() - 1; i++) {
+            int lx = sampledIdx.get(i);
+            int rx = sampledIdx.get(i + 1);
+            double e = joint_segment_error(points, lx, rx, errorType);
+            if (errorType == ERROR.L_infy) {
+                res = Math.max(res, e);
+            } else {
+                res += e;
+            }
+        }
+        return res;
+    }
+
+    // Example usage
+    public static void main(String[] args) {
+        Random rand = new Random(10);
+        String input = "D:\\LabSync\\iotdb\\我的Gitbook基地\\RUI Lei 
gitbook\\士论\\49. visval改进\\notebook\\raw.csv";
+        boolean hasHeader = true;
+        int timeIdx = 0;
+        int valueIdx = 1;
+        int N = -1;
+        List<Point> points = Tool.readFromFile(input, hasHeader, timeIdx, 
valueIdx, N);
+//        Polyline polyline = new Polyline();
+//        for (int i = 0; i < N; i += 1) {
+//            double v = rand.nextInt(1000);
+//            polyline.addVertex(new Point(i, v));
+//        }
+//        List<Point> points = polyline.getVertices();
+        try (FileWriter writer = new FileWriter("raw.csv")) {
+            // 写入CSV头部
+            writer.append("x,y,z\n");
+
+            // 写入每个点的数据
+            for (Point point : points) {
+                writer.append(point.x + "," + point.y + "," + point.z + "\n");
+            }
+            System.out.println(points.size() + " Data has been written");
+        } catch (IOException e) {
+            System.out.println("Error writing to CSV file: " + e.getMessage());
+        }
+
+        long startTime = System.currentTimeMillis();
+//        double[][] ad2 = prepareKSegments(points, ERROR.L1, false);
+        int m = 4;
+        List<Point> sampled = dynamic_programming(points, m - 1, ERROR.area, 
false);
+        long endTime = System.currentTimeMillis();
+        System.out.println("Time taken: " + (endTime - startTime) + "ms");
+
+        for (Point p : sampled) {
+            System.out.println(p);
+        }
+        System.out.println(sampled.size());
+
+//        try (PrintWriter writer = new PrintWriter(new File("output.csv"))) {
+//            // 写入字符串
+//            for (int i = 0; i < sampled.size(); i++) {
+//                writer.println(sampled.get(i).x + "," + sampled.get(i).y);
+//            }
+//
+//        } catch (FileNotFoundException e) {
+//            e.printStackTrace();
+//        }
+    }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/query/eBUG/Tool.java 
b/server/src/main/java/org/apache/iotdb/db/query/eBUG/Tool.java
index a61f091198a..9a54f835ec3 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/eBUG/Tool.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/eBUG/Tool.java
@@ -11,363 +11,407 @@ import java.util.List;
 import java.util.stream.Stream;
 
 public class Tool {
-  // Assumed interface for the simplification function
-  interface SimplifyFunction {
-    List<Point> reducePoints(List<Point> points, double epsilon, Object... 
kwargs)
-        throws IOException;
-  }
-
-  // Method to generate the output file name based on input path
-  public static String generateOutputFileName(
-      String inputFilePath, String outDir, String customize) {
-    // Get the file name without extension
-    Path path = Paths.get(inputFilePath);
-    String fileNameWithoutExtension = path.getFileName().toString();
-    String name = fileNameWithoutExtension.substring(0, 
fileNameWithoutExtension.lastIndexOf('.'));
-
-    // Get the file extension
-    String extension =
-        
path.getFileName().toString().substring(fileNameWithoutExtension.lastIndexOf('.'));
-
-    // Create output file path by appending '-ds' before the extension
-    //        String outputFile = name + "-ds-e" + e + extension;
-    String outputFile = name + customize + extension;
-
-    if (outDir == null) { // 表示使用input文件所在的文件夹
-      // Handle path compatibility for different operating systems 
(Linux/Windows)
-      return path.getParent().resolve(outputFile).toString();
-    } else {
-      Path out = Paths.get(outDir);
-      return out.resolve(outputFile).toString();
-    }
-  }
-
-  public static double getParam(
-      List<Point> points,
-      int m,
-      SimplifyFunction simplifyFunc,
-      double tolerantPts,
-      Object... kwargs)
-      throws IOException {
-    //        double x = 1; 不要从1开始,因为对于swab来说使用如此小的maxError会很慢,宁可让maxError从大到小
-    double x = 10;
-    boolean directLess = false;
-    boolean directMore = false;
-
-    int iterNum = 0;
-    int maxIterNum = 50;
-
-    // First binary search loop to find the initial range
-    double base = 2;
-    while (true) {
-      //      System.out.println("x=" + x);
-      iterNum++;
-      if (iterNum > maxIterNum) {
-        //                System.out.println("reach maxIterNum1");
-        break; // Avoid infinite loops for special cases
-      }
-      List<Point> res = simplifyFunc.reducePoints(points, x, kwargs);
-      int length = res.size();
-      //      System.out.println(length);
-
-      if (Math.abs(length - m) <= tolerantPts) {
-        return x; // Return the found parameter
-      }
-
-      if (length > m) {
-        if (directMore) {
-          break; // Reach the first more
-        }
-        if (!directLess) {
-          directLess = true;
+
+    public static void printArray(double[][] array) {
+        // 遍历每一行
+        for (double[] row : array) {
+            for (double value : row) {
+                // 格式化输出:%10.2f 表示右对齐,占10个字符,保留2位小数
+                System.out.printf("%10.2f ", value);
+            }
+            System.out.println(); // 换行
         }
+    }
 
-        x *= base; // Need less points, increase x
-      } else {
-        if (directLess) {
-          break; // Reach the first less
+    public static void printTransposeArray(double[][] array) {
+        // 遍历每一列
+        for (int i = 0; i < array[0].length; i++) {
+            for (int j = 0; j < array.length; j++) {
+                // 格式化输出:%10.2f 表示右对齐,占10个字符,保留2位小数
+                System.out.printf("%10.2f ", array[j][i]);
+            }
+            System.out.println(); // 换行
         }
-        if (!directMore) {
-          directMore = true;
+    }
+
+    public static void printArray(int[][] array) {
+        // 遍历每一行
+        for (int[] row : array) {
+            for (int value : row) {
+                System.out.printf("%10d ", value);
+            }
+            System.out.println(); // 换行
         }
+    }
 
-        x /= base; // Need more points, decrease x
-      }
+    public static void printTransposeArray(int[][] array) {
+        // 遍历每一列
+        for (int i = 0; i < array[0].length; i++) {
+            for (int j = 0; j < array.length; j++) {
+                // 格式化输出:%10.2f 表示右对齐,占10个字符,保留2位小数
+                System.out.printf("%10d ", array[j][i]);
+            }
+            System.out.println(); // 换行
+        }
     }
 
-    // Determine the initial left and right bounds
-    double left = (directLess) ? x / base : x;
-    double right = (directMore) ? x * base : x;
-
-    // Refine the range with binary search
-    iterNum = 0;
-    while (true) {
-      iterNum++;
-      if (iterNum > maxIterNum) {
-        //                System.out.println("reach maxIterNum");
-        break; // Avoid infinite loops
-      }
-
-      double mid = (left + right) / 2;
-
-      List<Point> res = simplifyFunc.reducePoints(points, mid, kwargs);
-      int length = res.size();
-      //      System.out.println(length);
-
-      if (Math.abs(length - m) <= tolerantPts) {
-        return mid; // Return the refined parameter
-      }
-
-      if (length > m) {
-        left = mid; // Need less, narrow range to the left
-      } else {
-        right = mid; // Need more, narrow range to the right
-      }
-      //      System.out.println(left + "," + right);
+    // Assumed interface for the simplification function
+    interface SimplifyFunction {
+        List<Point> reducePoints(List<Point> points, double epsilon, Object... 
kwargs)
+                throws IOException;
     }
 
-    return (left + right) / 2; // Return the average of left and right as the 
final parameter
-  }
-
-  public static List<Point> readFromFile(
-      String input, boolean hasHeader, int timeIdx, int valueIdx, int N) {
-    List<Point> res = new ArrayList<>();
-
-    // Using Files.lines() for memory-efficient line-by-line reading
-    try (Stream<String> lines = Files.lines(Paths.get(input))) {
-      Iterator<String> iterator = lines.iterator();
-      int lineNumber = 0;
-
-      // Skip the header line if necessary
-      if (hasHeader && iterator.hasNext()) {
-        iterator.next(); // Skip the header
-      }
-
-      // Process each line
-      while (iterator.hasNext()) {
-        lineNumber++;
-        String line = iterator.next();
-        String[] columns = line.split(",");
-
-        if (columns.length > Math.max(timeIdx, valueIdx)) {
-          double time;
-          if (timeIdx < 0) {
-            time = lineNumber;
-          } else {
-            time = Double.parseDouble(columns[timeIdx]);
-          }
-          double value = Double.parseDouble(columns[valueIdx]);
-          res.add(new Point(time, value));
-          //                    System.out.println("Line " + lineNumber + " - 
Time: " + time + ",
-          // Value: " + value);
+    // Method to generate the output file name based on input path
+    public static String generateOutputFileName(
+            String inputFilePath, String outDir, String customize) {
+        // Get the file name without extension
+        Path path = Paths.get(inputFilePath);
+        String fileNameWithoutExtension = path.getFileName().toString();
+        String name = fileNameWithoutExtension.substring(0, 
fileNameWithoutExtension.lastIndexOf('.'));
+
+        // Get the file extension
+        String extension =
+                
path.getFileName().toString().substring(fileNameWithoutExtension.lastIndexOf('.'));
+
+        // Create output file path by appending '-ds' before the extension
+        //        String outputFile = name + "-ds-e" + e + extension;
+        String outputFile = name + customize + extension;
+
+        if (outDir == null) { // 表示使用input文件所在的文件夹
+            // Handle path compatibility for different operating systems 
(Linux/Windows)
+            return path.getParent().resolve(outputFile).toString();
         } else {
-          System.out.println("Line " + lineNumber + " is malformed (not enough 
columns).");
+            Path out = Paths.get(outDir);
+            return out.resolve(outputFile).toString();
+        }
+    }
+
+    public static double getParam(
+            List<Point> points,
+            int m,
+            SimplifyFunction simplifyFunc,
+            double tolerantPts,
+            Object... kwargs)
+            throws IOException {
+        //        double x = 1; 
不要从1开始,因为对于swab来说使用如此小的maxError会很慢,宁可让maxError从大到小
+        double x = 10;
+        boolean directLess = false;
+        boolean directMore = false;
+
+        int iterNum = 0;
+        int maxIterNum = 50;
+
+        // First binary search loop to find the initial range
+        double base = 2;
+        while (true) {
+            //      System.out.println("x=" + x);
+            iterNum++;
+            if (iterNum > maxIterNum) {
+                //                System.out.println("reach maxIterNum1");
+                break; // Avoid infinite loops for special cases
+            }
+            List<Point> res = simplifyFunc.reducePoints(points, x, kwargs);
+            int length = res.size();
+            //      System.out.println(length);
+
+            if (Math.abs(length - m) <= tolerantPts) {
+                return x; // Return the found parameter
+            }
+
+            if (length > m) {
+                if (directMore) {
+                    break; // Reach the first more
+                }
+                if (!directLess) {
+                    directLess = true;
+                }
+
+                x *= base; // Need less points, increase x
+            } else {
+                if (directLess) {
+                    break; // Reach the first less
+                }
+                if (!directMore) {
+                    directMore = true;
+                }
+
+                x /= base; // Need more points, decrease x
+            }
         }
-        if (N > 0 && lineNumber >= N) {
-          // N>0控制点数,否则N<=0表示读全部数据
-          break;
+
+        // Determine the initial left and right bounds
+        double left = (directLess) ? x / base : x;
+        double right = (directMore) ? x * base : x;
+
+        // Refine the range with binary search
+        iterNum = 0;
+        while (true) {
+            iterNum++;
+            if (iterNum > maxIterNum) {
+                //                System.out.println("reach maxIterNum");
+                break; // Avoid infinite loops
+            }
+
+            double mid = (left + right) / 2;
+
+            List<Point> res = simplifyFunc.reducePoints(points, mid, kwargs);
+            int length = res.size();
+            //      System.out.println(length);
+
+            if (Math.abs(length - m) <= tolerantPts) {
+                return mid; // Return the refined parameter
+            }
+
+            if (length > m) {
+                left = mid; // Need less, narrow range to the left
+            } else {
+                right = mid; // Need more, narrow range to the right
+            }
+            //      System.out.println(left + "," + right);
         }
-      }
-    } catch (IOException e) {
-      e.printStackTrace();
+
+        return (left + right) / 2; // Return the average of left and right as 
the final parameter
     }
-    return res;
-  }
-
-  // 计算三角形面积
-  public static double triArea(Point d0, Point d1, Point d2) {
-    double dArea = ((d1.x - d0.x) * (d2.y - d0.y) - (d2.x - d0.x) * (d1.y - 
d0.y)) / 2.0;
-    return (dArea > 0.0) ? dArea : -dArea; // abs
-  }
-
-  // 计算简单多边形(边不交叉)的面积(鞋带公式)
-  public static double calculatePolygonArea(List<Point> points) {
-    // points多边形顶点,要求按照逆时针或者顺时针的顺序枚举,否则鞋带公式无法给出正确结果
-    int n = points.size();
-    double area = 0;
-    for (int i = 0; i < n; i++) {
-      int next = (i + 1) % n;
-      area += points.get(i).x * points.get(next).y - points.get(next).x * 
points.get(i).y;
+
+    public static List<Point> readFromFile(
+            String input, boolean hasHeader, int timeIdx, int valueIdx, int N) 
{
+        List<Point> res = new ArrayList<>();
+
+        // Using Files.lines() for memory-efficient line-by-line reading
+        try (Stream<String> lines = Files.lines(Paths.get(input))) {
+            Iterator<String> iterator = lines.iterator();
+            int lineNumber = 0;
+
+            // Skip the header line if necessary
+            if (hasHeader && iterator.hasNext()) {
+                iterator.next(); // Skip the header
+            }
+
+            // Process each line
+            while (iterator.hasNext()) {
+                lineNumber++;
+                String line = iterator.next();
+                String[] columns = line.split(",");
+
+                if (columns.length > Math.max(timeIdx, valueIdx)) {
+                    double time;
+                    if (timeIdx < 0) {
+                        time = lineNumber;
+                    } else {
+                        time = Double.parseDouble(columns[timeIdx]);
+                    }
+                    double value = Double.parseDouble(columns[valueIdx]);
+                    res.add(new Point(time, value));
+                    //                    System.out.println("Line " + 
lineNumber + " - Time: " + time + ",
+                    // Value: " + value);
+                } else {
+                    System.out.println("Line " + lineNumber + " is malformed 
(not enough columns).");
+                }
+                if (N > 0 && lineNumber >= N) {
+                    // N>0控制点数,否则N<=0表示读全部数据
+                    break;
+                }
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return res;
     }
-    return Math.abs(area) / 2.0;
-  }
-
-  // 计算两个向量的叉积
-  public static double crossProduct(double x1, double y1, double x2, double 
y2) {
-    //  >0: (x2,y2)在(x1,y1)的逆时针方向
-    //  <0: (x2,y2)在(x1,y1)的顺时针方向
-    //  =0: 平行或共线
-    return x1 * y2 - y1 * x2;
-  }
-
-  // 判断两条线段是否相交并计算交点
-  // L1包含一个线段的两个端点,L2包含另一个线段的两个端点
-  public static Object[] lineIntersection(Point[] L1, Point[] L2) {
-    double x1 = L1[0].x, y1 = L1[0].y, x2 = L1[1].x, y2 = L1[1].y;
-    double x3 = L2[0].x, y3 = L2[0].y, x4 = L2[1].x, y4 = L2[1].y;
-
-    // 判断是否相交(叉积)
-    double d1 = crossProduct(x2 - x1, y2 - y1, x3 - x1, y3 - y1);
-    double d2 = crossProduct(x2 - x1, y2 - y1, x4 - x1, y4 - y1);
-    double d3 = crossProduct(x4 - x3, y4 - y3, x1 - x3, y1 - y3);
-    double d4 = crossProduct(x4 - x3, y4 - y3, x2 - x3, y2 - y3);
-
-    // 如果叉积条件满足,表示有交点
-    // d1*d2<0意味着P3、P4分别在L12的两边
-    // d3*d4<0意味着P1、P2分别在L34的两边
-    // 两个同时满足说明有交点
-    if (d1 * d2 < 0 && d3 * d4 < 0) {
-      double denominator = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1); // 
不可能为0(平行或共线),因为已经判断相交了
-      double t1 = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / 
denominator;
-      double x = x1 + t1 * (x2 - x1);
-      double y = y1 + t1 * (y2 - y1);
-      return new Object[] {true, new Point(x, y)};
+
+    // 计算三角形面积
+    public static double triArea(Point d0, Point d1, Point d2) {
+        double dArea = ((d1.x - d0.x) * (d2.y - d0.y) - (d2.x - d0.x) * (d1.y 
- d0.y)) / 2.0;
+        return (dArea > 0.0) ? dArea : -dArea; // abs
     }
 
-    // 检查是否起点或终点重合
-    if ((x1 == x3 && y1 == y3) || (x1 == x4 && y1 == y4)) {
-      return new Object[] {true, new Point(x1, y1)};
+    // 计算简单多边形(边不交叉)的面积(鞋带公式)
+    public static double calculatePolygonArea(List<Point> points) {
+        // points多边形顶点,要求按照逆时针或者顺时针的顺序枚举,否则鞋带公式无法给出正确结果
+        int n = points.size();
+        double area = 0;
+        for (int i = 0; i < n; i++) {
+            int next = (i + 1) % n;
+            area += points.get(i).x * points.get(next).y - points.get(next).x 
* points.get(i).y;
+        }
+        return Math.abs(area) / 2.0;
     }
-    if ((x2 == x3 && y2 == y3) || (x2 == x4 && y2 == y4)) {
-      return new Object[] {true, new Point(x2, y2)};
+
+    // 计算两个向量的叉积
+    public static double crossProduct(double x1, double y1, double x2, double 
y2) {
+        //  >0: (x2,y2)在(x1,y1)的逆时针方向
+        //  <0: (x2,y2)在(x1,y1)的顺时针方向
+        //  =0: 平行或共线
+        return x1 * y2 - y1 * x2;
     }
 
-    return new Object[] {false, null};
-  }
-
-  // 计算总的多边形面积(通过时间序列扫描交点),默认要求点按照时间戳严格递增排列
-  public static double total_areal_displacement(
-      List<Point> points, List<Point> points2, boolean debug) {
-    double totalArea = 0;
-    int i = 0, j = 0; // i for points, j for points2
-    Point prevIntersection = null;
-    int prevI = -1, prevJ = -1;
-
-    //        List<double[]> intersectionCoords = new ArrayList<>();
-    List<Double> areaList = new ArrayList<>();
-
-    while (i < points.size() - 1 && j < points2.size() - 1) {
-      if (debug) {
-        System.out.println("--------- " + i + " " + j + " ------------");
-      }
-
-      // 当前线段
-      Point[] L1 = {points.get(i), points.get(i + 1)};
-      Point[] L2 = {points2.get(j), points2.get(j + 1)};
-
-      // 判断是否有交点
-      Object[] result = lineIntersection(L1, L2);
-      boolean isIntersect = (boolean) result[0];
-      Point intersection = (Point) result[1];
-
-      if (isIntersect) {
-        //                intersectionCoords.add(intersection);
-
-        if (prevIntersection != null) {
-          // 构造多边形点集
-          List<Point> polygon = new ArrayList<>(); // 按照顺时针/逆时针几何连接顺序枚举多边形的顶点
-          polygon.add(prevIntersection);
-          if (debug) {
-            System.out.println("- start intersection: " + prevIntersection);
-          }
-          polygon.addAll(points.subList(prevI, i + 1)); // 添加当前线段的点,左闭右开
-          //                    
polygon.addAll(Arrays.asList(Arrays.copyOfRange(points, prevI, i +
-          // 1)));  // 添加当前线段的点,左闭右开
-          if (debug) {
-            System.out.println("- one side: " + points.subList(prevI, i + 1));
-          }
-          polygon.add(intersection);
-          if (debug) {
-            System.out.println("- end intersection: " + intersection);
-          }
-          List<Point> tempPoints2 = points2.subList(prevJ, j + 1);
-          Collections.reverse(tempPoints2); // 添加另一序列的点
-          polygon.addAll(tempPoints2);
-          if (debug) {
-            System.out.println("- another side: " + tempPoints2);
-          }
-
-          //                    double[][] polygonArray = new 
double[polygon.size()][2];
-          //                    for (int k = 0; k < polygon.size(); k++) {
-          //                        polygonArray[k] = polygon.get(k);
-          //                    }
-
-          // 计算多边形面积,注意polygon里的点一定是按照顺时针/逆时针几何连接顺序枚举的多边形顶点
-          double area = calculatePolygonArea(polygon);
-          if (debug) {
-            System.out.println("Area = " + area);
-          }
-          totalArea += area;
-          areaList.add(area);
+    // 判断两条线段是否相交并计算交点
+    // L1包含一个线段的两个端点,L2包含另一个线段的两个端点
+    public static Object[] lineIntersection(Point[] L1, Point[] L2) {
+        double x1 = L1[0].x, y1 = L1[0].y, x2 = L1[1].x, y2 = L1[1].y;
+        double x3 = L2[0].x, y3 = L2[0].y, x4 = L2[1].x, y4 = L2[1].y;
+
+        // 判断是否相交(叉积)
+        double d1 = crossProduct(x2 - x1, y2 - y1, x3 - x1, y3 - y1);
+        double d2 = crossProduct(x2 - x1, y2 - y1, x4 - x1, y4 - y1);
+        double d3 = crossProduct(x4 - x3, y4 - y3, x1 - x3, y1 - y3);
+        double d4 = crossProduct(x4 - x3, y4 - y3, x2 - x3, y2 - y3);
+
+        // 如果叉积条件满足,表示有交点
+        // d1*d2<0意味着P3、P4分别在L12的两边
+        // d3*d4<0意味着P1、P2分别在L34的两边
+        // 两个同时满足说明有交点
+        if (d1 * d2 < 0 && d3 * d4 < 0) {
+            double denominator = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - 
y1); // 不可能为0(平行或共线),因为已经判断相交了
+            double t1 = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / 
denominator;
+            double x = x1 + t1 * (x2 - x1);
+            double y = y1 + t1 * (y2 - y1);
+            return new Object[]{true, new Point(x, y)};
         }
 
-        prevIntersection = intersection;
-        prevI = i + 1;
-        prevJ = j + 1;
+        // 检查是否起点或终点重合
+        if ((x1 == x3 && y1 == y3) || (x1 == x4 && y1 == y4)) {
+            return new Object[]{true, new Point(x1, y1)};
+        }
+        if ((x2 == x3 && y2 == y3) || (x2 == x4 && y2 == y4)) {
+            return new Object[]{true, new Point(x2, y2)};
+        }
+
+        return new Object[]{false, null};
+    }
+
+    // 计算总的多边形面积(通过时间序列扫描交点),默认要求点按照时间戳严格递增排列
+    public static double total_areal_displacement(
+            List<Point> points, List<Point> points2, boolean debug) {
+        double totalArea = 0;
+        int i = 0, j = 0; // i for points, j for points2
+        Point prevIntersection = null;
+        int prevI = -1, prevJ = -1;
+
+        //        List<double[]> intersectionCoords = new ArrayList<>();
+        List<Double> areaList = new ArrayList<>();
+
+        while (i < points.size() - 1 && j < points2.size() - 1) {
+            if (debug) {
+                System.out.println("--------- " + i + " " + j + " 
------------");
+            }
+
+            // 当前线段
+            Point[] L1 = {points.get(i), points.get(i + 1)};
+            Point[] L2 = {points2.get(j), points2.get(j + 1)};
+
+            // 判断是否有交点
+            Object[] result = lineIntersection(L1, L2);
+            boolean isIntersect = (boolean) result[0];
+            Point intersection = (Point) result[1];
+
+            if (isIntersect) {
+                //                intersectionCoords.add(intersection);
+
+                if (prevIntersection != null) {
+                    // 构造多边形点集
+                    List<Point> polygon = new ArrayList<>(); // 
按照顺时针/逆时针几何连接顺序枚举多边形的顶点
+                    polygon.add(prevIntersection);
+                    if (debug) {
+                        System.out.println("- start intersection: " + 
prevIntersection);
+                    }
+                    polygon.addAll(points.subList(prevI, i + 1)); // 
添加当前线段的点,左闭右开
+                    //                    
polygon.addAll(Arrays.asList(Arrays.copyOfRange(points, prevI, i +
+                    // 1)));  // 添加当前线段的点,左闭右开
+                    if (debug) {
+                        System.out.println("- one side: " + 
points.subList(prevI, i + 1));
+                    }
+                    polygon.add(intersection);
+                    if (debug) {
+                        System.out.println("- end intersection: " + 
intersection);
+                    }
+                    List<Point> tempPoints2 = points2.subList(prevJ, j + 1);
+                    Collections.reverse(tempPoints2); // 添加另一序列的点
+                    polygon.addAll(tempPoints2);
+                    if (debug) {
+                        System.out.println("- another side: " + tempPoints2);
+                    }
+
+                    //                    double[][] polygonArray = new 
double[polygon.size()][2];
+                    //                    for (int k = 0; k < polygon.size(); 
k++) {
+                    //                        polygonArray[k] = polygon.get(k);
+                    //                    }
+
+                    // 计算多边形面积,注意polygon里的点一定是按照顺时针/逆时针几何连接顺序枚举的多边形顶点
+                    double area = calculatePolygonArea(polygon);
+                    if (debug) {
+                        System.out.println("Area = " + area);
+                    }
+                    totalArea += area;
+                    areaList.add(area);
+                }
+
+                prevIntersection = intersection;
+                prevI = i + 1;
+                prevJ = j + 1;
+                if (debug) {
+                    System.out.println(
+                            "This intersection = "
+                                    + intersection
+                                    + ", next polygon: side1 = "
+                                    + prevI
+                                    + ", side2 = "
+                                    + prevJ);
+                }
+            }
+
+            int currentI = i; // 临时存储i
+            int currentJ = j; // 临时存储j
+            if (points.get(currentI + 1).x <= points2.get(currentJ + 1).x) {
+                i += 1; // 基于时间戳严格递增的假设,Line不会回头或者垂直
+            }
+            if (points.get(currentI + 1).x >= points2.get(currentJ + 1).x) {
+                j += 1; // 基于时间戳严格递增的假设,Line不会回头或者垂直
+            }
+        } // end of while
+
         if (debug) {
-          System.out.println(
-              "This intersection = "
-                  + intersection
-                  + ", next polygon: side1 = "
-                  + prevI
-                  + ", side2 = "
-                  + prevJ);
+            System.out.println(areaList);
         }
-      }
-
-      int currentI = i; // 临时存储i
-      int currentJ = j; // 临时存储j
-      if (points.get(currentI + 1).x <= points2.get(currentJ + 1).x) {
-        i += 1; // 基于时间戳严格递增的假设,Line不会回头或者垂直
-      }
-      if (points.get(currentI + 1).x >= points2.get(currentJ + 1).x) {
-        j += 1; // 基于时间戳严格递增的假设,Line不会回头或者垂直
-      }
-    } // end of while
-
-    if (debug) {
-      System.out.println(areaList);
+
+        return totalArea;
     }
 
-    return totalArea;
-  }
-
-  // 测试方法
-  public static void main(String[] args) {
-    // 示例数据
-    List<Point> points = new ArrayList<>();
-    points.add(new Point(0, 0));
-    points.add(new Point(1, 2));
-    points.add(new Point(2, -20));
-    points.add(new Point(3, 0));
-    points.add(new Point(4, -1));
-    points.add(new Point(5, -1.5));
-    points.add(new Point(6, 0));
-
-    List<Point> points2 = new ArrayList<>();
-    //        points2.add(points.get(0));
-    //        points2.add(points.get(3));
-    //        points2.add(points.get(6));
-    points2.add(new Point(1, -10));
-    points2.add(new Point(3, 0));
-
-    double area = total_areal_displacement(points, points2, true);
-    System.out.println("Total area: " + area);
-
-    //        points = new ArrayList<>();
-    //        points.add(new Point(0, 0));
-    //        points.add(new Point(1, 2));
-    //        points.add(new Point(1.5, -10));
-    //        double area = calculatePolygonArea(points);
-    //        System.out.println(area);
-    //
-    //        Point[] L1 = new Point[2];
-    //        L1[0] = new Point(1, 2);
-    //        L1[1] = new Point(2, -2);
-    //        Point[] L2 = new Point[2];
-    //        L2[0] = new Point(0, 0);
-    //        L2[1] = new Point(3, 0);
-    //        Object[] res = lineIntersection(L1, L2);
-    //        System.out.println(res[1]);
-  }
+    // 测试方法
+    public static void main(String[] args) {
+        // 示例数据
+        List<Point> points = new ArrayList<>();
+        points.add(new Point(0, 0));
+        points.add(new Point(1, 2));
+        points.add(new Point(2, -20));
+        points.add(new Point(3, 0));
+        points.add(new Point(4, -1));
+        points.add(new Point(5, -1.5));
+        points.add(new Point(6, 0));
+
+        List<Point> points2 = new ArrayList<>();
+        //        points2.add(points.get(0));
+        //        points2.add(points.get(3));
+        //        points2.add(points.get(6));
+        points2.add(new Point(1, -10));
+        points2.add(new Point(3, 0));
+
+        double area = total_areal_displacement(points, points2, true);
+        System.out.println("Total area: " + area);
+
+        //        points = new ArrayList<>();
+        //        points.add(new Point(0, 0));
+        //        points.add(new Point(1, 2));
+        //        points.add(new Point(1.5, -10));
+        //        double area = calculatePolygonArea(points);
+        //        System.out.println(area);
+        //
+        //        Point[] L1 = new Point[2];
+        //        L1[0] = new Point(1, 2);
+        //        L1[1] = new Point(2, -2);
+        //        Point[] L2 = new Point[2];
+        //        L2[0] = new Point(0, 0);
+        //        L2[1] = new Point(3, 0);
+        //        Object[] res = lineIntersection(L1, L2);
+        //        System.out.println(res[1]);
+    }
 }
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 8da7cca5175..44fc3298d96 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
@@ -76,16 +76,18 @@ public class eBUG {
       throw new IllegalArgumentException("Parameter e must be non-negative.");
     }
 
-    if (m > 2) {
-      System.out.println(
-          "online sampling mode, "
-              + "returning "
-              + m
-              + " sampled points sorted by time in ascending order");
-    } else {
-      System.out.println(
-          "offline precomputation mode, "
-              + "returning each point sorted by dominated significance (DS) in 
ascending order");
+    if (debug) {
+      if (m > 2) {
+        System.out.println(
+            "online sampling mode, "
+                + "returning "
+                + m
+                + " sampled points sorted by time in ascending order");
+      } else {
+        System.out.println(
+            "offline precomputation mode, "
+                + "returning each point sorted by dominated significance (DS) 
in ascending order");
+      }
     }
 
     //        List<Point> results = lineToSimplify.getVertices(); // 浅复制
@@ -177,14 +179,16 @@ public class eBUG {
       }
 
       // 更新当前点的重要性(z 轴存储effective area,这是一个单调增的指标)
-      if (tri.area > previousEA) {
-        previousEA = tri.area;
-      }
-      //            results.get(tri.indices[1]).z = previousEA; // dominated 
significance
-      points.get(tri.indices[1]).z = previousEA; // dominated significance
-      resultsBottomUpEliminated.add(points.get(tri.indices[1])); // TODO 
add的是Point引用,所以没有多用一倍的空间
-      if (debug) {
-        System.out.println(Arrays.toString(tri.indices) + ", Dominated Sig=" + 
previousEA);
+      if (m <= 2) { // precomputation mode
+        if (tri.area > previousEA) {
+          previousEA = tri.area;
+        }
+        //            results.get(tri.indices[1]).z = previousEA; // dominated 
significance
+        points.get(tri.indices[1]).z = previousEA; // dominated significance
+        resultsBottomUpEliminated.add(points.get(tri.indices[1])); // TODO 
add的是Point引用,所以没有多用一倍的空间
+        if (debug) {
+          System.out.println(Arrays.toString(tri.indices) + ", Dominated Sig=" 
+ previousEA);
+        }
       }
 
       // 更新相邻三角形
@@ -326,6 +330,8 @@ public class eBUG {
 
     if (m > 2) { // online sampling mode
       // 把滞后的淘汰点施加上去,然后返回在线采样结果(也就是返回剩余未被淘汰的点)
+      // 注意未淘汰的点的Dominated significance尚未赋值,还都是infinity
+      // 不过既然m>2在线采样模式,所以其实淘汰点的DS本身也没有记录
       for (Point p : laggedEliminatedPoints) {
         p.markEliminated();
         if (debug) {
@@ -337,7 +343,7 @@ public class eBUG {
       Point end = points.get(points.size() - 1);
       while (start
           != end) { // 
Point类里增加prev&next指针,这样T'_max{0,k-e}里点的连接关系就有了,这样从Pa开始沿着指针,遍历点数一定不超过e+3
-        onlineSampled.add(start); // 注意未淘汰的点的Dominated 
significance尚未赋值,还都是infinity
+        onlineSampled.add(start);
         start = start.next; // when e=0, only traversing three points pa pi pb
       }
       onlineSampled.add(end);


Reply via email to