// ------------------------
		//   Constructor
		// ------------------------

		// QR Decomposition, computed by Householder reflections.
		// @param A    Rectangular matrix
		public QRDecomposition (Matrix A)
		{
			// Initialize.
			QR = A.GetArrayCopy();
			m = A.GetRowDimension();
			n = A.GetColumnDimension();
			Rdiag = new double[n];

			// Main loop.
			for (int k = 0; k < n; k++)
			{
				// Compute 2-norm of k-th column without under/overflow.
				double nrm = 0;
				for (int i = k; i < m; i++)
				{
					nrm = MathUtils.Hypot(nrm,QR[i][k]);
				}

				if (nrm != 0.0)
				{
					// Form k-th Householder vector.
					if (QR[k][k] < 0)
					{
						nrm = -nrm;
					}
					for (int i = k; i < m; i++)
					{
						QR[i][k] /= nrm;
					}
					QR[k][k] += 1.0;

					// Apply transformation to remaining columns.
					for (int j = k+1; j < n; j++)
					{
						double s = 0.0;
						for (int i = k; i < m; i++)
						{
							s += QR[i][k]*QR[i][j];
						}
						s = -s/QR[k][k];
						for (int i = k; i < m; i++)
						{
							QR[i][j] += s*QR[i][k];
						}
					}
				}
				Rdiag[k] = -nrm;
			}
		}
		// ------------------------
		// Constructor
		// ------------------------

		/// <summary>
		/// Cholesky algorithm for symmetric and positive definite matrix.
		/// </summary>
		/// <param name="Arg">Square, symmetric matrix.</param>
		public CholeskyDecomposition (Matrix Arg)
		{
			// Initialize.
			double[][] A = Arg.GetArray();
			n = Arg.GetRowDimension();
			
			L = new double[n][];
			for (int i=0;i<n;i++)
				L[i] = new double[n];
			
			isspd = (Arg.GetColumnDimension() == n);
			// Main loop.
			for (int j = 0; j < n; j++)
			{
				double[] Lrowj = L[j];
				double d = 0.0;
				for (int k = 0; k < j; k++)
				{
					double[] Lrowk = L[k];
					double s = 0.0;
					for (int i = 0; i < k; i++)
					{
						s += Lrowk[i]*Lrowj[i];
					}
					Lrowj[k] = s = (A[j][k] - s)/L[k][k];
					d = d + s*s;
					isspd = isspd & (A[k][j] == A[j][k]);
				}
				d = A[j][j] - d;
				isspd = isspd & (d > 0.0);
				L[j][j] = Math.Sqrt(Math.Max(d,0.0));
				for (int k = j+1; k < n; k++)
				{
					L[j][k] = 0.0;
				}
			}
		}
		// ------------------------
		//   Constructor
		// ------------------------

		// LU Decomposition
		// @param  A   Rectangular matrix
		public LUDecomposition (Matrix A)
		{
			// Use a "left-looking", dot-product, Crout/Doolittle algorithm.
			LU = A.GetArrayCopy();
			m = A.GetRowDimension();
			n = A.GetColumnDimension();
			piv = new int[m];
			for (int i = 0; i < m; i++)
			{
				piv[i] = i;
			}
			pivsign = 1;
			double[] LUrowi;
			double[] LUcolj = new double[m];

			// Outer loop.
			for (int j = 0; j < n; j++)
			{
				// Make a copy of the j-th column to localize references.
				for (int i = 0; i < m; i++)
				{
					LUcolj[i] = LU[i][j];
				}

				// Apply previous transformations.
				for (int i = 0; i < m; i++)
				{
					LUrowi = LU[i];

					// Most of the time is spent in the following dot product.
					int kmax = Math.Min(i,j);
					double s = 0.0;
					for (int k = 0; k < kmax; k++)
					{
						s += LUrowi[k]*LUcolj[k];
					}

					LUrowi[j] = LUcolj[i] -= s;
				}

				// Find pivot and exchange if necessary.
				int p = j;
				for (int i = j+1; i < m; i++)
				{
					if (Math.Abs(LUcolj[i]) > Math.Abs(LUcolj[p]))
					{
						p = i;
					}
				}
				if (p != j)
				{
					for (int k = 0; k < n; k++)
					{
						double t = LU[p][k];
						LU[p][k] = LU[j][k];
						LU[j][k] = t;
					}
					int k1 = piv[p];
					piv[p] = piv[j];
					piv[j] = k1;
					pivsign = -pivsign;
				}

				// Compute multipliers.
				if (j < m & LU[j][j] != 0.0)
				{
					for (int i = j+1; i < m; i++)
					{
						LU[i][j] /= LU[j][j];
					}
				}
			}
		}
		// Solve A*X = B
		// @param  B   A Matrix with as many rows as A and any number of columns.
		// @return     X so that L*U*X = B(piv,:)
		// @exception  ArgumentException Matrix row dimensions must agree.
		// @exception  Exception  Matrix is singular.
		public Matrix Solve (Matrix B)
		{
			if (B.GetRowDimension() != m)
			{
				throw new ArgumentException("Matrix row dimensions must agree.");
			}
			if (!this.IsNonsingular())
			{
				throw new Exception("Matrix is singular.");
			}

			// Copy right hand side with pivoting
			int nx = B.GetColumnDimension();
			Matrix Xmat = B.GetMatrix(piv,0,nx-1);
			double[][] X = Xmat.GetArray();

			// Solve L*Y = B(piv,:)
			for (int k = 0; k < n; k++)
			{
				for (int i = k+1; i < n; i++)
				{
					for (int j = 0; j < nx; j++)
					{
						X[i][j] -= X[k][j]*LU[i][k];
					}
				}
			}
			// Solve U*X = Y;
			for (int k = n-1; k >= 0; k--)
			{
				for (int j = 0; j < nx; j++)
				{
					X[k][j] /= LU[k][k];
				}
				for (int i = 0; i < k; i++)
				{
					for (int j = 0; j < nx; j++)
					{
						X[i][j] -= X[k][j]*LU[i][k];
					}
				}
			}
			return Xmat;
		}
		/// <summary>
		/// Solve A*X = B
		/// </summary>
		/// <param name="B">A Matrix with as many rows as A and any number of columns.</param>
		/// <returns>X so that L*L'*X = B</returns>
		public Matrix Solve (Matrix B)
		{
			if (B.GetRowDimension() != n)
			{
				throw new ArgumentException("Matrix row dimensions must agree.");
			}
			if (!isspd)
			{
				throw new Exception("Matrix is not symmetric positive definite.");
			}

			// Copy right hand side.
			double[][] X = B.GetArrayCopy();
			int nx = B.GetColumnDimension();

			// Solve L*Y = B;
			for (int k = 0; k < n; k++)
			{
				for (int j = 0; j < nx; j++)
				{
					for (int i = 0; i < k ; i++)
					{
						X[k][j] -= X[i][j]*L[k][i];
					}
					X[k][j] /= L[k][k];
				}
			}

			// Solve L'*X = Y;
			for (int k = n-1; k >= 0; k--)
			{
				for (int j = 0; j < nx; j++)
				{
					for (int i = k+1; i < n ; i++)
					{
						X[k][j] -= X[i][j]*L[i][k];
					}
					X[k][j] /= L[k][k];
				}
			}

			return new Matrix(X,n,nx);
		}
		// Least squares solution of A*X = B
		// @param B    A Matrix with as many rows as A and any number of columns.
		// @return     X that minimizes the two norm of Q*R*X-B.
		// @exception  ArgumentException  Matrix row dimensions must agree.
		// @exception  Exception  Matrix is rank deficient.
		public Matrix Solve (Matrix B)
		{
			if (B.GetRowDimension() != m)
			{
				throw new ArgumentException("Matrix row dimensions must agree.");
			}
			if (!this.IsFullRank())
			{
				throw new Exception("Matrix is rank deficient.");
			}

			// Copy right hand side
			int nx = B.GetColumnDimension();
			double[][] X = B.GetArrayCopy();

			// Compute Y = transpose(Q)*B
			for (int k = 0; k < n; k++)
			{
				for (int j = 0; j < nx; j++)
				{
					double s = 0.0;
					for (int i = k; i < m; i++)
					{
						s += QR[i][k]*X[i][j];
					}
					s = -s/QR[k][k];
					for (int i = k; i < m; i++)
					{
						X[i][j] += s*QR[i][k];
					}
				}
			}
			// Solve R*X = Y;
			for (int k = n-1; k >= 0; k--)
			{
				for (int j = 0; j < nx; j++)
				{
					X[k][j] /= Rdiag[k];
				}
				for (int i = 0; i < k; i++)
				{
					for (int j = 0; j < nx; j++)
					{
						X[i][j] -= X[k][j]*QR[i][k];
					}
				}
			}
			return (new Matrix(X,n,nx).GetMatrix(0,n-1,0,nx-1));
		}
		// ------------------------
		//   Constructor
		// ------------------------

		/// <summary>
		/// Check for symmetry, then construct the eigenvalue decomposition
		/// </summary>
		/// <param name="Arg">Square matrix</param>
		public EigenvalueDecomposition (Matrix Arg)
		{
			double[][] A = Arg.GetArray();
			n = Arg.GetColumnDimension();
			
			V = new double[n][];
			for (int i=0;i<n;i++)
				V[i] = new double[n];
			
			d = new double[n];
			e = new double[n];

			issymmetric = true;
			for (int j = 0; (j < n) & issymmetric; j++)
			{
				for (int i = 0; (i < n) & issymmetric; i++)
				{
					issymmetric = (A[i][j] == A[j][i]);
				}
			}

			if (issymmetric)
			{
				for (int i = 0; i < n; i++)
				{
					for (int j = 0; j < n; j++)
					{
						V[i][j] = A[i][j];
					}
				}

				// Tridiagonalize.
				Tred2();

				// Diagonalize.
				Tql2();

			}
			else
			{
				H = new double[n][];
				for (int i=0;i<n;i++)
					H[i] = new double[n];
				
				ort = new double[n];

				for (int j = 0; j < n; j++)
				{
					for (int i = 0; i < n; i++)
					{
						H[i][j] = A[i][j];
					}
				}

				// Reduce to Hessenberg form.
				Orthes();

				// Reduce Hessenberg to real Schur form.
				Hqr2();
			}
		}
		// ------------------------
		//   Constructor
		// ------------------------

		// Construct the singular value decomposition
		// @param Arg    Rectangular matrix
		public SingularValueDecomposition (Matrix Arg)
		{
			// Derived from LINPACK code.
			// Initialize.
			double[][] A = Arg.GetArrayCopy();
			m = Arg.GetRowDimension();
			n = Arg.GetColumnDimension();

			// Apparently the failing cases are only a proper subset of (m<n),
			// so let's not throw error.  Correct fix to come later?
			// if (m<n) {
			// throw new ArgumentException("Jama SVD only works for m >= n"); }
			//
			int nu = Math.Min(m,n);
			s = new double [Math.Min(m+1,n)];
			
			U = new double[m][];
			for (int i=0;i<m;i++)
				U[i] = new double[nu];
			
			V = new double [n][];
			for (int i=0;i<n;i++)
				V[i] = new double[n];
			
			double[] e = new double [n];
			double[] work = new double [m];
			bool wantu = true;
			bool wantv = true;

			// Reduce A to bidiagonal form, storing the diagonal elements
			// in s and the super-diagonal elements in e.
			int nct = Math.Min(m-1,n);
			int nrt = Math.Max(0,Math.Min(n-2,m));
			for (int k = 0; k < Math.Max(nct,nrt); k++)
			{
				if (k < nct)
				{
					// Compute the transformation for the k-th column and
					// place the k-th diagonal in s[k].
					// Compute 2-norm of k-th column without under/overflow.
					s[k] = 0;
					for (int i = k; i < m; i++)
					{
						s[k] = MathUtils.Hypot(s[k],A[i][k]);
					}
					if (s[k] != 0.0)
					{
						if (A[k][k] < 0.0)
						{
							s[k] = -s[k];
						}
						for (int i = k; i < m; i++)
						{
							A[i][k] /= s[k];
						}
						A[k][k] += 1.0;
					}
					s[k] = -s[k];
				}
				for (int j = k+1; j < n; j++)
				{
					if ((k < nct) & (s[k] != 0.0))
					{

						// Apply the transformation.

						double t = 0;
						for (int i = k; i < m; i++)
						{
							t += A[i][k]*A[i][j];
						}
						t = -t/A[k][k];
						for (int i = k; i < m; i++)
						{
							A[i][j] += t*A[i][k];
						}
					}

					// Place the k-th row of A into e for the
					// subsequent calculation of the row transformation.

					e[j] = A[k][j];
				}
				if (wantu & (k < nct))
				{

					// Place the transformation in U for subsequent back
					// multiplication.

					for (int i = k; i < m; i++)
					{
						U[i][k] = A[i][k];
					}
				}
				if (k < nrt)
				{

					// Compute the k-th row transformation and place the
					// k-th super-diagonal in e[k].
					// Compute 2-norm without under/overflow.
					e[k] = 0;
					for (int i = k+1; i < n; i++)
					{
						e[k] = MathUtils.Hypot(e[k],e[i]);
					}
					if (e[k] != 0.0)
					{
						if (e[k+1] < 0.0)
						{
							e[k] = -e[k];
						}
						for (int i = k+1; i < n; i++)
						{
							e[i] /= e[k];
						}
						e[k+1] += 1.0;
					}
					e[k] = -e[k];
					if ((k+1 < m) & (e[k] != 0.0))
					{

						// Apply the transformation.

						for (int i = k+1; i < m; i++)
						{
							work[i] = 0.0;
						}
						for (int j = k+1; j < n; j++)
						{
							for (int i = k+1; i < m; i++)
							{
								work[i] += e[j]*A[i][j];
							}
						}
						for (int j = k+1; j < n; j++)
						{
							double t = -e[j]/e[k+1];
							for (int i = k+1; i < m; i++)
							{
								A[i][j] += t*work[i];
							}
						}
					}
					if (wantv)
					{

						// Place the transformation in V for subsequent
						// back multiplication.

						for (int i = k+1; i < n; i++)
						{
							V[i][k] = e[i];
						}
					}
				}
			}

			// Set up the final bidiagonal matrix or order p.

			int p = Math.Min(n,m+1);
			if (nct < n)
			{
				s[nct] = A[nct][nct];
			}
			if (m < p)
			{
				s[p-1] = 0.0;
			}
			if (nrt+1 < p)
			{
				e[nrt] = A[nrt][p-1];
			}
			e[p-1] = 0.0;

			// If required, generate U.

			if (wantu)
			{
				for (int j = nct; j < nu; j++)
				{
					for (int i = 0; i < m; i++)
					{
						U[i][j] = 0.0;
					}
					U[j][j] = 1.0;
				}
				for (int k = nct-1; k >= 0; k--)
				{
					if (s[k] != 0.0)
					{
						for (int j = k+1; j < nu; j++)
						{
							double t = 0;
							for (int i = k; i < m; i++)
							{
								t += U[i][k]*U[i][j];
							}
							t = -t/U[k][k];
							for (int i = k; i < m; i++)
							{
								U[i][j] += t*U[i][k];
							}
						}
						for (int i = k; i < m; i++)
						{
							U[i][k] = -U[i][k];
						}
						U[k][k] = 1.0 + U[k][k];
						for (int i = 0; i < k-1; i++)
						{
							U[i][k] = 0.0;
						}
					}
					else
					{
						for (int i = 0; i < m; i++)
						{
							U[i][k] = 0.0;
						}
						U[k][k] = 1.0;
					}
				}
			}

			// If required, generate V.

			if (wantv)
			{
				for (int k = n-1; k >= 0; k--)
				{
					if ((k < nrt) & (e[k] != 0.0))
					{
						for (int j = k+1; j < nu; j++)
						{
							double t = 0;
							for (int i = k+1; i < n; i++)
							{
								t += V[i][k]*V[i][j];
							}
							t = -t/V[k+1][k];
							for (int i = k+1; i < n; i++)
							{
								V[i][j] += t*V[i][k];
							}
						}
					}
					for (int i = 0; i < n; i++)
					{
						V[i][k] = 0.0;
					}
					V[k][k] = 1.0;
				}
			}

			// Main iteration loop for the singular values.

			int pp = p-1;
			int iter = 0;
			double eps = Math.Pow(2.0,-52.0);
			double tiny = Math.Pow(2.0,-966.0);
			while (p > 0)
			{
				int k, kase;

				// Here is where a test for too many iterations would go.

				// This section of the program inspects for
				// negligible elements in the s and e arrays.  On
				// completion the variables kase and k are set as follows.

				// kase = 1     if s(p) and e[k-1] are negligible and k<p
				// kase = 2     if s(k) is negligible and k<p
				// kase = 3     if e[k-1] is negligible, k<p, and
				//              s(k), ..., s(p) are not negligible (qr step).
				// kase = 4     if e(p-1) is negligible (convergence).

				for (k = p-2; k >= -1; k--)
				{
					if (k == -1)
					{
						break;
					}
					if (Math.Abs(e[k]) <= tiny + eps*(Math.Abs(s[k]) + Math.Abs(s[k+1])))
					{
						e[k] = 0.0;
						break;
					}
				}
				if (k == p-2)
				{
					kase = 4;
				}
				else
				{
					int ks;
					for (ks = p-1; ks >= k; ks--)
					{
						if (ks == k)
						{
							break;
						}
						double t = (ks != p ? Math.Abs(e[ks]) : 0.0) + (ks != k+1 ? Math.Abs(e[ks-1]) : 0.0);
						if (Math.Abs(s[ks]) <= tiny + eps*t)
						{
							s[ks] = 0.0;
							break;
						}
					}
					if (ks == k)
					{
						kase = 3;
					}
					else if (ks == p-1)
					{
						kase = 1;
					}
					else
					{
						kase = 2;
						k = ks;
					}
				}
				k++;

				// Perform the task indicated by kase.

				switch (kase)
				{
						// Deflate negligible s(p).
					case 1:
						{
							double f = e[p-2];
							e[p-2] = 0.0;
							for (int j = p-2; j >= k; j--)
							{
								double t = MathUtils.Hypot(s[j],f);
								double cs = s[j]/t;
								double sn = f/t;
								s[j] = t;
								if (j != k)
								{
									f = -sn*e[j-1];
									e[j-1] = cs*e[j-1];
								}
								if (wantv)
								{
									for (int i = 0; i < n; i++)
									{
										t = cs*V[i][j] + sn*V[i][p-1];
										V[i][p-1] = -sn*V[i][j] + cs*V[i][p-1];
										V[i][j] = t;
									}
								}
							}
						}
						break;

						// Split at negligible s(k).

					case 2:
						{
							double f = e[k-1];
							e[k-1] = 0.0;
							for (int j = k; j < p; j++)
							{
								double t = MathUtils.Hypot(s[j],f);
								double cs = s[j]/t;
								double sn = f/t;
								s[j] = t;
								f = -sn*e[j];
								e[j] = cs*e[j];
								if (wantu)
								{
									for (int i = 0; i < m; i++)
									{
										t = cs*U[i][j] + sn*U[i][k-1];
										U[i][k-1] = -sn*U[i][j] + cs*U[i][k-1];
										U[i][j] = t;
									}
								}
							}
						}
						break;

						// Perform one qr step.

					case 3:
						{
							// Calculate the shift.
							double scale = Math.Max(Math.Max(Math.Max(Math.Max(Math.Abs(s[p-1]),Math.Abs(s[p-2])),Math.Abs(e[p-2])), Math.Abs(s[k])),Math.Abs(e[k]));
							double sp = s[p-1]/scale;
							double spm1 = s[p-2]/scale;
							double epm1 = e[p-2]/scale;
							double sk = s[k]/scale;
							double ek = e[k]/scale;
							double b = ((spm1 + sp)*(spm1 - sp) + epm1*epm1)/2.0;
							double c = (sp*epm1)*(sp*epm1);
							double shift = 0.0;
							if ((b != 0.0) | (c != 0.0))
							{
								shift = Math.Sqrt(b*b + c);
								if (b < 0.0)
								{
									shift = -shift;
								}
								shift = c/(b + shift);
							}
							double f = (sk + sp)*(sk - sp) + shift;
							double g = sk*ek;

							// Chase zeros.

							for (int j = k; j < p-1; j++)
							{
								double t = MathUtils.Hypot(f,g);
								double cs = f/t;
								double sn = g/t;
								if (j != k)
								{
									e[j-1] = t;
								}
								f = cs*s[j] + sn*e[j];
								e[j] = cs*e[j] - sn*s[j];
								g = sn*s[j+1];
								s[j+1] = cs*s[j+1];
								if (wantv)
								{
									for (int i = 0; i < n; i++)
									{
										t = cs*V[i][j] + sn*V[i][j+1];
										V[i][j+1] = -sn*V[i][j] + cs*V[i][j+1];
										V[i][j] = t;
									}
								}
								t = MathUtils.Hypot(f,g);
								cs = f/t;
								sn = g/t;
								s[j] = t;
								f = cs*e[j] + sn*s[j+1];
								s[j+1] = -sn*e[j] + cs*s[j+1];
								g = sn*e[j+1];
								e[j+1] = cs*e[j+1];
								if (wantu && (j < m-1))
								{
									for (int i = 0; i < m; i++)
									{
										t = cs*U[i][j] + sn*U[i][j+1];
										U[i][j+1] = -sn*U[i][j] + cs*U[i][j+1];
										U[i][j] = t;
									}
								}
							}
							e[p-2] = f;
							iter = iter + 1;
						}
						break;

						// Convergence.

					case 4:
						{

							// Make the singular values positive.

							if (s[k] <= 0.0)
							{
								s[k] = (s[k] < 0.0 ? -s[k] : 0.0);
								if (wantv)
								{
									for (int i = 0; i <= pp; i++)
									{
										V[i][k] = -V[i][k];
									}
								}
							}

							// Order the singular values.

							while (k < pp)
							{
								if (s[k] >= s[k+1])
								{
									break;
								}
								double t = s[k];
								s[k] = s[k+1];
								s[k+1] = t;
								if (wantv && (k < n-1))
								{
									for (int i = 0; i < n; i++)
									{
										t = V[i][k+1];
										V[i][k+1] = V[i][k];
										V[i][k] = t;
									}
								}
								if (wantu && (k < m-1))
								{
									for (int i = 0; i < m; i++)
									{
										t = U[i][k+1];
										U[i][k+1] = U[i][k];
										U[i][k] = t;
									}
								}
								k++;
							}
							iter = 0;
							p--;
						}
						break;
				}
			}
		}