OpenNL 是一个用于求解大型稀疏线性系统的C开发库。 它包括一个易于使用的用于组装矩阵的 API,以及用于对称和非对称系统的各种迭代求解器。 OpenNL API 在 geogram/NL/nl.h 中声明。
NSDT工具推荐: Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编辑器 - REVIT导出3D模型插件 - 3D模型语义搜索引擎
让我们从一个简单的例子开始。 假设你要求解以下线性系统:
[ 1 2 ] [x] [5]
[ 3 4 ] [y] = [6]
首先,你需要声明将存储系统解的变量。 然后,我们创建一个 OpenNL 上下文,并声明变量的数量:
double x,y;
nlNewContext();
nlSolverParameteri(NL_NB_VARIABLES, 2);
现在我们可以构建线性系统了。 线性系统是逐行构建的。 OpenNL 有一个状态机,由 nlBegin()
、 nlEnd()
调用控制。看起来与 OpenGL 2.x 类似,但OpenNL构建稀疏矩阵而不是图形基元:
nlBegin(NL_SYSTEM);
nlBegin(NL_MATRIX);
nlBegin(NL_ROW);
nlCoefficient(0, 1.0);
nlCoefficient(1, 2.0);
nlRightHandSide(5.0);
nlEnd(NL_ROW);
nlBegin(NL_ROW);
nlCoefficient(0, 3.0);
nlCoefficient(1, 4.0);
nlRightHandSide(6.0);
nlEnd(NL_ROW);
nlEnd(NL_MATRIX);
nlEnd(NL_SYSTEM);
接下来我们对系统进行求解:
nlSolve();
x = nlGetVariable(0);
y = nlGetVariable(1);
最后,我们删除 OpenNL 上下文:
nlDeleteContext(nlGetCurrent());
OpenNL 有一个特殊的最小二乘模式,可以组装正规方程(最小二乘)。 假设你有一个文件,其中每条线上都包含 X,Y 点坐标,并且想要找到最适合数据点的线方程 y=ax+b
。 和之前一样,我们创建一个 OpenNL 上下文并声明变量的数量。 此外,我们激活最小二乘模式:
nlNewContext();
nlSolverParameteri(NL_LEAST_SQUARES, NL_TRUE);
nlSolverParameteri(NL_NB_VARIABLES, 2);
然后,我们读取文件并根据文件数据组装矩阵:
FILE* input = fopen("datapoints.dat", "r");
double X,Y; // current datapoint
nlBegin(NL_SYSTEM);
nlBegin(NL_MATRIX);
while(!feof(input)) {
fread(input, "%f %f", &X, &Y);
nlBegin(NL_ROW);
nlCoefficient(0, X);
nlCoefficient(1, 1.0);
nlRightHandSide(Y);
nlEnd(NL_ROW);
}
nlEnd(NL_MATRIX);
nlEnd(NL_SYSTEM);
就像前面的例子一样,我们现在可以求解系统:
nlSolve();
a = nlGetVariable(0);
b = nlGetVariable(1);
并且不要忘记关闭输入文件并删除 OpenNL 上下文:
fclose(input);
nlDeleteContext(nlGetCurrent());
如前面的示例所示,我们假设有一个文件,其中每条线上都包含 X,Y 点坐标,并且我们仍然希望找到最适合数据点的线方程 y=ax+b
,但这一次我们有附加约束:直线的斜率 a 应等于 1。OpenNL 上下文的初始化与之前一样:
FILE* input = fopen("datapoints.dat", "r");
double X,Y;
nlNewContext();
nlSolverParameteri(NL_LEAST_SQUARES, NL_TRUE);
nlSolverParameteri(NL_NB_VARIABLES, 2);
当我们构建系统时,我们锁定变量 0(对应于 a)并设置其值(1.0),如下所示:
nlBegin(NL_SYSTEM);
nlLockVariable(0);
nlSetVariable(0, 1.0);
nlBegin(NL_MATRIX);
while(!feof(input)) {
fread(input, "%f %f", &X, &Y);
nlBegin(NL_ROW);
nlCoefficient(0, X);
nlCoefficient(1, 1.0);
nlRightHandSide(Y);
nlEnd(NL_ROW);
}
nlEnd(NL_MATRIX);
nlEnd(NL_SYSTEM);
然后剩下的就和以前一样了:
nlSolve();
a = nlGetVariable(0);
b = nlGetVariable(1);
fclose(input);
nlDeleteContext(nlGetCurrent());
原文链接:用OpenNL求解线性系统 - BimAnt