LuDecomposition.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. namespace VisualMath.Accord.Math.Decompositions
  7. {
  8. using System;
  9. using VisualMath.Accord.Math;
  10. /// <summary>
  11. /// LU decomposition of a rectangular matrix.
  12. /// </summary>
  13. /// <remarks>
  14. /// <para>
  15. /// For an m-by-n matrix <c>A</c> with <c>m >= n</c>, the LU decomposition is an m-by-n
  16. /// unit lower triangular matrix <c>L</c>, an n-by-n upper triangular matrix <c>U</c>,
  17. /// and a permutation vector <c>piv</c> of length m so that <c>A(piv) = L*U</c>.
  18. /// If m &lt; n, then <c>L</c> is m-by-m and <c>U</c> is m-by-n.</para>
  19. /// <para>
  20. /// The LU decomposition with pivoting always exists, even if the matrix is
  21. /// singular, so the constructor will never fail. The primary use of the
  22. /// LU decomposition is in the solution of square systems of simultaneous
  23. /// linear equations. This will fail if <see cref="NonSingular"/> returns
  24. /// <see langword="false"/>.
  25. /// </para>
  26. /// </remarks>
  27. ///
  28. public sealed class LuDecomposition
  29. {
  30. private double[,] lu;
  31. private int pivotSign;
  32. private int[] pivotVector;
  33. /// <summary>Construct a new LU decomposition.</summary>
  34. /// <param name="value">The matrix A to be decomposed.</param>
  35. public LuDecomposition(double[,] value)
  36. : this(value, false)
  37. {
  38. }
  39. /// <summary>Construct a LU decomposition.</summary>
  40. /// <param name="value">The matrix A to be decomposed.</param>
  41. /// <param name="transpose">True if the decomposition should be performed on
  42. /// the transpose of A rather than A itself, false otherwise. Default is false.</param>
  43. public LuDecomposition(double[,] value, bool transpose)
  44. {
  45. if (value == null)
  46. {
  47. throw new ArgumentNullException("value", "Matrix cannot be null.");
  48. }
  49. if ((!transpose && value.GetLength(0) < value.GetLength(1)) ||
  50. (transpose && value.GetLength(1) < value.GetLength(0)))
  51. {
  52. throw new ArgumentException("Matrix has more columns than rows.", "value");
  53. }
  54. this.lu = transpose ? value.Transpose() : (double[,])value.Clone();
  55. int rows = lu.GetLength(0);
  56. int cols = lu.GetLength(1);
  57. this.pivotVector = new int[rows];
  58. for (int i = 0; i < rows; i++)
  59. pivotVector[i] = i;
  60. pivotSign = 1;
  61. double[] LUcolj = new double[rows];
  62. // Outer loop.
  63. for (int j = 0; j < cols; j++)
  64. {
  65. // Make a copy of the j-th column to localize references.
  66. for (int i = 0; i < rows; i++)
  67. LUcolj[i] = lu[i, j];
  68. // Apply previous transformations.
  69. for (int i = 0; i < rows; i++)
  70. {
  71. // Most of the time is spent in the following dot product.
  72. int kmax = System.Math.Min(i, j);
  73. double s = 0.0;
  74. for (int k = 0; k < kmax; k++)
  75. s += lu[i, k] * LUcolj[k];
  76. lu[i, j] = LUcolj[i] -= s;
  77. }
  78. // Find pivot and exchange if necessary.
  79. int p = j;
  80. for (int i = j + 1; i < rows; i++)
  81. {
  82. if (System.Math.Abs(LUcolj[i]) > System.Math.Abs(LUcolj[p]))
  83. p = i;
  84. }
  85. if (p != j)
  86. {
  87. for (int k = 0; k < cols; k++)
  88. {
  89. double t = lu[p, k];
  90. lu[p, k] = lu[j, k];
  91. lu[j, k] = t;
  92. }
  93. int v = pivotVector[p];
  94. pivotVector[p] = pivotVector[j];
  95. pivotVector[j] = v;
  96. pivotSign = -pivotSign;
  97. }
  98. // Compute multipliers.
  99. if (j < rows & lu[j, j] != 0.0)
  100. {
  101. for (int i = j + 1; i < rows; i++)
  102. lu[i, j] /= lu[j, j];
  103. }
  104. }
  105. }
  106. /// <summary>Returns if the matrix is non-singular.</summary>
  107. public bool NonSingular
  108. {
  109. get
  110. {
  111. for (int j = 0; j < lu.GetLength(1); j++)
  112. if (lu[j, j] == 0)
  113. return false;
  114. return true;
  115. }
  116. }
  117. /// <summary>Returns the determinant of the matrix.</summary>
  118. public double Determinant
  119. {
  120. get
  121. {
  122. if (lu.GetLength(0) != lu.GetLength(1))
  123. throw new InvalidOperationException("Matrix must be square.");
  124. double determinant = (double)pivotSign;
  125. for (int j = 0; j < lu.GetLength(1); j++)
  126. determinant *= lu[j, j];
  127. return determinant;
  128. }
  129. }
  130. /// <summary>Returns the lower triangular factor <c>L</c> with <c>A=LU</c>.</summary>
  131. public double[,] LowerTriangularFactor
  132. {
  133. get
  134. {
  135. int rows = lu.GetLength(0);
  136. int columns = lu.GetLength(1);
  137. double[,] X = new double[rows, columns];
  138. for (int i = 0; i < rows; i++)
  139. {
  140. for (int j = 0; j < columns; j++)
  141. {
  142. if (i > j)
  143. X[i, j] = lu[i, j];
  144. else if (i == j)
  145. X[i, j] = 1.0;
  146. else
  147. X[i, j] = 0.0;
  148. }
  149. }
  150. return X;
  151. }
  152. }
  153. /// <summary>Returns the lower triangular factor <c>L</c> with <c>A=LU</c>.</summary>
  154. public double[,] UpperTriangularFactor
  155. {
  156. get
  157. {
  158. int rows = lu.GetLength(0);
  159. int columns = lu.GetLength(1);
  160. double[,] X = new double[rows, columns];
  161. for (int i = 0; i < rows; i++)
  162. {
  163. for (int j = 0; j < columns; j++)
  164. {
  165. if (i <= j)
  166. X[i, j] = lu[i, j];
  167. else
  168. X[i, j] = 0.0;
  169. }
  170. }
  171. return X;
  172. }
  173. }
  174. /// <summary>Returns the pivot permuation vector.</summary>
  175. public double[] PivotPermutationVector
  176. {
  177. get
  178. {
  179. int rows = lu.GetLength(0);
  180. double[] p = new double[rows];
  181. for (int i = 0; i < rows; i++)
  182. p[i] = (double)this.pivotVector[i];
  183. return p;
  184. }
  185. }
  186. /// <summary>Solves a set of equation systems of type <c>A * X = I</c>.</summary>
  187. public double[,] Inverse()
  188. {
  189. if (!this.NonSingular)
  190. {
  191. throw new InvalidOperationException("Matrix is singular");
  192. }
  193. int rows = lu.GetLength(1);
  194. int columns = lu.GetLength(1);
  195. int count = rows;
  196. // Copy right hand side with pivoting
  197. double[,] X = new double[rows, columns];
  198. for (int i = 0; i < rows; i++)
  199. {
  200. int k = pivotVector[i];
  201. X[i, k] = 1.0;
  202. }
  203. // Solve L*Y = B(piv,:)
  204. for (int k = 0; k < columns; k++)
  205. for (int i = k + 1; i < columns; i++)
  206. for (int j = 0; j < count; j++)
  207. X[i, j] -= X[k, j] * lu[i, k];
  208. // Solve U*X = I;
  209. for (int k = columns - 1; k >= 0; k--)
  210. {
  211. for (int j = 0; j < count; j++)
  212. X[k, j] /= lu[k, k];
  213. for (int i = 0; i < k; i++)
  214. for (int j = 0; j < count; j++)
  215. X[i, j] -= X[k, j] * lu[i, k];
  216. }
  217. return X;
  218. }
  219. /// <summary>Solves a set of equation systems of type <c>A * X = B</c>.</summary>
  220. /// <param name="value">Right hand side matrix with as many rows as <c>A</c> and any number of columns.</param>
  221. /// <returns>Matrix <c>X</c> so that <c>L * U * X = B</c>.</returns>
  222. public double[,] Solve(double[,] value)
  223. {
  224. if (value == null)
  225. {
  226. throw new ArgumentNullException("value");
  227. }
  228. if (value.GetLength(0) != this.lu.GetLength(0))
  229. {
  230. throw new ArgumentException("Invalid matrix dimensions.", "value");
  231. }
  232. if (!this.NonSingular)
  233. {
  234. throw new InvalidOperationException("Matrix is singular");
  235. }
  236. // Copy right hand side with pivoting
  237. int count = value.GetLength(1);
  238. double[,] X = value.Submatrix(pivotVector, 0, count - 1);
  239. int columns = lu.GetLength(1);
  240. // Solve L*Y = B(piv,:)
  241. for (int k = 0; k < columns; k++)
  242. for (int i = k + 1; i < columns; i++)
  243. for (int j = 0; j < count; j++)
  244. X[i, j] -= X[k, j] * lu[i, k];
  245. // Solve U*X = Y;
  246. for (int k = columns - 1; k >= 0; k--)
  247. {
  248. for (int j = 0; j < count; j++)
  249. X[k, j] /= lu[k, k];
  250. for (int i = 0; i < k; i++)
  251. for (int j = 0; j < count; j++)
  252. X[i, j] -= X[k, j] * lu[i, k];
  253. }
  254. return X;
  255. }
  256. /// <summary>Solves a set of equation systems of type <c>X * A = B</c>.</summary>
  257. /// <param name="value">Right hand side matrix with as many columns as <c>A</c> and any number of rows.</param>
  258. /// <returns>Matrix <c>X</c> so that <c>X * L * U = A</c>.</returns>
  259. public double[,] SolveTranspose(double[,] value)
  260. {
  261. if (value == null)
  262. {
  263. throw new ArgumentNullException("value");
  264. }
  265. if (value.GetLength(0) != this.lu.GetLength(0))
  266. {
  267. throw new ArgumentException("Invalid matrix dimensions.", "value");
  268. }
  269. if (!this.NonSingular)
  270. {
  271. throw new InvalidOperationException("Matrix is singular");
  272. }
  273. // Copy right hand side with pivoting
  274. double[,] X = value.Submatrix(null, pivotVector);
  275. int count = X.GetLength(1);
  276. int columns = lu.GetLength(1);
  277. // Solve L*Y = B(piv,:)
  278. for (int k = 0; k < columns; k++)
  279. for (int i = k + 1; i < columns; i++)
  280. for (int j = 0; j < count; j++)
  281. X[j, i] -= X[j, k] * lu[i, k];
  282. // Solve U*X = Y;
  283. for (int k = columns - 1; k >= 0; k--)
  284. {
  285. for (int j = 0; j < count; j++)
  286. X[j, k] /= lu[k, k];
  287. for (int i = 0; i < k; i++)
  288. for (int j = 0; j < count; j++)
  289. X[j, i] -= X[j, k] * lu[i, k];
  290. }
  291. return X;
  292. }
  293. /// <summary>Solves a set of equation systems of type <c>A * X = B</c>.</summary>
  294. /// <param name="value">Right hand side matrix with as many rows as <c>A</c> and any number of columns.</param>
  295. /// <returns>Matrix <c>X</c> so that <c>L * U * X = B</c>.</returns>
  296. public double[] Solve(double[] value)
  297. {
  298. if (value == null)
  299. {
  300. throw new ArgumentNullException("value");
  301. }
  302. if (value.Length != this.lu.GetLength(0))
  303. {
  304. throw new ArgumentException("Invalid matrix dimensions.", "value");
  305. }
  306. if (!this.NonSingular)
  307. {
  308. throw new InvalidOperationException("Matrix is singular");
  309. }
  310. // Copy right hand side with pivoting
  311. int count = value.Length;
  312. double[] b = new double[count];
  313. for (int i = 0; i < b.Length; i++)
  314. b[i] = value[pivotVector[i]];
  315. int rows = lu.GetLength(1);
  316. int columns = lu.GetLength(1);
  317. // Solve L*Y = B
  318. double[] X = new double[count];
  319. for (int i = 0; i < rows; i++)
  320. {
  321. X[i] = b[i];
  322. for (int j = 0; j < i; j++)
  323. X[i] -= lu[i, j] * X[j];
  324. }
  325. // Solve U*X = Y;
  326. for (int i = rows - 1; i >= 0; i--)
  327. {
  328. //double sum = 0.0;
  329. for (int j = columns - 1; j > i; j--)
  330. X[i] -= lu[i, j] * X[j];
  331. X[i] /= lu[i, i];
  332. }
  333. return X;
  334. }
  335. }
  336. }