求解 Javascript 中的非平方线性方程组
Solving non-square system of linear equations in Javascript
我有一个电阻系统,像这样:
Resistor schematic
我制作了一个网站,可以呈现这样的图表(不完全是这个)。用户可以改变每个电阻的阻值。我想计算系统中的每一个电流。
我找到了一个使用基尔霍夫定律的解,它给了我一个线性方程组。我使用逆矩阵用 math.js 解决了它。这种方法在较小的电路上效果很好。
在这个电路中,我的方程比变量多,这意味着我无法计算逆矩阵来求解它们。手动简化它们,以匹配未知数的数量是一种选择,但这需要人工。网站应该可以自己计算一切。
现在我正在寻找一种方法来求解不能表示为方阵的线性方程组。有什么建议吗?
谢谢!
编辑:
我目前的做法是这样的。
let R1 = 3;
let R2 = 10;
let R3 = 3;
let R4 = 2;
let R5 = 4;
let R6 = 4;
let V1 = 5;
let I1 = 0;
let I2 = 0;
let I3 = 0;
let I4 = 0;
let I5 = 0;
let I6 = 0;
const matrix = [
[-1, 1, 1, 0, 0, 0],
[1, -1, 0, 0, 0, -1],
[0, 0, -1, 1, 1, 0],
[0, -R2, 0, 0, 0, 0],
[0, 0, 0, -R6, -R5, 0],
[0, 0, -R1, -R6, 0, -(R3 + R4)]
];
const result = [0, 0, 0, -V1, 0, -V1];
const inverse = math.inv(matrix);
const currents = math.multiply(inverse, result);
console.log(currents);
[I1, I2, I3, I4, I5, I6] = currents;
<script src="https://cdn.jsdelivr.net/npm/mathjs@9.4.4/lib/browser/math.min.js"></script>
问题是在这个例子中,我得到了错误的解决方案。我将其缩小到缺少条件(方程式)。
我有 6 个电流,这意味着我只能有 6 个方程来计算逆矩阵...但是在这种情况下以及我拥有的许多其他情况下,6 个方程是不够的。
问题是我需要一台电脑来理解它。不是人类。所以,我需要找到一种方法来解决此类 6 个变量的问题,但方程式要多于 6 个。
- 这种方法减少了矩阵的行,结果给出了一个具有未知值的字符串。如果系统具有无限分辨率,这将 returns 简化方程式,以便您稍后可以进行参数化。
EDIT :独立项在数组的最后一列。
let eq = [
[1, 0, 1],
[1, -2, 0],
[0, 2, 1]
];
console.log(rowReduction());
function rowReduction() {
for (let columnIndex = 0; columnIndex < eq[0].length; columnIndex++) {
if (columnIndex < eq.length) {
let rowCheck = 0;
while (isEqual(eq[columnIndex][columnIndex], 0) && rowCheck < eq.length) {
if (rowCheck !== columnIndex) {
eq[columnIndex] = eq[rowCheck].map((e, i) => eq[columnIndex][i] + e);
}
rowCheck++;
}
}
}
for (let columnIndex = 0; columnIndex < eq[0].length; columnIndex++) {
if (columnIndex < eq.length) {
let diagElement = eq[columnIndex][columnIndex];
if (nonEqual(diagElement, 0)) {
eq[columnIndex] = eq[columnIndex].map((e, i) => e / diagElement);
}
for (let rowIndex = 0; rowIndex < eq.length; rowIndex++) {
if (rowIndex !== columnIndex && nonEqual(eq[rowIndex][columnIndex], 0)) {
const opuesto = -eq[rowIndex][columnIndex];
eq[rowIndex] = eq[columnIndex].map((e, i) => eq[rowIndex][i] + opuesto * e);
}
}
}
}
let compatible = true;
for (let f = 0; f < eq.length; f++) {
let nulo = true;
for (let c = 0; c < eq[f].length - 1; c++) {
if (nonEqual(eq[f][c], 0)) nulo = false;
}
if (nulo && nonEqual(eq[f][eq[f].length - 1], 0)) compatible = false;
}
return compatible ? evaluateEq() : "Incompatible system";
function evaluateEq() {
let str = "";
eq.forEach(function a(row, i) {
//avoid null rows
if (nonEqual(row.reduce((l, n) => l + Math.abs(n), 0), 0)) {
row.forEach(function b(e, j) {
e = e.toFixed(3); //decimals after comma
if (j + 1 === row.length) { //independent term
str += " = " + e;
} else if (nonEqual(e, 0)) {
str += " + ";
if (nonEqual(e, 1)) str += "(" + e + ")*";
str += "x[" + j + "]";
}
});
str += "\n";
}
});
return str;
}
//to avoid problems due to margin error
function isEqual(n, target) {
return parseFloat(n).toFixed(8) == target;
}
function nonEqual(n, target) {
return parseFloat(n).toFixed(8) != target;
}
}
经过反复试验,我发现 ml-matrix 中的 solve
函数允许包含 N 个变量的 N 个以上的方程。
我也尝试过使用伪逆的方法,但这也要求矩阵是方阵。
如果方程和未知数的数量相等,您可以使用 LU 分解求解矩阵。
如果方程的数量多于未知数的数量,则使用最小二乘法。
如果方程的数量少于未知数的数量,则使用奇异值分解。
Here 是如何使用 R 完成的示例。我确信 Python、JAMA 和其他库都有 SVD 求解器。我不知道 Javascript。
我有一个电阻系统,像这样: Resistor schematic
我制作了一个网站,可以呈现这样的图表(不完全是这个)。用户可以改变每个电阻的阻值。我想计算系统中的每一个电流。
我找到了一个使用基尔霍夫定律的解,它给了我一个线性方程组。我使用逆矩阵用 math.js 解决了它。这种方法在较小的电路上效果很好。
在这个电路中,我的方程比变量多,这意味着我无法计算逆矩阵来求解它们。手动简化它们,以匹配未知数的数量是一种选择,但这需要人工。网站应该可以自己计算一切。
现在我正在寻找一种方法来求解不能表示为方阵的线性方程组。有什么建议吗?
谢谢!
编辑:
我目前的做法是这样的。
let R1 = 3;
let R2 = 10;
let R3 = 3;
let R4 = 2;
let R5 = 4;
let R6 = 4;
let V1 = 5;
let I1 = 0;
let I2 = 0;
let I3 = 0;
let I4 = 0;
let I5 = 0;
let I6 = 0;
const matrix = [
[-1, 1, 1, 0, 0, 0],
[1, -1, 0, 0, 0, -1],
[0, 0, -1, 1, 1, 0],
[0, -R2, 0, 0, 0, 0],
[0, 0, 0, -R6, -R5, 0],
[0, 0, -R1, -R6, 0, -(R3 + R4)]
];
const result = [0, 0, 0, -V1, 0, -V1];
const inverse = math.inv(matrix);
const currents = math.multiply(inverse, result);
console.log(currents);
[I1, I2, I3, I4, I5, I6] = currents;
<script src="https://cdn.jsdelivr.net/npm/mathjs@9.4.4/lib/browser/math.min.js"></script>
问题是在这个例子中,我得到了错误的解决方案。我将其缩小到缺少条件(方程式)。
我有 6 个电流,这意味着我只能有 6 个方程来计算逆矩阵...但是在这种情况下以及我拥有的许多其他情况下,6 个方程是不够的。
问题是我需要一台电脑来理解它。不是人类。所以,我需要找到一种方法来解决此类 6 个变量的问题,但方程式要多于 6 个。
- 这种方法减少了矩阵的行,结果给出了一个具有未知值的字符串。如果系统具有无限分辨率,这将 returns 简化方程式,以便您稍后可以进行参数化。
EDIT :独立项在数组的最后一列。
let eq = [
[1, 0, 1],
[1, -2, 0],
[0, 2, 1]
];
console.log(rowReduction());
function rowReduction() {
for (let columnIndex = 0; columnIndex < eq[0].length; columnIndex++) {
if (columnIndex < eq.length) {
let rowCheck = 0;
while (isEqual(eq[columnIndex][columnIndex], 0) && rowCheck < eq.length) {
if (rowCheck !== columnIndex) {
eq[columnIndex] = eq[rowCheck].map((e, i) => eq[columnIndex][i] + e);
}
rowCheck++;
}
}
}
for (let columnIndex = 0; columnIndex < eq[0].length; columnIndex++) {
if (columnIndex < eq.length) {
let diagElement = eq[columnIndex][columnIndex];
if (nonEqual(diagElement, 0)) {
eq[columnIndex] = eq[columnIndex].map((e, i) => e / diagElement);
}
for (let rowIndex = 0; rowIndex < eq.length; rowIndex++) {
if (rowIndex !== columnIndex && nonEqual(eq[rowIndex][columnIndex], 0)) {
const opuesto = -eq[rowIndex][columnIndex];
eq[rowIndex] = eq[columnIndex].map((e, i) => eq[rowIndex][i] + opuesto * e);
}
}
}
}
let compatible = true;
for (let f = 0; f < eq.length; f++) {
let nulo = true;
for (let c = 0; c < eq[f].length - 1; c++) {
if (nonEqual(eq[f][c], 0)) nulo = false;
}
if (nulo && nonEqual(eq[f][eq[f].length - 1], 0)) compatible = false;
}
return compatible ? evaluateEq() : "Incompatible system";
function evaluateEq() {
let str = "";
eq.forEach(function a(row, i) {
//avoid null rows
if (nonEqual(row.reduce((l, n) => l + Math.abs(n), 0), 0)) {
row.forEach(function b(e, j) {
e = e.toFixed(3); //decimals after comma
if (j + 1 === row.length) { //independent term
str += " = " + e;
} else if (nonEqual(e, 0)) {
str += " + ";
if (nonEqual(e, 1)) str += "(" + e + ")*";
str += "x[" + j + "]";
}
});
str += "\n";
}
});
return str;
}
//to avoid problems due to margin error
function isEqual(n, target) {
return parseFloat(n).toFixed(8) == target;
}
function nonEqual(n, target) {
return parseFloat(n).toFixed(8) != target;
}
}
经过反复试验,我发现 ml-matrix 中的 solve
函数允许包含 N 个变量的 N 个以上的方程。
我也尝试过使用伪逆的方法,但这也要求矩阵是方阵。
如果方程和未知数的数量相等,您可以使用 LU 分解求解矩阵。
如果方程的数量多于未知数的数量,则使用最小二乘法。
如果方程的数量少于未知数的数量,则使用奇异值分解。
Here 是如何使用 R 完成的示例。我确信 Python、JAMA 和其他库都有 SVD 求解器。我不知道 Javascript。