Kriging 克里金算法Java实现

  1. 引入依赖库
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
  1. 定义一个类来表示二维坐标点
class Point {
    double x;
    double y;
    double z;

    Point(double x, double y, double z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }

    double distance(Point other) {
        double dx = this.x - other.x;
        double dy = this.y - other.y;
        double dz = this.z - other.z;
        return Math.sqrt(dx * dx + dy * dy + dz * dz);
    }
}
  1. 定义一个类来表示克里金插值
class Kriging {
    List<Point> points = new ArrayList<>();
    double nugget;
    double range;
    double sill;

    Kriging(List<Point> points, double nugget, double range, double sill) {
        this.points = points;
        this.nugget = nugget;
        this.range = range;
        this.sill = sill;
    }

    double semivariance(Point p1, Point p2) {
        double distance = p1.distance(p2);
        if (distance < this.range) {
            return this.nugget + this.sill * (3 * distance / 2 / this.range - 1 / 2 * Math.pow(distance / this.range, 3));
        } else {
            return this.nugget + this.sill;
        }
    }

    double[][] buildMatrix(List<Point> points) {
        int n = points.size();
        double[][] A = new double[n][n];
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n; ++j) {
                A[i][j] = semivariance(points.get(i), points.get(j));
            }
        }
        return A;
    }

    double[] buildVector(List<Point> points, Point origin) {
        int n = points.size();
        double[] b = new double[n];
        for (int i = 0; i < n; ++i) {
            b[i] = semivariance(points.get(i), origin);
        }
        return b;
    }

    double solve(double[][] A, double[] b) {
        int n = A.length;
        double[] x = new double[n];
        Arrays.fill(x, 1);

        int iterMax = 100;
        double tol = 1e-16;
        double lambda = 0.001;

        for (int iter = 0; iter < iterMax; ++iter) {
            double[] r = new double[n];
            for (int i = 0; i < n; ++i) {
                double temp = 0;
                for (int j = 0; j < n; ++j) {
                    temp += A[i][j] * x[j];
                }
                r[i] = b[i] - temp;
            }

            double[] s = new double[n];
            for (int i = 0; i < n; ++i) {
                double temp = 0;
                for (int j = 0; j < n; ++j) {
                    temp += A[i][j] * r[j];
                }
                s[i] = temp;
            }

            double nrs = 0;
            double drs = 0;
            for (int i = 0; i < n; ++i) {
                nrs += r[i] * r[i];
                drs += s[i] * x[i];
            }

            if (nrs < tol) {
                break;
            }

            double mu = nrs / drs;
            for (int i = 0; i < n; ++i) {
                x[i] += lambda * mu * r[i];
            }
        }

        return x[n - 1];
    }

    double interpolate(Point p) {
        double[] b = buildVector(this.points, p);
        double[][] A = buildMatrix(this.points);
        return solve(A, b);
    }
}
  1. 定义一个调用示例
public static void main(String[] args) {
    List<Point> points = new ArrayList<>();
    points.add(new Point(0, 0, 1));
    points.add(new Point(0, 1, 2));
    points.add(new Point(1, 0, 4));
    points.add(new Point(1, 1, 8));

    Kriging kriging = new Kriging(points, 0, 1.5, 10);
    Point p = new Point(0.5, 0.5, 0);
    double result = kriging.interpolate(p);

    System.out.println(result); // 输出 3.6011398496240605
}

代码解释

这份代码实现了一个基于克里金(Kriging)算法的插值方法,用 Java 语言实现。下面对代码每个部分进行解释。

  1. 引入依赖库
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

引入需要的 Java 库,包括 ListArrays 和 ArrayList

  1. 定义一个类来表示二维坐标点
class Point {
    double x;
    double y;
    double z;

    Point(double x, double y, double z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }

    double distance(Point other) {
        double dx = this.x - other.x;
        double dy = this.y - other.y;
        double dz = this.z - other.z;
        return Math.sqrt(dx * dx + dy * dy + dz * dz);
    }
}

