// ------------------------------------------------------------------------ // // Init function - call prior to start of iterations // // ------------------------------------------------------------------------ void Init(const Matrix<T>& A, DenseMatrix<T>& W, DenseMatrix<T>& H) { WtW.Resize(W.Width(), W.Width()); WtA.Resize(W.Width(), A.Width()); HHt.Resize(H.Height(), H.Height()); AHt.Resize(A.Height(), H.Height()); ScaleFactors.Resize(H.Height(), 1); // compute the kxk matrix WtW = W' * W Gemm(TRANSPOSE, NORMAL, T(1), W, W, T(0), WtW); // compute the kxn matrix WtA = W' * A Gemm(TRANSPOSE, NORMAL, T(1), W, A, T(0), WtA); }
/// Construct a constant matrix coefficient times a scalar Coefficient MatrixFunctionCoefficient(const DenseMatrix &m, Coefficient &q) : MatrixCoefficient(m.Height(), m.Width()), Q(&q) { Function = NULL; TDFunction = NULL; mat = m; }
void OverwriteCols(DenseMatrix<T>& A, const DenseMatrix<T>& B, const std::vector<unsigned int>& col_indices, const unsigned int num_cols) { const unsigned int height = A.Height(); // Overwrite columns of A with B. if (B.Height() != A.Height()) throw std::logic_error("OverwriteCols: height mismatch"); if (num_cols > static_cast<unsigned int>(A.Width())) throw std::logic_error("OverwriteCols: col indices out of bounds"); T* buf_a = A.Buffer(); const unsigned int ldim_a = A.LDim(); const T* buf_b = B.LockedBuffer(); const unsigned int ldim_b = B.LDim(); for (unsigned int c=0; c<num_cols; ++c) { unsigned int col_a = col_indices[c]; unsigned int offset_a = col_a*ldim_a; unsigned int offset_b = c*ldim_b; memcpy(&buf_a[offset_a], &buf_b[offset_b], height * sizeof(T)); } }
bool SolveNormalEq(const DenseMatrix<T>& LHS, // kxk const DenseMatrix<T>& RHS, // kxn DenseMatrix<T>& X) // kxn { // Solve LHS * X = RHS for X, where LHS is assumed SPD. if (LHS.Width() != LHS.Height()) throw std::logic_error("SolveNormalEq: expected square matrix on LHS"); if ( (X.Height() != LHS.Height()) || (X.Width() != RHS.Width())) throw std::logic_error("SolveNormalEq: non-conformant matrix X"); // copy the input, since the solver overwrites it DenseMatrix<T> M(LHS); X = RHS; return SolveNormalEq(M, X); }
void IsoparametricTransformation::Transform (const DenseMatrix &matrix, DenseMatrix &result) { MFEM_ASSERT(matrix.Height() == GetDimension(), "invalid input"); result.SetSize(PointMat.Height(), matrix.Width()); IntegrationPoint ip; Vector col; for (int j = 0; j < matrix.Width(); j++) { ip.Set(matrix.GetColumn(j), matrix.Height()); result.GetColumnReference(j, col); Transform(ip, col); } }
void VisualizationSceneVector3d::PrepareFlat() { int i, j; glNewList (displlist, GL_COMPILE); int nbe = mesh -> GetNBE(); DenseMatrix pointmat; Array<int> vertices; double p[4][3], c[4]; for (i = 0; i < nbe; i++) { if (!bdr_attr_to_show[mesh->GetBdrAttribute(i)-1]) continue; mesh->GetBdrPointMatrix(i, pointmat); mesh->GetBdrElementVertices(i, vertices); for (j = 0; j < pointmat.Width(); j++) { pointmat(0, j) += (*solx)(vertices[j])*(ianim)/ianimmax; pointmat(1, j) += (*soly)(vertices[j])*(ianim)/ianimmax; pointmat(2, j) += (*solz)(vertices[j])*(ianim)/ianimmax; } for (j = 0; j < pointmat.Width(); j++) { p[j][0] = pointmat(0, j); p[j][1] = pointmat(1, j); p[j][2] = pointmat(2, j); c[j] = (*sol)(vertices[j]); } if (j == 3) DrawTriangle(p, c, minv, maxv); else DrawQuad(p, c, minv, maxv); } glEndList(); }
void MakeDiagonallyDominant(DenseMatrix<T>& M) { // Make the diagonal element larger than the row sum, to ensure that // the matrix is nonsingular. All entries in the matrix are nonnegative, // so no absolute values are needed. for (int r=0; r<M.Height(); ++r) { T row_sum = 0.0; for (int c=0; c<M.Width(); ++c) row_sum += M.Get(r, c); M.Set(r, r, row_sum + T(1)); } }
void OptimalActiveSetH(DenseMatrix<T>& H, // 2 x n const DenseMatrix<T>& WtW, // 2 x 2 const DenseMatrix<T>& WtA) // 2 x n { // Remove negative entries in each of the n columns of matrix H, but // do so in a manner that minimizes the overall objective function. // Each column can be considered in isolation. // // The problem for each column i of H, h = H(:,i), is as follows: // // min_{h>=0} |Wh - a|^2 // // This is minimized when h* = w'a / (w'w). Expressed in terms of the // individual elements, this becomes: // // h*[0] = w[0]'a / (w[0]'w[0]) // h*[1] = w[1]'a / (w[1]'w[1]) // If both elements of h* are nonnegative, this is the optimal solution. // If any elements are negative, the Rank2 algorithm is used to adjust // their values. int width = H.Width(); const T wtw_00 = WtW.Get(0,0); const T wtw_11 = WtW.Get(1,1); const T inv_wtw_00 = T(1.0) / wtw_00; const T inv_wtw_11 = T(1.0) / wtw_11; const T sqrt_wtw_00 = sqrt(wtw_00); const T sqrt_wtw_11 = sqrt(wtw_11); for (int i=0; i<width; ++i) { T v1 = WtA.Get(0,i) * inv_wtw_00; T v2 = WtA.Get(1,i) * inv_wtw_11; T vv1 = v1 * sqrt_wtw_00; T vv2 = v2 * sqrt_wtw_11; if (vv1 >= vv2) v2 = T(0); else v1 = T(0); if ( (H.Get(0,i) <= T(0)) || (H.Get(1,i) <= T(0))) { H.Set(0, i, v1); H.Set(1, i, v2); } } }
void IsoparametricTransformation::Transform (const DenseMatrix &matrix, DenseMatrix &result) { result.SetSize(PointMat.Height(), matrix.Width()); IntegrationPoint ip; Vector col; for (int j = 0; j < matrix.Width(); j++) { ip.x = matrix(0, j); if (matrix.Height() > 1) { ip.y = matrix(1, j); if (matrix.Height() > 2) { ip.z = matrix(2, j); } } result.GetColumnReference(j, col); Transform(ip, col); } }
bool HasNaNs(const DenseMatrix<T>& M) { // returns true if any matrix element is NaN int height = M.Height(); int width = M.Width(); for (int c=0; c<width; ++c) { for (int r=0; r<height; ++r) { T elt = M.Get(r, c); if (std::isnan(elt)) return true; } } return false; }
// helper to set submatrix of A repeated vdim times static void SetVDofSubMatrixTranspose(SparseMatrix& A, Array<int>& rows, Array<int>& cols, const DenseMatrix& subm, int vdim) { if (vdim == 1) { A.SetSubMatrixTranspose(rows, cols, subm, 1); } else { int nr = subm.Width(), nc = subm.Height(); for (int d = 0; d < vdim; d++) { Array<int> rows_sub(rows.GetData() + d*nr, nr); // (not owner) Array<int> cols_sub(cols.GetData() + d*nc, nc); // (not owner) A.SetSubMatrixTranspose(rows_sub, cols_sub, subm, 1); } } }
void Overwrite(DenseMatrix<T>& A, const DenseMatrix<T>& B, const std::vector<unsigned int>& row_indices, const std::vector<unsigned int>& col_indices, const unsigned int num_rows, const unsigned int num_cols) { // Overwrite entries in A with entries in B. The row and column // index arrays contain the destination indices to be overwritten. // Matrix B has size num_rows x num_cols. if (num_rows > static_cast<unsigned int>(A.Height())) throw std::logic_error("Overwrite: row indices out of bounds"); if (num_cols > static_cast<unsigned int>(A.Width())) throw std::logic_error("Overwrite: col indices out of bounds"); const T* buf_b = B.LockedBuffer(); const unsigned int ldim_b = B.LDim(); T* buf_a = A.Buffer(); const unsigned int ldim_a = A.LDim(); for (unsigned int c=0; c<num_cols; ++c) { unsigned int col_a = col_indices[c]; unsigned int offset_a = ldim_a * col_a; unsigned int offset_b = ldim_b * c; for (unsigned int r=0; r<num_rows; ++r) { unsigned int row_a = row_indices[r]; //T val = B.Get(r, c); //A.Set(row_a, col_a, val); buf_a[offset_a + row_a] = buf_b[offset_b + r]; } } }
void ZeroizeSmallValues(DenseMatrix<T>& A, const T tol) { // set Aij to zero if |Aij| < tol T* buf = A.Buffer(); const unsigned int ldim = A.LDim(); const unsigned int height = A.Height(); const unsigned int width = A.Width(); OPENMP_PRAGMA(omp parallel for) for (unsigned int c=0; c<width; ++c) { unsigned int col_offset = c*ldim; for (unsigned int r=0; r<height; ++r) { T val = buf[col_offset + r]; if (std::abs(val) < tol) { buf[col_offset + r] = T(0); } } } }
bool SystemSolveH(DenseMatrix<T>& X, // H 2 x n DenseMatrix<T>& A, // WtW 2 x 2 DenseMatrix<T>& B) // WtA 2 x n { // This function solves the system A*X = B for X. The columns of X and B // are treated as separate subproblems. Each subproblem can be expressed // as follows, for column i of X and B (the ' means transpose): // // A * [x0 x1]' = [b0 b1]' // // The solution proceeds by transforming matrix A to upper triangular form // via a fast Givens rotation. The resulting triangular system for the // two unknowns in each column of X is then solved by backsubstitution. // // The fast Givens method relies on the fact that matrix A can be // expressed as the product of a diagonal matrix D and another matrix Y, // and that this form is preserved under the rotation. If J is the // Givens rotation matrix, then: // // AX = B // JAX = JB J is the Givens rotation matrix // (JA)X = JB letting A = D1Y1 // (JD1Y1)X = JB // (D2Y2)X = JB // // The matrix D1 is the identity matrix, and the matrix Y1 is the // original matrix A. The matrix J has the form [c -s; c s] in Matlab // notation. NOTE: with this convention, the tangent has a minus sign: // // t = -A(1, 0) / A(0, 0) // // Matrix A has the form [a b; c d], and after the rotation it is // transformed to [a2 b2; 0 d2]. // // There are two forms for the D2 and Y2 matrices, depending on whether // cosines or sines are 'factored out'. If |A00| >= |A01|, then the // upper left element is factored out and the 'cosine' formulation is // used. If |A00| < |A01|, then the upper right element is factored // out and the 'sine' formulation is used. // // A general reference for this code is the paper 'Fast Plane Rotations // with Dynamic Scaling', by A. Anda and H. Park, SIAM Journal on Matrix // Analysis and Applications, Vol 15, no. 1, pp. 162-174, Jan. 1994. int n = B.Width(); T abs_A00 = std::abs(A.Get(0, 0)); T abs_A01 = std::abs(A.Get(0, 1)); const T epsilon = std::numeric_limits<T>::epsilon(); if ( (abs_A00 < epsilon) && (abs_A01 < epsilon)) { std::cerr << "SystemSolveH: singular matrix" << std::endl; return false; } T a2, b2, d2, e2, f2, inv_a2, inv_d2, x_1; if (abs_A00 >= abs_A01) { // use 'cosine' formulation; t is the tangent T t = -A.Get(1,0) / A.Get(0,0); a2 = A.Get(0,0) - t*A.Get(1,0); b2 = A.Get(0,1) - t*A.Get(1,1); d2 = A.Get(1,1) + t*A.Get(0,1); // precompute 1/a2 and 1/d2 to avoid repeated division inv_a2 = T(1.0) / a2; inv_d2 = T(1.0) / d2; // a2 is guaranteed to be positive if (std::abs(d2/a2) < epsilon) return false; // solve the upper triangular systems by backsubstitution for (int i=0; i<n; ++i) { e2 = B.Get(0,i) - t*B.Get(1,i); f2 = B.Get(1,i) + t*B.Get(0,i); x_1 = f2 * inv_d2; X.Set(1, i, x_1); X.Set(0, i, (e2 - b2*x_1)*inv_a2); } } else { // use 'sine' formulation; ct is the cotangent T ct = -A.Get(0,0) / A.Get(1,0); a2 = -A.Get(1,0) + ct*A.Get(0,0); b2 = -A.Get(1,1) + ct*A.Get(0,1); d2 = A.Get(0,1) + ct*A.Get(1,1); // precompute 1/a2 and 1/d2 to avoid repeated division inv_a2 = T(1.0) / a2; inv_d2 = T(1.0) / d2; // a2 is guaranteed to be positive if (std::abs(d2/a2) < epsilon) return false; // solve the upper triangular systems by backsubstitution for (int i=0; i<n; ++i) { e2 = -B.Get(1,i) + ct*B.Get(0,i); f2 = B.Get(0,i) + ct*B.Get(1,i); x_1 = f2 * inv_d2; X.Set(1, i, x_1); X.Set(0, i, (e2 - b2*x_1) * inv_a2); } } return true; }
void BppUpdateSets(BitMatrix& nonopt_set, BitMatrix& infeas_set, const BitMatrix& not_opt_mask, const DenseMatrix<T>& X, const DenseMatrix<T>& Y, const BitMatrix& passive_set) { // This function performs the equivalent of these operations: // // nonopt_set = not_opt_mask & (Y < T(0)) & ~passive_set; // infeas_set = not_opt_mask & (X < T(0)) & passive_set; const unsigned int height = not_opt_mask.Height(); const unsigned int width = not_opt_mask.Width(); if ( (static_cast<unsigned int>(X.Height()) != height) || (static_cast<unsigned int>(Y.Height()) != height) || (passive_set.Height() != height)) throw std::logic_error("BppUpdateSets: height mismatch"); if ( (static_cast<unsigned int>(X.Width()) != width) || (static_cast<unsigned int>(Y.Width()) != width) || (passive_set.Width() != width)) throw std::logic_error("BppUpdateSets: width mismatch"); nonopt_set.Resize(height, width); infeas_set.Resize(height, width); const unsigned int BITS = BitMatrix::BITS_PER_WORD; const unsigned int MASK = nonopt_set.Mask(); assert(infeas_set.Mask() == MASK); unsigned int* buf_r = nonopt_set.Buffer(); const unsigned int ldim_r = nonopt_set.LDim(); unsigned int* buf_i = infeas_set.Buffer(); const unsigned int ldim_i = infeas_set.LDim(); const unsigned int* buf_m = not_opt_mask.LockedBuffer(); const unsigned int ldim_m = not_opt_mask.LDim(); const T* buf_x = X.LockedBuffer(); const unsigned int ldim_x = X.LDim(); const T* buf_y = Y.LockedBuffer(); const unsigned int ldim_y = Y.LDim(); const unsigned int* buf_p = passive_set.LockedBuffer(); const unsigned int ldim_p = passive_set.LDim(); const unsigned int full_wds = height / BITS; const unsigned int extra = height - BITS*full_wds; assert(ldim_r >= ldim_m); assert(ldim_r >= ldim_p); OPENMP_PRAGMA(omp parallel for) for (unsigned int c=0; c<width; ++c) { unsigned int offset_r = c*ldim_r; unsigned int offset_i = c*ldim_i; unsigned int offset_m = c*ldim_m; unsigned int offset_x = c*ldim_x; unsigned int offset_y = c*ldim_y; unsigned int offset_p = c*ldim_p; unsigned int r_wd = 0, r=0; for (; r_wd<full_wds; ++r_wd) { unsigned int x_wd = 0, y_wd = 0; for (unsigned int q=0; q<BITS; ++q, ++r) { if (buf_x[offset_x + r] < T(0)) x_wd |= (1 << q); if (buf_y[offset_y + r] < T(0)) y_wd |= (1 << q); } buf_r[offset_r + r_wd] = buf_m[offset_m + r_wd] & y_wd & ~buf_p[offset_p + r_wd]; buf_i[offset_i + r_wd] = buf_m[offset_m + r_wd] & x_wd & buf_p[offset_p + r_wd]; } if (extra > 0) { unsigned int x_wd = 0, y_wd = 0; for (unsigned int q=0; q<extra; ++q, ++r) { if (buf_x[offset_x + r] < T(0)) x_wd |= (1 << q); if (buf_y[offset_y + r] < T(0)) y_wd |= (1 << q); } buf_r[offset_r + r_wd] = MASK & buf_m[offset_m + r_wd] & y_wd & ~buf_p[offset_p + r_wd]; buf_i[offset_i + r_wd] = MASK & buf_m[offset_m + r_wd] & x_wd & buf_p[offset_p + r_wd]; } } }
bool NnlsHals(const MatrixType<T>& A, DenseMatrix<T>& W, DenseMatrix<T>& H, const T tol, const bool verbose, const unsigned int max_iter) { unsigned int n = A.Width(); unsigned int k = W.Width(); if (static_cast<unsigned int>(W.Height()) != static_cast<unsigned int>(A.Height())) throw std::logic_error("NnlsHals: W and A must have identical height"); if (static_cast<unsigned int>(H.Width()) != static_cast<unsigned int>(A.Width())) throw std::logic_error("NnlsHals: H and A must have identical width"); if (H.Height() != W.Width()) throw std::logic_error("NnlsHals: non-conformant W and H"); DenseMatrix<T> WtW(k, k), WtA(k, n), WtWH_r(1, n), gradH(k, n); if (verbose) std::cout << "\nRunning NNLS solver..." << std::endl; // compute W'W and W'A for the normal equations Gemm(TRANSPOSE, NORMAL, T(1.0), W, W, T(0.0), WtW); Gemm(TRANSPOSE, NORMAL, T(1.0), W, A, T(0.0), WtA); bool success = false; T pg0 = T(0), pg; for (unsigned int i=0; i<max_iter; ++i) { // compute the new matrix H UpdateH_Hals(H, WtWH_r, WtW, WtA); // compute gradH = WtW*H - WtA Gemm(NORMAL, NORMAL, T(1.0), WtW, H, T(0.0), gradH); Axpy( T(-1.0), WtA, gradH); // compute progress metric if (0 == i) { pg0 = ProjectedGradientNorm(gradH, H); if (verbose) ReportProgress(i+1, T(1.0)); continue; } else { pg = ProjectedGradientNorm(gradH, H); } if (verbose) ReportProgress(i+1, pg/pg0); // check progress vs. desired tolerance if (pg < tol * pg0) { success = true; NormalizeAndScale<T>(W, H); break; } } if (!success) std::cerr << "NNLS solver reached iteration limit." << std::endl; return success; }
bool NnlsBlockpivot(const DenseMatrix<T>& LHS, const DenseMatrix<T>& RHS, DenseMatrix<T>& X, // input as xinit DenseMatrix<T>& Y) // gradX { // Solve (LHS)*X = RHS for X by block principal pivoting. Matrix LHS // is assumed to be symmetric positive definite. const int PBAR = 3; const unsigned int WIDTH = RHS.Width(); const unsigned int HEIGHT = RHS.Height(); const unsigned int MAX_ITER = HEIGHT*5; BitMatrix passive_set = (X > T(0)); std::vector<unsigned int> tmp_indices(WIDTH); for (unsigned int i=0; i<WIDTH; ++i) tmp_indices[i] = i; MakeZeros(X); if (!BppSolveNormalEqNoGroup(tmp_indices, passive_set, LHS, RHS, X)) return false; // Y = LHS * X - RHS Gemm(NORMAL, NORMAL, T(1), LHS, X, T(0), Y); Axpy( T(-1), RHS, Y); std::vector<int> P(WIDTH, PBAR), Ninf(WIDTH, HEIGHT+1); BitMatrix nonopt_set = (Y < T(0)) & ~passive_set; BitMatrix infeas_set = (X < T(0)) & passive_set; std::vector<int> col_sums(WIDTH); std::vector<int> not_good(WIDTH); nonopt_set.SumColumns(not_good); infeas_set.SumColumns(col_sums); not_good += col_sums; BitMatrix not_opt_cols = (not_good > 0); BitMatrix not_opt_mask; std::vector<unsigned int> non_opt_col_indices(WIDTH); not_opt_cols.Find(non_opt_col_indices); DenseMatrix<double> RHSsub(HEIGHT, WIDTH); DenseMatrix<double> Xsub(HEIGHT, WIDTH); DenseMatrix<double> Ysub(HEIGHT, WIDTH); unsigned int iter = 0; while (!non_opt_col_indices.empty()) { // exit if not getting anywhere if (iter >= MAX_ITER) return false; UpdatePassiveSet(passive_set, PBAR, HEIGHT, not_opt_cols, nonopt_set, infeas_set, not_good, P, Ninf); // equivalent of repmat(NotOptCols, HEIGHT, 1) not_opt_mask = MatrixFromColumnMask(not_opt_cols, HEIGHT); // Setup for the normal equation solver by extracting submatrices // from RHS and X. The normal equation solver will extract further // subproblems from RHSsub and Xsub and write all updated values // back into RHSsub and Xsub. RHS.SubmatrixFromCols(RHSsub, non_opt_col_indices); X.SubmatrixFromCols(Xsub, non_opt_col_indices); if (!BppSolveNormalEqNoGroup(non_opt_col_indices, passive_set, LHS, RHSsub, Xsub)) return false; ZeroizeSmallValues(Xsub, 1.0e-12); // compute Ysub = LHS * Xsub - RHSsub Ysub.Resize(RHSsub.Height(), RHSsub.Width()); Gemm(NORMAL, NORMAL, T(1), LHS, Xsub, T(0), Ysub); Axpy( T(-1), RHSsub, Ysub); // update Y and X using the new values in Ysub and Xsub OverwriteCols(Y, Ysub, non_opt_col_indices, non_opt_col_indices.size()); OverwriteCols(X, Xsub, non_opt_col_indices, non_opt_col_indices.size()); ZeroizeSmallValues(X, 1.0e-12); ZeroizeSmallValues(Y, 1.0e-12); // Check optimality - BppUpdateSets does the equivalent of the next two lines. // nonopt_set = not_opt_mask & (Y < T(0)) & ~passive_set; // infeas_set = not_opt_mask & (X < T(0)) & passive_set; BppUpdateSets(nonopt_set, infeas_set, not_opt_mask, X, Y, passive_set); nonopt_set.SumColumns(not_good); infeas_set.SumColumns(col_sums); not_good += col_sums; not_opt_cols = (not_good > 0); not_opt_cols.Find(non_opt_col_indices); ++iter; } return true; }
void VisualizationSceneVector3d::Prepare() { int i,j; switch (shading) { case 0: PrepareFlat(); return; case 2: PrepareFlat2(); return; default: break; } glNewList(displlist, GL_COMPILE); int ne = mesh -> GetNBE(); int nv = mesh -> GetNV(); DenseMatrix pointmat; Array<int> vertices; double nor[3]; Vector nx(nv); Vector ny(nv); Vector nz(nv); for (int d = 0; d < mesh -> bdr_attributes.Size(); d++) { if (!bdr_attr_to_show[mesh -> bdr_attributes[d]-1]) continue; nx=0.; ny=0.; nz=0.; for (i = 0; i < ne; i++) if (mesh -> GetBdrAttribute(i) == mesh -> bdr_attributes[d]) { mesh->GetBdrPointMatrix (i, pointmat); mesh->GetBdrElementVertices (i, vertices); for (j = 0; j < pointmat.Size(); j++) { pointmat(0, j) += (*solx)(vertices[j])*(ianim)/ianimmax; pointmat(1, j) += (*soly)(vertices[j])*(ianim)/ianimmax; pointmat(2, j) += (*solz)(vertices[j])*(ianim)/ianimmax; } if (pointmat.Width() == 3) j = Compute3DUnitNormal(&pointmat(0,0), &pointmat(0,1), &pointmat(0,2), nor); else j = Compute3DUnitNormal(&pointmat(0,0), &pointmat(0,1), &pointmat(0,2), &pointmat(0,3), nor); if (j == 0) for (j = 0; j < pointmat.Size(); j++) { nx(vertices[j]) += nor[0]; ny(vertices[j]) += nor[1]; nz(vertices[j]) += nor[2]; } } for (i = 0; i < ne; i++) if (mesh -> GetBdrAttribute(i) == mesh -> bdr_attributes[d]) { switch (mesh->GetBdrElementType(i)) { case Element::TRIANGLE: glBegin (GL_TRIANGLES); break; case Element::QUADRILATERAL: glBegin (GL_QUADS); break; } mesh->GetBdrPointMatrix (i, pointmat); mesh->GetBdrElementVertices (i, vertices); for (j = 0; j < pointmat.Size(); j++) { pointmat(0, j) += (*solx)(vertices[j])*(ianim)/ianimmax; pointmat(1, j) += (*soly)(vertices[j])*(ianim)/ianimmax; pointmat(2, j) += (*solz)(vertices[j])*(ianim)/ianimmax; } for (j = 0; j < pointmat.Size(); j++) { MySetColor((*sol)(vertices[j]), minv, maxv); glNormal3d(nx(vertices[j]), ny(vertices[j]), nz(vertices[j])); glVertex3dv(&pointmat(0, j)); } glEnd(); } } glEndList(); }
bool SolveNormalEqLeft(const DenseMatrix<T>& LHS, // kxk const DenseMatrix<T>& RHS, // mxk DenseMatrix<T>& X) // mxk { // Solve X * LHS = RHS for X, where LHS is symmetric positive-definite. if (LHS.Width() != LHS.Height()) throw std::logic_error("SolveNormalEqLeft: expected square matrix on LHS"); if ( (X.Width() != LHS.Height()) || (X.Height() != RHS.Height())) throw std::logic_error("SolveNormalEqLeft: non-conformant matrix X"); // // copy the input, since the solver overwrites it DenseMatrix<T> U(LHS); // Compute the Cholesky factor LHS = U'U bool success = true; try { Cholesky(UPPER, U); } catch (EL::NonHPSDMatrixException& e) { std::cerr << "Cholesky factorization failure - "; std::cerr << "matrix was not symmetric positive-definite." << std::endl; success = false; } catch (std::logic_error& e) { std::cerr << "Cholesky factorization failure - "; std::cerr << "matrix was not symmetric positive-definite." << std::endl; success = false; } if (!success) return false; // Solve X (U'U) = RHS as follows: // // Group the two left matrices: // // (XU') U = RHS // // Let Y = XU', so the equation becomes: // // YU = RHS // // Do a triangular solve: Y = (RHS) * inverse(U) X = RHS; Trsm(RIGHT, UPPER, NORMAL, NON_UNIT, T(1), U, X); // The solution Y is stored in X. // // Now solve XU' = Y, so X = Y * inverse(U') Trsm(RIGHT, UPPER, TRANSPOSE, NON_UNIT, T(1), U, X); // check // DenseMatrix<T> temp(m, k); // Gemm(NORMAL, NORMAL, T(1), X, LHS, T(0), temp); // Axpy(-1.0, RHS, temp); // double norm = Norm(temp, FROBENIUS_NORM); // std::cout << "\tSolveNormalEqLeft: norm = " << norm << std::endl; return true; }
MatrixConstantCoefficient(const DenseMatrix &m) : MatrixCoefficient(m.Height(), m.Width()), mat(m) { }