diff --git a/Models/LeastSquaresResult.cs b/Models/LeastSquaresResult.cs
new file mode 100644
index 0000000..9a880e6
--- /dev/null
+++ b/Models/LeastSquaresResult.cs
@@ -0,0 +1,68 @@
+using System.Collections.Generic;
+
+namespace kcsj.Models
+{
+ public class LeastSquaresResult
+ {
+ public int ObservationCount { get; set; }
+ public int UnknownCount { get; set; }
+ public int Redundancy { get; set; }
+
+ ///
+ /// 单位权中误差
+ ///
+ public double Sigma0 { get; set; }
+
+ ///
+ /// 未知点平差高程
+ ///
+ public Dictionary UnknownElevations { get; } = new();
+
+ ///
+ /// 所有点平差后高程,包括已知点和未知点
+ ///
+ public Dictionary AdjustedElevations { get; } = new();
+
+ ///
+ /// 未知点高程中误差
+ ///
+ public Dictionary UnknownElevationErrors { get; } = new();
+
+ ///
+ /// 每条观测的改正数 v
+ ///
+ public List Residuals { get; } = new();
+
+ ///
+ /// 每条观测的平差后高差
+ ///
+ public List AdjustedHeightDiffs { get; } = new();
+
+ ///
+ /// 每条观测的详细结果
+ ///
+ public List ObservationResults { get; } = new();
+ }
+
+ public class ObservationAdjustmentResult
+ {
+ public int Index { get; set; }
+
+ public string FromPoint { get; set; } = "";
+ public string ToPoint { get; set; } = "";
+
+ public double ObservedHeightDiff { get; set; }
+ public double Distance { get; set; }
+ public double Weight { get; set; }
+
+ ///
+ /// 改正数 v
+ ///
+ public double Residual { get; set; }
+
+ ///
+ /// 平差后高差 h + v
+ ///
+ public double AdjustedHeightDiff { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Services/DataCheck.cs b/Services/DataCheck.cs
new file mode 100644
index 0000000..2484541
--- /dev/null
+++ b/Services/DataCheck.cs
@@ -0,0 +1,297 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using kcsj.Models;
+
+namespace kcsj.Services
+{
+ public class DataCheckResult
+ {
+ public List Errors { get; } = new();
+ public List Warnings { get; } = new();
+ public List Infos { get; } = new();
+
+ public bool IsValid => Errors.Count == 0;
+
+ public string ToLogText()
+ {
+ var lines = new List();
+
+ lines.Add("========== 数据检查结果 ==========");
+
+ foreach (string info in Infos)
+ {
+ lines.Add("[信息] " + info);
+ }
+
+ foreach (string warning in Warnings)
+ {
+ lines.Add("[警告] " + warning);
+ }
+
+ foreach (string error in Errors)
+ {
+ lines.Add("[错误] " + error);
+ }
+
+ lines.Add(IsValid ? "数据检查通过。" : "数据检查未通过。");
+ lines.Add("================================");
+
+ return string.Join(Environment.NewLine, lines);
+ }
+ }
+
+ public static class DataCheck
+ {
+ public static DataCheckResult Check(
+ List knownPoints,
+ List observations)
+ {
+ var result = new DataCheckResult();
+
+ if (knownPoints == null || knownPoints.Count == 0)
+ {
+ result.Errors.Add("未导入已知点数据。");
+ }
+ else
+ {
+ result.Infos.Add($"已知点数量:{knownPoints.Count}");
+ }
+
+ if (observations == null || observations.Count == 0)
+ {
+ result.Errors.Add("未导入观测数据。");
+ }
+ else
+ {
+ result.Infos.Add($"观测数据数量:{observations.Count}");
+ }
+
+ if (!result.IsValid)
+ {
+ return result;
+ }
+
+ CheckKnownPoints(knownPoints, result);
+ CheckObservations(observations, result);
+ CheckNetwork(knownPoints, observations, result);
+ CheckRedundancy(knownPoints, observations, result);
+
+ return result;
+ }
+
+ private static void CheckKnownPoints(
+ List knownPoints,
+ DataCheckResult result)
+ {
+ var names = new HashSet(StringComparer.OrdinalIgnoreCase);
+
+ for (int i = 0; i < knownPoints.Count; i++)
+ {
+ KnownPoint point = knownPoints[i];
+
+ if (string.IsNullOrWhiteSpace(point.Name))
+ {
+ result.Errors.Add($"第 {i + 1} 个已知点点名为空。");
+ continue;
+ }
+
+ string name = point.Name.Trim();
+
+ if (!names.Add(name))
+ {
+ result.Errors.Add($"已知点点名重复:{name}");
+ }
+
+ if (double.IsNaN(point.Elevation) || double.IsInfinity(point.Elevation))
+ {
+ result.Errors.Add($"已知点 {name} 的高程不是有效数字。");
+ }
+ }
+ }
+
+ private static void CheckObservations(
+ List observations,
+ DataCheckResult result)
+ {
+ var edges = new HashSet(StringComparer.OrdinalIgnoreCase);
+
+ for (int i = 0; i < observations.Count; i++)
+ {
+ Observation obs = observations[i];
+
+ if (string.IsNullOrWhiteSpace(obs.FromPoint))
+ {
+ result.Errors.Add($"第 {i + 1} 条观测起点为空。");
+ continue;
+ }
+
+ if (string.IsNullOrWhiteSpace(obs.ToPoint))
+ {
+ result.Errors.Add($"第 {i + 1} 条观测终点为空。");
+ continue;
+ }
+
+ string from = obs.FromPoint.Trim();
+ string to = obs.ToPoint.Trim();
+
+ if (string.Equals(from, to, StringComparison.OrdinalIgnoreCase))
+ {
+ result.Errors.Add($"第 {i + 1} 条观测起点和终点相同:{from}");
+ }
+
+ if (double.IsNaN(obs.HeightDiff) || double.IsInfinity(obs.HeightDiff))
+ {
+ result.Errors.Add($"第 {i + 1} 条观测高差不是有效数字。");
+ }
+
+ if (double.IsNaN(obs.Distance) || double.IsInfinity(obs.Distance))
+ {
+ result.Errors.Add($"第 {i + 1} 条观测距离不是有效数字。");
+ }
+ else if (obs.Distance <= 0)
+ {
+ result.Errors.Add($"第 {i + 1} 条观测距离必须大于 0。");
+ }
+
+ string edge1 = from + "-" + to;
+ string edge2 = to + "-" + from;
+
+ if (edges.Contains(edge1) || edges.Contains(edge2))
+ {
+ result.Warnings.Add($"第 {i + 1} 条观测边可能重复:{from} - {to}");
+ }
+ else
+ {
+ edges.Add(edge1);
+ }
+ }
+ }
+
+ private static void CheckNetwork(
+ List knownPoints,
+ List observations,
+ DataCheckResult result)
+ {
+ if (!result.IsValid)
+ {
+ return;
+ }
+
+ var knownNames = new HashSet(
+ knownPoints.Select(p => p.Name.Trim()),
+ StringComparer.OrdinalIgnoreCase);
+
+ var allNames = new HashSet(StringComparer.OrdinalIgnoreCase);
+
+ foreach (KnownPoint point in knownPoints)
+ {
+ allNames.Add(point.Name.Trim());
+ }
+
+ foreach (Observation obs in observations)
+ {
+ allNames.Add(obs.FromPoint.Trim());
+ allNames.Add(obs.ToPoint.Trim());
+ }
+
+ var graph = new Dictionary>(StringComparer.OrdinalIgnoreCase);
+
+ foreach (string name in allNames)
+ {
+ graph[name] = new List();
+ }
+
+ foreach (Observation obs in observations)
+ {
+ string from = obs.FromPoint.Trim();
+ string to = obs.ToPoint.Trim();
+
+ graph[from].Add(to);
+ graph[to].Add(from);
+ }
+
+ var visited = new HashSet(StringComparer.OrdinalIgnoreCase);
+ var queue = new Queue();
+
+ foreach (string knownName in knownNames)
+ {
+ if (graph.ContainsKey(knownName))
+ {
+ visited.Add(knownName);
+ queue.Enqueue(knownName);
+ }
+ }
+
+ while (queue.Count > 0)
+ {
+ string current = queue.Dequeue();
+
+ foreach (string next in graph[current])
+ {
+ if (!visited.Contains(next))
+ {
+ visited.Add(next);
+ queue.Enqueue(next);
+ }
+ }
+ }
+
+ foreach (string name in allNames)
+ {
+ if (!visited.Contains(name))
+ {
+ result.Errors.Add($"点 {name} 没有与任何已知点连通。");
+ }
+ }
+
+ int unknownCount = allNames.Count(name => !knownNames.Contains(name));
+
+ result.Infos.Add($"总点数:{allNames.Count}");
+ result.Infos.Add($"未知点数:{unknownCount}");
+ }
+
+ private static void CheckRedundancy(
+ List knownPoints,
+ List observations,
+ DataCheckResult result)
+ {
+ if (!result.IsValid)
+ {
+ return;
+ }
+
+ var knownNames = new HashSet(
+ knownPoints.Select(p => p.Name.Trim()),
+ StringComparer.OrdinalIgnoreCase);
+
+ var allNames = new HashSet(StringComparer.OrdinalIgnoreCase);
+
+ foreach (KnownPoint point in knownPoints)
+ {
+ allNames.Add(point.Name.Trim());
+ }
+
+ foreach (Observation obs in observations)
+ {
+ allNames.Add(obs.FromPoint.Trim());
+ allNames.Add(obs.ToPoint.Trim());
+ }
+
+ int unknownCount = allNames.Count(name => !knownNames.Contains(name));
+ int observationCount = observations.Count;
+ int redundancy = observationCount - unknownCount;
+
+ result.Infos.Add($"多余观测数:r = {observationCount} - {unknownCount} = {redundancy}");
+
+ if (observationCount < unknownCount)
+ {
+ result.Errors.Add("观测数少于未知点数,无法平差。");
+ }
+ else if (redundancy == 0)
+ {
+ result.Warnings.Add("多余观测数为 0,无法进行精度评定。");
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Services/DataStore.cs b/Services/DataStore.cs
new file mode 100644
index 0000000..dfc416e
--- /dev/null
+++ b/Services/DataStore.cs
@@ -0,0 +1,56 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using kcsj.Models;
+
+namespace kcsj.Services
+{
+ public static class DataStore
+ {
+ public static List KnownPoints { get; private set; } = new();
+ public static List Observations { get; private set; } = new();
+
+ public static string DataSource { get; private set; } = "";
+
+ public static bool HasData
+ {
+ get
+ {
+ return KnownPoints.Count > 0 && Observations.Count > 0;
+ }
+ }
+
+ public static void SetData(
+ List knownPoints,
+ List observations,
+ string dataSource)
+ {
+ if (knownPoints == null || knownPoints.Count == 0)
+ {
+ throw new ArgumentException("已知点数据为空,不能保存数据。");
+ }
+
+ if (observations == null || observations.Count == 0)
+ {
+ throw new ArgumentException("观测数据为空,不能保存数据。");
+ }
+
+ KnownPoints = knownPoints.ToList();
+ Observations = observations.ToList();
+ DataSource = dataSource;
+
+ LogService.AddLog($"数据已更新,来源:{dataSource}");
+ LogService.AddLog($"已知点数量:{KnownPoints.Count}");
+ LogService.AddLog($"观测数据数量:{Observations.Count}");
+ }
+
+ public static void Clear()
+ {
+ KnownPoints.Clear();
+ Observations.Clear();
+ DataSource = "";
+
+ LogService.AddLog("数据已清空。");
+ }
+ }
+}
\ No newline at end of file
diff --git a/Services/LeastSquares.cs b/Services/LeastSquares.cs
new file mode 100644
index 0000000..3e41ee7
--- /dev/null
+++ b/Services/LeastSquares.cs
@@ -0,0 +1,242 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using kcsj.Models;
+
+namespace kcsj.Services
+{
+ public static class LeastSquaresAdjustmentService
+ {
+ ///
+ /// 水准网间接平差
+ ///
+ /// 观测关系:
+ /// h_AB = H_B - H_A
+ ///
+ /// 误差方程:
+ /// v = Bx - L
+ ///
+ /// 法方程:
+ /// N x = W
+ /// N = B^T P B
+ /// W = B^T P L
+ /// x = N^-1 W
+ ///
+ public static LeastSquaresResult Adjust(
+ List knownPoints,
+ List observations)
+ {
+ if (knownPoints == null || knownPoints.Count == 0)
+ {
+ throw new ArgumentException("已知点不能为空。");
+ }
+
+ if (observations == null || observations.Count == 0)
+ {
+ throw new ArgumentException("观测数据不能为空。");
+ }
+
+ Dictionary knownElevations =
+ knownPoints.ToDictionary(
+ p => p.Name.Trim(),
+ p => p.Elevation,
+ StringComparer.OrdinalIgnoreCase);
+
+ HashSet allPointNames = new(StringComparer.OrdinalIgnoreCase);
+
+ foreach (Observation obs in observations)
+ {
+ if (string.IsNullOrWhiteSpace(obs.FromPoint) ||
+ string.IsNullOrWhiteSpace(obs.ToPoint))
+ {
+ throw new ArgumentException("观测数据中存在空点名。");
+ }
+
+ allPointNames.Add(obs.FromPoint.Trim());
+ allPointNames.Add(obs.ToPoint.Trim());
+ }
+
+ List unknownNames = allPointNames
+ .Where(name => !knownElevations.ContainsKey(name))
+ .OrderBy(name => name)
+ .ToList();
+
+ if (unknownNames.Count == 0)
+ {
+ throw new InvalidOperationException("没有未知点,不需要进行间接平差。");
+ }
+
+ int observationCount = observations.Count;
+ int unknownCount = unknownNames.Count;
+
+ if (observationCount < unknownCount)
+ {
+ throw new InvalidOperationException("观测数小于未知数,无法进行最小二乘平差。");
+ }
+
+ Dictionary unknownIndex = new(StringComparer.OrdinalIgnoreCase);
+
+ for (int i = 0; i < unknownNames.Count; i++)
+ {
+ unknownIndex[unknownNames[i]] = i;
+ }
+
+ MatrixOperations B = new MatrixOperations(observationCount, unknownCount);
+ MatrixOperations L = new MatrixOperations(observationCount, 1);
+ MatrixOperations P = new MatrixOperations(observationCount, observationCount);
+
+ double[] weights = new double[observationCount];
+
+ for (int i = 0; i < observationCount; i++)
+ {
+ Observation obs = observations[i];
+
+ string from = obs.FromPoint.Trim();
+ string to = obs.ToPoint.Trim();
+
+ // h_AB = H_B - H_A
+ // FromPoint 是未知点,系数为 -1
+ if (unknownIndex.ContainsKey(from))
+ {
+ B[i, unknownIndex[from]] = -1.0;
+ }
+
+ // ToPoint 是未知点,系数为 +1
+ if (unknownIndex.ContainsKey(to))
+ {
+ B[i, unknownIndex[to]] = 1.0;
+ }
+
+ // 已知点贡献:H_B(已知) - H_A(已知)
+ double knownContribution = 0.0;
+
+ if (knownElevations.ContainsKey(to))
+ {
+ knownContribution += knownElevations[to];
+ }
+
+ if (knownElevations.ContainsKey(from))
+ {
+ knownContribution -= knownElevations[from];
+ }
+
+ // L = h观测 - 已知点贡献
+ L[i, 0] = obs.HeightDiff - knownContribution;
+
+ // 水准测量常用定权:p = 1 / S
+ // 距离越长,权越小
+ double weight;
+
+ if (obs.Distance <= 0)
+ {
+ weight = 1.0;
+ }
+ else
+ {
+ weight = 1.0 / obs.Distance;
+ }
+
+ P[i, i] = weight;
+ weights[i] = weight;
+ }
+
+ MatrixOperations Bt = B.Transpose();
+
+ MatrixOperations N = Bt.Multiply(P).Multiply(B);
+ MatrixOperations W = Bt.Multiply(P).Multiply(L);
+
+ MatrixOperations Qxx = N.Inverse();
+ MatrixOperations X = Qxx.Multiply(W);
+
+ // v = Bx - L
+ MatrixOperations V = B.Multiply(X).Sub(L);
+
+ // V^T P V
+ MatrixOperations VtPV = V.Transpose().Multiply(P).Multiply(V);
+
+ int redundancy = observationCount - unknownCount;
+
+ double sigma0;
+
+ if (redundancy > 0)
+ {
+ sigma0 = Math.Sqrt(VtPV[0, 0] / redundancy);
+ }
+ else
+ {
+ sigma0 = double.NaN;
+ }
+
+ LeastSquaresResult result = new LeastSquaresResult
+ {
+ ObservationCount = observationCount,
+ UnknownCount = unknownCount,
+ Redundancy = redundancy,
+ Sigma0 = sigma0
+ };
+
+ foreach (KnownPoint point in knownPoints)
+ {
+ result.AdjustedElevations[point.Name.Trim()] = point.Elevation;
+ }
+
+ for (int i = 0; i < unknownCount; i++)
+ {
+ string pointName = unknownNames[i];
+ double elevation = X[i, 0];
+
+ result.UnknownElevations[pointName] = elevation;
+ result.AdjustedElevations[pointName] = elevation;
+
+ if (double.IsNaN(sigma0))
+ {
+ result.UnknownElevationErrors[pointName] = double.NaN;
+ }
+ else
+ {
+ result.UnknownElevationErrors[pointName] =
+ sigma0 * Math.Sqrt(Math.Abs(Qxx[i, i]));
+ }
+ }
+
+ for (int i = 0; i < observationCount; i++)
+ {
+ Observation obs = observations[i];
+
+ double residual = V[i, 0];
+ double adjustedHeightDiff = obs.HeightDiff + residual;
+
+ result.Residuals.Add(residual);
+ result.AdjustedHeightDiffs.Add(adjustedHeightDiff);
+
+ result.ObservationResults.Add(new ObservationAdjustmentResult
+ {
+ Index = i + 1,
+ FromPoint = obs.FromPoint,
+ ToPoint = obs.ToPoint,
+ ObservedHeightDiff = obs.HeightDiff,
+ Distance = obs.Distance,
+ Weight = weights[i],
+ Residual = residual,
+ AdjustedHeightDiff = adjustedHeightDiff
+ });
+ }
+
+ LogService.AddLog("间接平差计算完成。");
+ LogService.AddLog($"观测数:{observationCount}");
+ LogService.AddLog($"未知点数:{unknownCount}");
+ LogService.AddLog($"多余观测数:{redundancy}");
+
+ if (double.IsNaN(sigma0))
+ {
+ LogService.AddLog("单位权中误差:无法计算,多余观测数为 0。");
+ }
+ else
+ {
+ LogService.AddLog($"单位权中误差:{sigma0:F6}");
+ }
+
+ return result;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Services/MatrixOperations.cs b/Services/MatrixOperations.cs
new file mode 100644
index 0000000..bfa795f
--- /dev/null
+++ b/Services/MatrixOperations.cs
@@ -0,0 +1,197 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace kcsj.Services
+{
+ public class MatrixOperations
+ {
+ private const double eps = 1e-2;
+ private readonly double[,] values;
+
+ private int RowCount { get; }
+ private int ColumnCount { get; }
+
+ public double this[int row, int column]
+ {
+ get => values[row, column];
+ set => values[row, column] = value;
+ }
+
+ // 初始化矩阵大小
+ public MatrixOperations(int rowCount, int columnCount)
+ {
+ if (rowCount <= 0 || columnCount <= 0)
+ {
+ throw new ArgumentException("矩阵行列数必须大于 0。");
+ }
+
+ RowCount = rowCount;
+ ColumnCount = columnCount;
+ values = new double[rowCount, columnCount];
+ }
+
+ // 从二维数组初始化矩阵
+ public MatrixOperations(double[,] source)
+ {
+ RowCount = source.GetLength(0);
+ ColumnCount = source.GetLength(1);
+ values = new double[RowCount, ColumnCount];
+
+ for (int i = 0; i < RowCount; i++)
+ {
+ for (int j = 0; j < ColumnCount; j++)
+ {
+ values[i, j] = source[i, j];
+ }
+ }
+ }
+
+ public MatrixOperations Add(MatrixOperations other)
+ {
+ if (RowCount != other.RowCount || ColumnCount != other.ColumnCount)
+ {
+ throw new ArgumentException("矩阵维度不匹配,无法相加。");
+ }
+ MatrixOperations result = new MatrixOperations(RowCount, ColumnCount);
+ for (int i = 0; i < RowCount; i++)
+ {
+ for (int j = 0; j < ColumnCount; j++)
+ {
+ result[i, j] = this[i, j] + other[i, j];
+ }
+ }
+ return result;
+ }
+
+ public MatrixOperations Sub (MatrixOperations other)
+ {
+ if (RowCount != other.RowCount || ColumnCount != other.ColumnCount)
+ {
+ throw new ArgumentException("矩阵维度不匹配,无法相减。");
+ }
+ MatrixOperations result = new MatrixOperations(RowCount, ColumnCount);
+ for (int i = 0; i < RowCount; i++)
+ {
+ for (int j = 0; j < ColumnCount; j++)
+ {
+ result[i, j] = this[i, j] - other[i, j];
+ }
+ }
+ return result;
+
+ }
+
+ public MatrixOperations Multiply(MatrixOperations other)
+ {
+ if (ColumnCount != other.RowCount)
+ {
+ throw new ArgumentException("矩阵维度不匹配,无法相乘。");
+ }
+ MatrixOperations result = new MatrixOperations(RowCount, other.ColumnCount);
+ for (int i = 0; i < RowCount; i++)
+ {
+ for (int j = 0; j < other.ColumnCount; j++)
+ {
+ double sum = 0;
+ for (int k = 0; k < ColumnCount; k++)
+ {
+ sum += this[i, k] * other[k, j];
+ }
+ result[i, j] = sum;
+ }
+ }
+ return result;
+ }
+
+ public MatrixOperations Transpose()
+ {
+ MatrixOperations result = new MatrixOperations(ColumnCount, RowCount);
+ for (int i = 0; i < RowCount; i++)
+ {
+ for (int j = 0; j < ColumnCount; j++)
+ {
+ result[j, i] = this[i, j];
+ }
+ }
+ return result;
+ }
+
+ public MatrixOperations Inverse()
+ {
+ if (RowCount != ColumnCount)
+ {
+ throw new ArgumentException("只有方阵才有逆矩阵。");
+ }
+ int n = RowCount;
+ MatrixOperations augmented = new MatrixOperations(n, 2 * n);
+ // 构造增广矩阵 [A | I]
+ for (int i = 0; i < n; i++)
+ {
+ for (int j = 0; j < n; j++)
+ {
+ augmented[i, j] = this[i, j];
+ }
+ augmented[i, n + i] = 1; // 添加单位矩阵部分
+ }
+ // 使用高斯消元法将左侧变为单位矩阵
+ for (int i = 0; i < n; i++)
+ {
+ // 寻找主元素
+ int pivotRow = i;
+ for (int row = i + 1; row < n; row++)
+ {
+ if (Math.Abs(augmented[row, i]) > Math.Abs(augmented[pivotRow, i]))
+ {
+ pivotRow = row;
+ }
+ }
+ if (Math.Abs(augmented[pivotRow, i]) < eps)
+ {
+ throw new InvalidOperationException("矩阵不可逆。");
+ }
+ // 交换行
+ if (pivotRow != i)
+ {
+ for (int col = 0; col < 2 * n; col++)
+ {
+ double temp = augmented[i, col];
+ augmented[i, col] = augmented[pivotRow, col];
+ augmented[pivotRow, col] = temp;
+ }
+ }
+ // 将主元素归一化
+ double pivotValue = augmented[i, i];
+ for (int col = 0; col < 2 * n; col++)
+ {
+ augmented[i, col] /= pivotValue;
+ }
+ // 消去其他行的当前列
+ for (int row = 0; row < n; row++)
+ {
+ if (row != i)
+ {
+ double factor = augmented[row, i];
+ for (int col = 0; col < 2 * n; col++)
+ {
+ augmented[row, col] -= factor * augmented[i, col];
+ }
+ }
+ }
+ }
+ // 提取右侧的逆矩阵
+ MatrixOperations inverse = new MatrixOperations(n, n);
+ for (int i = 0; i < n; i++)
+ {
+ for (int j = 0; j < n; j++)
+ {
+ inverse[i, j] = augmented[i, n + j];
+ }
+ }
+ return inverse;
+ }
+
+ }
+}