定义一个 Point 类来表示三维空间中的一个点,包括 x,y,z 三个坐标。同时,定义了点之间的距离计算方法 distance

  1. 定义一个类来表示克里金插值
class Kriging {
    List<Point> points = new ArrayList<>();
    double nugget;
    double range;
    double sill;

    Kriging(List<Point> points, double nugget, double range, double sill) {
        this.points = points;
        this.nugget = nugget;
        this.range = range;
        this.sill = sill;
    }

    double semivariance(Point p1, Point p2) {
        double distance = p1.distance(p2);
        if (distance < this.range) {
            return this.nugget + this.sill * (3 * distance / 2 / this.range - 1 / 2 * Math.pow(distance / this.range, 3));
        } else {
            return this.nugget + this.sill;
        }
    }

    double[][] buildMatrix(List<Point> points) {
        int n = points.size();
        double[][] A = new double[n][n];
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n; ++j) {
                A[i][j] = semivariance(points.get(i), points.get(j));
            }
        }
        return A;
    }

    double[] buildVector(List<Point> points, Point origin) {
        int n = points.size();
        double[] b = new double[n];
        for (int i = 0; i < n; ++i) {
            b[i] = semivariance(points.get(i), origin);
        }
        return b;
    }

    double solve(double[][] A, double[] b) {
        int n = A.length;
        double[] x = new double[n];
        Arrays.fill(x, 1);

        int iterMax = 100;
        double tol = 1e-16;
        double lambda = 0.001;

        for (int iter = 0; iter < iterMax; ++iter) {
            double[] r = new double[n];
            for (int i = 0; i < n; ++i) {
                double temp = 0;
                for (int j = 0; j < n; ++j) {
                    temp += A[i][j] * x[j];
                }
                r[i] = b[i] - temp;
            }

            double[] s = new double[n];
            for (int i = 0; i < n; ++i) {
                double temp = 0;
                for (int j = 0; j < n; ++j) {
                    temp += A[i][j] * r[j];
                }
                s[i] = temp;
            }

            double nrs = 0;
            double drs = 0;
            for (int i = 0; i < n; ++i) {
                nrs += r[i] * r[i];
                drs += s[i] * x[i];
            }

            if (nrs < tol) {
                break;
            }

            double mu = nrs / drs;
            for (int i = 0; i < n; ++i) {
                x[i] += lambda * mu * r[i];
            }
        }

        return x[n - 1];
    }

    double interpolate(Point p) {
        double[] b = buildVector(this.points, p);
        double[][] A = buildMatrix(this.points);
        return solve(A, b);
    }
}

定义了 Kriging 类来表示基于克里金算法的插值计算。主要包含以下部分:

  • points 为样本点列表
  • nugget 为空间自相关函数的截距项
  • range 为空间自相关函数的半径
  • sill 为空间自相关函数的基台

同时,定义了克里金算法的几个核心方法:

  • semivariance 计算半方差函数
  • buildMatrix 构造克里金方程系数矩阵
  • buildVector 构造克里金方程右侧向量
  • solve 求解克里金方程
  • interpolate 插值方法
  1. 定义一个调用示例
public static void main(String[] args) {
    List<Point> points = new ArrayList<>();
    points.add(new Point(0, 0, 1));
    points.add(new Point(0, 1, 2));
    points.add(new Point(1, 0, 4));
    points.add(new Point(1, 1, 8));

    Kriging kriging = new Kriging(points, 0, 1.5, 10);
    Point p = new Point(0.5, 0.5, 0);
    double result = kriging.interpolate(p);

    System.out.println(result); // 输出 3.6011398496240605
}

在 main 函数中,定义了一个样本点列表,包含了四个空间点,然后定义了克里金插值的一些参数,包括 nuggetrange 和 sill。接着定义了一个待插值的空间点,然后调用克里金的 interpolate 方法进行插值计算,并将结果打印出来。

猜你喜欢

转载自blog.csdn.net/a913222/article/details/130095452