Eigen::SparseMatrix<double> Condi2Joint(Eigen::SparseMatrix<double> Condi, Eigen::SparseVector<double> Pa) { // second dimension of Condi is the parent Eigen::SparseMatrix<double> Joint; Joint.resize(Condi.rows(), Condi.cols()); for (int cols = 0; cols < Condi.cols(); cols++) { Eigen::SparseVector<double> tmp_vec = Condi.block(0, cols, Condi.rows(), 1)*Pa.coeff(cols); for (int id_rows = 0; id_rows < tmp_vec.size(); id_rows++) { Joint.coeffRef(id_rows, cols) = tmp_vec.coeff(id_rows); } } Joint.prune(TOLERANCE); return Joint; }
IGL_INLINE void igl::in_element( const Eigen::PlainObjectBase<DerivedV> & V, const Eigen::MatrixXi & Ele, const Eigen::PlainObjectBase<DerivedQ> & Q, const AABB<DerivedV,DIM> & aabb, Eigen::SparseMatrix<Scalar> & I) { using namespace std; using namespace Eigen; using namespace igl; const int Qr = Q.rows(); std::vector<Triplet<Scalar> > IJV; IJV.reserve(Qr); #pragma omp parallel for if (Qr>10000) for(int e = 0;e<Qr;e++) { // find all const auto R = aabb.find(V,Ele,Q.row(e),false); for(const auto r : R) { #pragma omp critical IJV.push_back(Triplet<Scalar>(e,r,1)); } } I.resize(Qr,Ele.rows()); I.setFromTriplets(IJV.begin(),IJV.end()); }
IGL_INLINE void igl::sparse( const IndexVector & I, const IndexVector & J, const ValueVector & V, const size_t m, const size_t n, Eigen::SparseMatrix<T>& X) { using namespace std; using namespace Eigen; assert((int)I.maxCoeff() < (int)m); assert((int)I.minCoeff() >= 0); assert((int)J.maxCoeff() < (int)n); assert((int)J.minCoeff() >= 0); assert(I.size() == J.size()); assert(J.size() == V.size()); // Really we just need .size() to be the same, but this is safer assert(I.rows() == J.rows()); assert(J.rows() == V.rows()); assert(I.cols() == J.cols()); assert(J.cols() == V.cols()); vector<Triplet<T> > IJV; IJV.reserve(I.size()); for(int x = 0;x<I.size();x++) { IJV.push_back(Triplet<T >(I(x),J(x),V(x))); } X.resize(m,n); X.setFromTriplets(IJV.begin(),IJV.end()); }
void igl::crouzeix_raviart_massmatrix( const Eigen::PlainObjectBase<DerivedV> & V, const Eigen::PlainObjectBase<DerivedF> & F, const Eigen::PlainObjectBase<DerivedE> & E, const Eigen::PlainObjectBase<DerivedEMAP> & EMAP, Eigen::SparseMatrix<MT> & M) { using namespace Eigen; using namespace std; assert(F.cols() == 3); // Mesh should be edge-manifold assert(is_edge_manifold(F)); // number of elements (triangles) int m = F.rows(); // Get triangle areas VectorXd TA; doublearea(V,F,TA); vector<Triplet<MT> > MIJV(3*m); for(int f = 0;f<m;f++) { for(int c = 0;c<3;c++) { MIJV[f+m*c] = Triplet<MT>(EMAP(f+m*c),EMAP(f+m*c),TA(f)*0.5); } } M.resize(E.rows(),E.rows()); M.setFromTriplets(MIJV.begin(),MIJV.end()); }
// fmap case void create_matrix(const paracel::list_type<paracel::str_type> & linelst, Eigen::SparseMatrix<double, Eigen::RowMajor> & blk_mtx, paracel::dict_type<size_t, paracel::str_type> & rm, paracel::dict_type<size_t, paracel::str_type> & cm, paracel::dict_type<size_t, int> & dm, paracel::dict_type<size_t, int> & col_dm) { paracel::scheduler scheduler(m_comm, pattern, mix); // TODO // hash lines into slotslst auto result = scheduler.lines_organize(linelst, parserfunc); std::cout << "procs " << m_comm.get_rank() << " slotslst generated" << std::endl; m_comm.sync(); // alltoall exchange auto stf = scheduler.exchange(result); std::cout << "procs " << m_comm.get_rank() << " get desirable lines" << std::endl; m_comm.sync(); // mapping inds to ids, get rmap, cmap, std_new... paracel::list_type<std::tuple<size_t, size_t, double> > stf_new; scheduler.index_mapping(stf, stf_new, rm, cm, dm, col_dm); std::cout << "procs " << m_comm.get_rank() << " index mapping" << std::endl; // create block sparse matrix paracel::list_type<eigen_triple> nonzero_tpls; for(auto & tpl : stf_new) { nonzero_tpls.push_back(eigen_triple(std::get<0>(tpl), std::get<1>(tpl), std::get<2>(tpl))); } blk_mtx.resize(rm.size(), cm.size()); blk_mtx.setFromTriplets(nonzero_tpls.begin(), nonzero_tpls.end()); }
IGL_INLINE void igl::in_element( const Eigen::MatrixXd & V, const Eigen::MatrixXi & Ele, const Eigen::MatrixXd & Q, const InElementAABB & aabb, Eigen::SparseMatrix<double> & I) { using namespace std; using namespace Eigen; using namespace igl; const int Qr = Q.rows(); std::vector<Triplet<double> > IJV; IJV.reserve(Qr); #pragma omp parallel for for(int e = 0;e<Qr;e++) { // find all const auto R = aabb.find(V,Ele,Q.row(e),false); for(const auto r : R) { #pragma omp critical IJV.push_back(Triplet<double>(e,r,1)); } } I.resize(Qr,Ele.rows()); I.setFromTriplets(IJV.begin(),IJV.end()); }
IGL_INLINE void igl::PolyVectorFieldFinder<DerivedV, DerivedF>::computeCoefficientLaplacian(int n, Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar> > &D) { std::vector<Eigen::Triplet<std::complex<typename DerivedV::Scalar> >> tripletList; // For every non-border edge for (unsigned eid=0; eid<numE; ++eid) { if (!isBorderEdge[eid]) { int fid0 = E2F(eid,0); int fid1 = E2F(eid,1); tripletList.push_back(Eigen::Triplet<std::complex<typename DerivedV::Scalar> >(fid0, fid0, std::complex<typename DerivedV::Scalar>(1.))); tripletList.push_back(Eigen::Triplet<std::complex<typename DerivedV::Scalar> >(fid1, fid1, std::complex<typename DerivedV::Scalar>(1.))); tripletList.push_back(Eigen::Triplet<std::complex<typename DerivedV::Scalar> >(fid0, fid1, -1.*std::polar(1.,-1.*n*K[eid]))); tripletList.push_back(Eigen::Triplet<std::complex<typename DerivedV::Scalar> >(fid1, fid0, -1.*std::polar(1.,1.*n*K[eid]))); } } D.resize(numF,numF); D.setFromTriplets(tripletList.begin(), tripletList.end()); }
void LaplacianOperator::computeLaplacianOperator( Eigen::SparseMatrix<double>& laplacianOperator ) { laplacianOperator.resize(mMeshVertexCount,mMeshVertexCount); laplacianOperator.reserve(Eigen::VectorXi::Constant(mMeshVertexCount,10)); for (int i = 0; i < mMeshVertexCount; i++) { /* 如果第i个点没有邻接点,即它是一个孤立的点,那么它的laplacian坐标为0 */ if( adjacentMatrix.innerVector(i).nonZeros() == 0) { laplacianOperator.insert(i,i) = 0; continue; } laplacianOperator.insert(i,i) = 1; #ifdef MY_DEBUG int adjCount = 0; #endif for (Eigen::SparseMatrix<double>::InnerIterator it(adjacentMatrix,i); it; it++) { if(i != it.row()) { laplacianOperator.insert(i,it.row()) = -1/degreeMatrix(i); #ifdef MY_DEBUG adjCount++; if(adjCount >= 10) printf("InnerVector size should expand! CurrentMax:%d.\n",adjCount); #endif } } } }
void CodeAtlas::FuzzyDependBuilder::buildChildDepend( QMultiHash<QString, ChildPack>& childList , Eigen::SparseMatrix<double>& vtxEdgeMat, Eigen::VectorXd& edgeWeightVec, QList<FuzzyDependAttr::DependPair>& dependPair) { QStringList codeList; QVector<ChildPack*> childPackPtr; for (QMultiHash<QString, ChildPack>::Iterator pChild = childList.begin(); pChild != childList.end(); ++pChild) { codeList.push_back(pChild.value().m_code); childPackPtr.push_back(&pChild.value()); } std::vector<Triplet> tripletArray; QVector<double> edgeWeightArray; // add dependency edges between child nodes int ithSrc = 0; for (QMultiHash<QString, ChildPack>::Iterator pChild = childList.begin(); pChild != childList.end(); ++pChild, ++ithSrc) { // for each child, find number of occurrences of this child's name ChildPack& srcChild = pChild.value(); const QString& srcName = pChild.key(); QVector<int> occurence; WordExtractor::findOccurrence(srcName, codeList, occurence); for (int ithTar = 0; ithTar < childPackPtr.size(); ++ithTar) { int nOccur = occurence[ithTar]; if (nOccur == 0 || ithTar == ithSrc) continue; ChildPack& tarChild = *childPackPtr[ithTar]; SymbolEdge::Ptr pEdge = SymbolTree::getOrAddEdge(srcChild.m_pNode, tarChild.m_pNode, SymbolEdge::EDGE_FUZZY_DEPEND); pEdge->clear(); pEdge->strength() = nOccur; int nEdge = tripletArray.size()/2; tripletArray.push_back(Triplet(srcChild.m_index, nEdge ,1.0)); tripletArray.push_back(Triplet(tarChild.m_index, nEdge ,-1.0)); edgeWeightArray.push_back(nOccur); dependPair.push_back(FuzzyDependAttr::DependPair(srcChild.m_pNode, tarChild.m_pNode, nOccur)); } } if (int nEdges = tripletArray.size()/2) { vtxEdgeMat.resize(childList.size(),nEdges); vtxEdgeMat.setFromTriplets(tripletArray.begin(), tripletArray.end()); edgeWeightVec.resize(nEdges); memcpy(edgeWeightVec.data(), edgeWeightArray.data(), sizeof(double)* nEdges); } }
void testEigen(int m, int n, int nnz, std::vector<int>& rows, std::vector<int>& cols, std::vector<double>& values, double* matB){ double start, stop, time_to_solve, time_to_build; double tol=1e-9; Eigen::SparseMatrix<double> A; std::vector< Eigen::Triplet<double> > trips; trips.reserve(m * n); for (int k = 0; k < nnz; k++){ double _val = values[k]; int i = rows[k]; int j = cols[k]; if (fabs(_val) > tol){ trips.push_back(Eigen::Triplet<double>(i-1,j-1,_val)); } } //NOTE: setFromTriples() accumulates contributions to the same (i,j)! A.resize(m, n); start = second(); A.setFromTriplets(trips.begin(), trips.end()); stop = second(); time_to_build = stop - start; Eigen::SparseLU< Eigen::SparseMatrix<double>, Eigen::COLAMDOrdering<int> > solverLU; Eigen::VectorXd b; b.resize(m); for (int i = 0; i < m; i++ ) b(i) = matB[i]; printf("\nProcessing in Eigen using LU...\n"); start = second(); solverLU.compute(A); Eigen::VectorXd X = solverLU.solve(b); stop = second(); time_to_solve = stop - start; Eigen::VectorXd ax = A * X; Eigen::VectorXd bMinusAx = b - ax; double h_r[m]; for (int i=0; i<m; i++) h_r[i]=bMinusAx(i); double r_inf = vec_norminf(m, h_r); printf("(Eigen) |b - A*x| = %E \n", r_inf); printf("(Eigen) Time to build(sec): %f\n", time_to_build); printf("(Eigen) Time (sec): %f\n", time_to_solve); }
inline void space_operator( Eigen::SparseMatrix<double>& result, Eigen::SparseMatrix<double>& laplace, const double multiplier, Eigen::SparseMatrix<double>& unit_matrix) { result.resize(unit_matrix.rows(), unit_matrix.cols()); result = laplace*multiplier+unit_matrix; }
IGL_INLINE void igl::repdiag( const Eigen::SparseMatrix<T>& A, const int d, Eigen::SparseMatrix<T>& B) { using namespace std; using namespace Eigen; int m = A.rows(); int n = A.cols(); vector<Triplet<T> > IJV; IJV.reserve(A.nonZeros()*d); // Loop outer level for (int k=0; k<A.outerSize(); ++k) { // loop inner level for (typename Eigen::SparseMatrix<T>::InnerIterator it(A,k); it; ++it) { for(int i = 0;i<d;i++) { IJV.push_back(Triplet<T>(i*m+it.row(),i*n+it.col(),it.value())); } } } B.resize(m*d,n*d); B.setFromTriplets(IJV.begin(),IJV.end()); // Q: Why is this **Very** slow? //int m = A.rows(); //int n = A.cols(); //B.resize(m*d,n*d); //// Reserve enough space for new non zeros //B.reserve(d*A.nonZeros()); //// loop over reps //for(int i=0;i<d;i++) //{ // // Loop outer level // for (int k=0; k<A.outerSize(); ++k) // { // // loop inner level // for (typename Eigen::SparseMatrix<T>::InnerIterator it(A,k); it; ++it) // { // B.insert(i*m+it.row(),i*n+it.col()) = it.value(); // } // } //} //B.makeCompressed(); }
IGL_INLINE void igl::adjacency_matrix( const Eigen::PlainObjectBase<DerivedF> & F, Eigen::SparseMatrix<T>& A) { using namespace std; using namespace Eigen; typedef typename DerivedF::Scalar Index; typedef Triplet<T> IJV; vector<IJV > ijv; ijv.reserve(F.size()*2); // Loop over faces for(int i = 0;i<F.rows();i++) { // Loop over this face for(int j = 0;j<F.cols();j++) { // Get indices of edge: s --> d Index s = F(i,j); Index d = F(i,(j+1)%F.cols()); ijv.push_back(IJV(s,d,1)); ijv.push_back(IJV(d,s,1)); } } const Index n = F.maxCoeff()+1; A.resize(n,n); switch(F.cols()) { case 3: A.reserve(6*(F.maxCoeff()+1)); break; case 4: A.reserve(26*(F.maxCoeff()+1)); break; } A.setFromTriplets(ijv.begin(),ijv.end()); // Force all non-zeros to be one // Iterate over outside for(int k=0; k<A.outerSize(); ++k) { // Iterate over inside for(typename Eigen::SparseMatrix<T>::InnerIterator it (A,k); it; ++it) { assert(it.value() != 0); A.coeffRef(it.row(),it.col()) = 1; } } }
IGL_INLINE bool igl::GeneralPolyVectorFieldFinder<DerivedV, DerivedF>:: solve(const Eigen::VectorXi &isConstrained, const Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, Eigen::Dynamic> &cfW, const Eigen::VectorXi &rootsIndex, Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, Eigen::Dynamic> &output) { // polynomial is of the form: // z^(2n) + // -c[0]z^(2n-1) + // c[1]z^(2n-2) + // -c[2]z^(2n-3) + // ... + // (-1)^n c[n-1] std::vector<Eigen::Matrix<std::complex<typename DerivedV::Scalar>, Eigen::Dynamic,1>> coeffs(n,Eigen::Matrix<std::complex<typename DerivedV::Scalar>, Eigen::Dynamic,1>::Zero(numF, 1)); for (int i =0; i<n; ++i) { int degree = i+1; Eigen::Matrix<std::complex<typename DerivedV::Scalar>, Eigen::Dynamic,1> Ck; getGeneralCoeffConstraints(isConstrained, cfW, i, rootsIndex, Ck); Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar> > DD; computeCoefficientLaplacian(degree, DD); Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar> > f; f.resize(numF,1); if (isConstrained.sum() == numF) coeffs[i] = Ck; else minQuadWithKnownMini(DD, f, isConstrained, Ck, coeffs[i]); } std::vector<Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 2> > pv; setFieldFromGeneralCoefficients(coeffs, pv); output.setZero(numF,3*n); for (int fi=0; fi<numF; ++fi) { const Eigen::Matrix<typename DerivedV::Scalar, 1, 3> &b1 = B1.row(fi); const Eigen::Matrix<typename DerivedV::Scalar, 1, 3> &b2 = B2.row(fi); for (int i=0; i<n; ++i) output.block(fi,3*i, 1, 3) = pv[i](fi,0)*b1 + pv[i](fi,1)*b2; } return true; }
void Mesh::buildMassMatrix(const VectorXd &q, Eigen::SparseMatrix<double> &M) const { M.resize(numdofs(), numdofs()); vector<Tr> entries; for(OMMesh::VertexIter vi = mesh_->vertices_begin(); vi != mesh_->vertices_end(); ++vi) { int vidx = vi.handle().idx(); double area = barycentricDualArea(q, vidx); for(int i=0; i<3; i++) entries.push_back(Tr(3*vidx+i, 3*vidx+i, area)); } M.setFromTriplets(entries.begin(), entries.end()); }
inline void identity_operator( Eigen::SparseMatrix<double>& result, int size) { result.resize(size, size); result.reserve(size); std::vector<double_triplet_t> matrix_coeffs; matrix_coeffs.reserve(size); // #diag // diag for (int i = 0; i < size; ++i) matrix_coeffs.push_back(double_triplet_t(i,i, 1.)); result.setFromTriplets(matrix_coeffs.begin(), matrix_coeffs.end()); }
inline void igl::PlanarizerShapeUp<DerivedV, DerivedF>::assembleSelector(int fi, Eigen::SparseMatrix<typename DerivedV::Scalar > &S) { std::vector<Eigen::Triplet<typename DerivedV::Scalar>> tripletList; for (int fvi = 0; fvi< ni; fvi++) { int vi = Fin(fi,fvi); tripletList.push_back(Eigen::Triplet<typename DerivedV::Scalar>(3*fvi+0,3*vi+0,1.)); tripletList.push_back(Eigen::Triplet<typename DerivedV::Scalar>(3*fvi+1,3*vi+1,1.)); tripletList.push_back(Eigen::Triplet<typename DerivedV::Scalar>(3*fvi+2,3*vi+2,1.)); } S.resize(3*ni,3*numV); S.setFromTriplets(tripletList.begin(), tripletList.end()); }
inline void laplace_operator_1d( Eigen::SparseMatrix<double>& result, int size) { result.resize(size, size); result.reserve(size*3-2); std::vector<double_triplet_t> matrix_coeffs; matrix_coeffs.reserve(size*3-2); // #diag + #diag(-1) + #diag(+1) // diag for (int i = 0; i < size; ++i) matrix_coeffs.push_back(double_triplet_t(i,i, -2.)); // diag(-1) for (int i = 1; i < size; ++i) matrix_coeffs.push_back(double_triplet_t(i,i-1, 1.)); // diag(+1) for (int i = 0; i < size-1; ++i) matrix_coeffs.push_back(double_triplet_t(i,i+1, 1.)); result.setFromTriplets(matrix_coeffs.begin(), matrix_coeffs.end()); }
IGL_INLINE void igl::sparse( const IndexVector & I, const IndexVector & J, const ValueVector & V, const size_t m, const size_t n, Eigen::SparseMatrix<T>& X) { using namespace std; using namespace Eigen; assert((int)I.maxCoeff() < (int)m); assert((int)I.minCoeff() >= 0); assert((int)J.maxCoeff() < (int)n); assert((int)J.minCoeff() >= 0); assert(I.size() == J.size()); assert(J.size() == V.size()); // Really we just need .size() to be the same, but this is safer assert(I.rows() == J.rows()); assert(J.rows() == V.rows()); assert(I.cols() == J.cols()); assert(J.cols() == V.cols()); //// number of values //int nv = V.size(); //Eigen::DynamicSparseMatrix<T, Eigen::RowMajor> dyn_X(m,n); //// over estimate the number of entries //dyn_X.reserve(I.size()); //for(int i = 0;i < nv;i++) //{ // dyn_X.coeffRef((int)I(i),(int)J(i)) += (T)V(i); //} //X = Eigen::SparseMatrix<T>(dyn_X); vector<Triplet<T> > IJV; IJV.reserve(I.size()); for(int x = 0;x<I.size();x++) { IJV.push_back(Triplet<T >(I(x),J(x),V(x))); } X.resize(m,n); X.setFromTriplets(IJV.begin(),IJV.end()); }
Eigen::SparseMatrix<double> joint2conditional(Eigen::SparseMatrix<double> edgePot)// pa is the second dimension { // second dimension of edgePot is the parent Eigen::SparseMatrix<double> Conditional; Conditional.resize(edgePot.rows(), edgePot.cols()); Eigen::SparseVector<double> Parent_Marginal; Parent_Marginal.resize(edgePot.cols()); for (int id_col = 0; id_col < edgePot.cols(); id_col++) { Eigen::SparseVector<double> tmp_vec = edgePot.block(0, id_col, edgePot.rows(), 1); Parent_Marginal.coeffRef(id_col) = tmp_vec.sum(); if (Parent_Marginal.coeff(id_col)>TOLERANCE) for (int id_row = 0; id_row < edgePot.rows(); id_row++) { Conditional.coeffRef(id_row, id_col) = edgePot.coeff(id_row, id_col) / Parent_Marginal.coeff(id_col); } } Conditional.makeCompressed(); Conditional.prune(TOLERANCE); return Conditional; }
IGL_INLINE void igl::sparse( const Eigen::PlainObjectBase<DerivedD>& D, Eigen::SparseMatrix<T>& X) { assert(false && "Obsolete. Just call D.sparseView() directly"); using namespace std; using namespace Eigen; vector<Triplet<T> > DIJV; const int m = D.rows(); const int n = D.cols(); for(int i = 0;i<m;i++) { for(int j = 0;j<n;j++) { if(D(i,j)!=0) { DIJV.push_back(Triplet<T>(i,j,D(i,j))); } } } X.resize(m,n); X.setFromTriplets(DIJV.begin(),DIJV.end()); }
IGL_INLINE void igl::arap_linear_block_spokes( const MatV & V, const MatF & F, const int d, Eigen::SparseMatrix<Scalar> & Kd) { using namespace std; using namespace Eigen; // simplex size (3: triangles, 4: tetrahedra) int simplex_size = F.cols(); // Number of elements int m = F.rows(); // Temporary output Matrix<int,Dynamic,2> edges; Kd.resize(V.rows(), V.rows()); vector<Triplet<Scalar> > Kd_IJV; if(simplex_size == 3) { // triangles Kd.reserve(7*V.rows()); Kd_IJV.reserve(7*V.rows()); edges.resize(3,2); edges << 1,2, 2,0, 0,1; }else if(simplex_size == 4) { // tets Kd.reserve(17*V.rows()); Kd_IJV.reserve(17*V.rows()); edges.resize(6,2); edges << 1,2, 2,0, 0,1, 3,0, 3,1, 3,2; } // gather cotangent weights Matrix<Scalar,Dynamic,Dynamic> C; cotmatrix_entries(V,F,C); // should have weights for each edge assert(C.cols() == edges.rows()); // loop over elements for(int i = 0;i<m;i++) { // loop over edges of element for(int e = 0;e<edges.rows();e++) { int source = F(i,edges(e,0)); int dest = F(i,edges(e,1)); double v = 0.5*C(i,e)*(V(source,d)-V(dest,d)); Kd_IJV.push_back(Triplet<Scalar>(source,dest,v)); Kd_IJV.push_back(Triplet<Scalar>(dest,source,-v)); Kd_IJV.push_back(Triplet<Scalar>(source,source,v)); Kd_IJV.push_back(Triplet<Scalar>(dest,dest,-v)); } } Kd.setFromTriplets(Kd_IJV.begin(),Kd_IJV.end()); Kd.makeCompressed(); }
void Poisson_LIMSolver2D::prepareProblemData(std::vector<int>& hessRowIdx, std::vector<int>& hessColIdx) { const int numNodes = mesh->InitalVertices->rows(); // create sparse gradient operator matrix Eigen::SparseMatrix<double> tempG; Eigen::VectorXd dAreas,dAreasTemp; Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic> vertices(*mesh->DeformedVertices); Eigen::Matrix<int,Eigen::Dynamic,Eigen::Dynamic> faces(*mesh->Triangles); igl::grad(vertices,faces,tempG); // Only get x and y derivatives of elements as z is zero int newRowSize = 2.0/3.0*tempG.rows(); std::vector<Eigen::Triplet<double> > triplets; for (int k=0;k<tempG.outerSize();++k) { for (Eigen::SparseMatrix<double>::InnerIterator it(tempG,k);it;++it) { int row = it.row(); int col = it.col(); if(row < newRowSize) { triplets.push_back(Eigen::Triplet<double>(row,col,it.value())); } } } tempG.setZero(); tempG.resize(newRowSize,tempG.cols()); tempG.setFromTriplets(triplets.begin(), triplets.end()); // Extend gradient operator matrix for x and y scalar function triplets.clear(); G.resize(newRowSize*2,tempG.cols()*2); for (int k=0;k<tempG.outerSize();++k) { for (Eigen::SparseMatrix<double>::InnerIterator it(tempG,k);it;++it) { int row = it.row()*2; int col = it.col()*2; triplets.push_back(Eigen::Triplet<double>(row,col,it.value())); triplets.push_back(Eigen::Triplet<double>(row+1,col+1,it.value())); } } G.setFromTriplets(triplets.begin(), triplets.end()); // Compute area weights Eigen::SparseMatrix<double> M; igl::doublearea(vertices,faces,dAreas); triplets.clear(); M.resize(dAreas.rows()*4,dAreas.rows()*4); for(int r=0;r<dAreas.rows();r++) { int id = 4*r; triplets.push_back(Eigen::Triplet<double>(id,id,dAreas(r))); triplets.push_back(Eigen::Triplet<double>(id+1,id+1,dAreas(r))); triplets.push_back(Eigen::Triplet<double>(id+2,id+2,dAreas(r))); triplets.push_back(Eigen::Triplet<double>(id+3,id+3,dAreas(r))); } M.setFromTriplets(triplets.begin(),triplets.end()); // Compute laplacian L = 0.5*G.transpose()*M*G; for (int k=0;k<L.outerSize();++k) { for (Eigen::SparseMatrix<double>::InnerIterator it(L,k);it;++it) { int row = it.row(); int col = it.col(); // std::sort for upper triangule matrix if(row <= col) { hessRowIdx.push_back(row); hessColIdx.push_back(col); } } } GTb = 0.5*G.transpose()*M*b; constantEnergyPart = b.transpose()*b; }
void serialization_test() { std::string file("test"); bool tbIn = true,tbOut; char tcIn = 't',tcOut; unsigned char tucIn = 'u',tucOut; short tsIn = 6,tsOut; int tiIn = -10,tiOut; unsigned int tuiIn = 10,tuiOut; float tfIn = 1.0005,tfOut; double tdIn = 1.000000005,tdOut; int* tinpIn = NULL,*tinpOut = NULL; float* tfpIn = new float,*tfpOut = NULL; *tfpIn = 1.11101; std::string tstrIn("test12345"),tstrOut; Test2 tObjIn,tObjOut; int ti = 2; tObjIn.ti = &ti; Test1 test1,test2,test3; test1.ts = "100"; test2.ts = "200"; test3.ts = "300"; Test1 testA, testC; testA.tt = &test1; testA.ts = "test123"; testA.tvt.push_back(&test2); testA.tvt.push_back(&test3); Test1 testB = testA; testB.ts = "400"; testB.tvt.pop_back(); std::pair<int,bool> tPairIn(10,true); std::pair<int,bool> tPairOut; std::vector<int> tVector1In ={1,2,3,4,5}; std::vector<int> tVector1Out; std::pair<int,bool> p1(10,1); std::pair<int,bool> p2(1,0); std::pair<int,bool> p3(10000,1); std::vector<std::pair<int,bool> > tVector2In ={p1,p2,p3}; std::vector<std::pair<int,bool> > tVector2Out; std::set<std::pair<int,bool> > tSetIn ={p1,p2,p3}; std::set<std::pair<int,bool> > tSetOut; std::map<int,bool> tMapIn ={p1,p2,p3}; std::map<int,bool> tMapOut; Eigen::Matrix<float,3,3> tDenseMatrixIn; tDenseMatrixIn << Eigen::Matrix<float,3,3>::Random(); tDenseMatrixIn.coeffRef(0,0) = 1.00001; Eigen::Matrix<float,3,3> tDenseMatrixOut; Eigen::Matrix<float,3,3,Eigen::RowMajor> tDenseRowMatrixIn; tDenseRowMatrixIn << Eigen::Matrix<float,3,3,Eigen::RowMajor>::Random(); Eigen::Matrix<float,3,3,Eigen::RowMajor> tDenseRowMatrixOut; Eigen::SparseMatrix<double> tSparseMatrixIn; tSparseMatrixIn.resize(3,3); tSparseMatrixIn.insert(0,0) = 1.3; tSparseMatrixIn.insert(1,1) = 10.2; tSparseMatrixIn.insert(2,2) = 100.1; tSparseMatrixIn.finalize(); Eigen::SparseMatrix<double> tSparseMatrixOut; // binary serialization igl::serialize(tbIn,file); igl::deserialize(tbOut,file); assert(tbIn == tbOut); igl::serialize(tcIn,file); igl::deserialize(tcOut,file); assert(tcIn == tcOut); igl::serialize(tucIn,file); igl::deserialize(tucOut,file); assert(tucIn == tucOut); igl::serialize(tsIn,file); igl::deserialize(tsOut,file); assert(tsIn == tsOut); igl::serialize(tiIn,file); igl::deserialize(tiOut,file); assert(tiIn == tiOut); igl::serialize(tuiIn,file); igl::deserialize(tuiOut,file); assert(tuiIn == tuiOut); igl::serialize(tfIn,file); igl::deserialize(tfOut,file); assert(tfIn == tfOut); igl::serialize(tdIn,file); igl::deserialize(tdOut,file); assert(tdIn == tdOut); igl::serialize(tinpIn,file); igl::deserialize(tinpOut,file); assert(tinpIn == tinpOut); igl::serialize(tfpIn,file); igl::deserialize(tfpOut,file); assert(*tfpIn == *tfpOut); tfpOut = NULL; igl::serialize(tstrIn,file); igl::deserialize(tstrOut,file); assert(tstrIn == tstrOut); // updating igl::serialize(tbIn,"tb",file,true); igl::serialize(tcIn,"tc",file); igl::serialize(tiIn,"ti",file); tiIn++; igl::serialize(tiIn,"ti",file); tiIn++; igl::serialize(tiIn,"ti",file); igl::deserialize(tbOut,"tb",file); igl::deserialize(tcOut,"tc",file); igl::deserialize(tiOut,"ti",file); assert(tbIn == tbOut); assert(tcIn == tcOut); assert(tiIn == tiOut); igl::serialize(tsIn,"tsIn",file,true); igl::serialize(tVector1In,"tVector1In",file); igl::serialize(tVector2In,"tsIn",file); igl::deserialize(tVector2Out,"tsIn",file); for(unsigned int i=0;i<tVector2In.size();i++) { assert(tVector2In[i].first == tVector2Out[i].first); assert(tVector2In[i].second == tVector2Out[i].second); } tVector2Out.clear(); igl::serialize(tObjIn,file); igl::deserialize(tObjOut,file); assert(tObjIn.tc == tObjOut.tc); assert(*tObjIn.ti == *tObjOut.ti); for(unsigned int i=0;i<tObjIn.tvb.size();i++) assert(tObjIn.tvb[i] == tObjOut.tvb[i]); tObjOut.ti = NULL; igl::serialize(tPairIn,file); igl::deserialize(tPairOut,file); assert(tPairIn.first == tPairOut.first); assert(tPairIn.second == tPairOut.second); igl::serialize(tVector1In,file); igl::deserialize(tVector1Out,file); for(unsigned int i=0;i<tVector1In.size();i++) assert(tVector1In[i] == tVector1Out[i]); igl::serialize(tVector2In,file); igl::deserialize(tVector2Out,file); for(unsigned int i=0;i<tVector2In.size();i++) { assert(tVector2In[i].first == tVector2Out[i].first); assert(tVector2In[i].second == tVector2Out[i].second); } igl::serialize(tSetIn,file); igl::deserialize(tSetOut,file); assert(tSetIn.size() == tSetOut.size()); igl::serialize(tMapIn,file); igl::deserialize(tMapOut,file); assert(tMapIn.size() == tMapOut.size()); igl::serialize(tDenseMatrixIn,file); igl::deserialize(tDenseMatrixOut,file); assert((tDenseMatrixIn - tDenseMatrixOut).sum() == 0); igl::serialize(tDenseRowMatrixIn,file); igl::deserialize(tDenseRowMatrixOut,file); assert((tDenseRowMatrixIn - tDenseRowMatrixOut).sum() == 0); igl::serialize(tSparseMatrixIn,file); igl::deserialize(tSparseMatrixOut,file); assert((tSparseMatrixIn - tSparseMatrixOut).sum() == 0); igl::serialize(testB,file); igl::deserialize(testC,file); assert(testB.ts == testC.ts); assert(testB.tvt.size() == testC.tvt.size()); for(unsigned int i=0;i<testB.tvt.size();i++) { assert(testB.tvt[i]->ts == testC.tvt[i]->ts); assert(testB.tvt[i]->tvt.size() == testC.tvt[i]->tvt.size()); assert(testB.tvt[i]->tt == testC.tvt[i]->tt); } assert(testB.tt->ts == testC.tt->ts); assert(testB.tt->tvt.size() == testC.tt->tvt.size()); assert(testB.tt->tt == testC.tt->tt); testC = Test1(); // big data test /*std::vector<std::vector<float> > bigDataIn,bigDataOut; for(unsigned int i=0;i<10000;i++) { std::vector<float> v; for(unsigned int j=0;j<10000;j++) { v.push_back(j); } bigDataIn.push_back(v); } igl::Timer timer; timer.start(); igl::serialize(bigDataIn,file); timer.stop(); std::cout << "ser: " << timer.getElapsedTimeInMilliSec() << std::endl; timer.start(); igl::deserialize(bigDataOut,file); timer.stop(); std::cout << "des: " << timer.getElapsedTimeInMilliSec() << std::endl; char c; std::cin >> c; */ // xml serialization igl::serialize_xml(tbIn,file); igl::deserialize_xml(tbOut,file); assert(tbIn == tbOut); igl::serialize_xml(tcIn,file); igl::deserialize_xml(tcOut,file); assert(tcIn == tcOut); igl::serialize_xml(tucIn,file); igl::deserialize_xml(tucOut,file); assert(tucIn == tucOut); igl::serialize_xml(tsIn,file); igl::deserialize_xml(tsOut,file); assert(tsIn == tsOut); igl::serialize_xml(tiIn,file); igl::deserialize_xml(tiOut,file); assert(tiIn == tiOut); igl::serialize_xml(tuiIn,file); igl::deserialize_xml(tuiOut,file); assert(tuiIn == tuiOut); igl::serialize_xml(tfIn,file); igl::deserialize_xml(tfOut,file); assert(tfIn == tfOut); igl::serialize_xml(tdIn,file); igl::deserialize_xml(tdOut,file); assert(tdIn == tdOut); igl::serialize_xml(tinpIn,file); igl::deserialize_xml(tinpOut,file); assert(tinpIn == tinpOut); igl::serialize_xml(tfpIn,file); igl::deserialize_xml(tfpOut,file); assert(*tfpIn == *tfpOut); igl::serialize_xml(tstrIn,file); igl::deserialize_xml(tstrOut,file); assert(tstrIn == tstrOut); // updating igl::serialize_xml(tbIn,"tb",file,false,true); igl::serialize_xml(tcIn,"tc",file); igl::serialize_xml(tiIn,"ti",file); tiIn++; igl::serialize_xml(tiIn,"ti",file); tiIn++; igl::serialize_xml(tiIn,"ti",file); igl::deserialize_xml(tbOut,"tb",file); igl::deserialize_xml(tcOut,"tc",file); igl::deserialize_xml(tiOut,"ti",file); assert(tbIn == tbOut); assert(tcIn == tcOut); assert(tiIn == tiOut); igl::serialize_xml(tsIn,"tsIn",file,false,true); igl::serialize_xml(tVector1In,"tVector1In",file); igl::serialize_xml(tVector2In,"tsIn",file); igl::deserialize_xml(tVector2Out,"tsIn",file); for(unsigned int i=0;i<tVector2In.size();i++) { assert(tVector2In[i].first == tVector2Out[i].first); assert(tVector2In[i].second == tVector2Out[i].second); } tVector2Out.clear(); // binarization igl::serialize_xml(tVector2In,"tVector2In",file,true); igl::deserialize_xml(tVector2Out,"tVector2In",file); for(unsigned int i=0;i<tVector2In.size();i++) { assert(tVector2In[i].first == tVector2Out[i].first); assert(tVector2In[i].second == tVector2Out[i].second); } igl::serialize_xml(tObjIn,file); igl::deserialize_xml(tObjOut,file); assert(tObjIn.tc == tObjOut.tc); assert(*tObjIn.ti == *tObjOut.ti); for(unsigned int i=0;i<tObjIn.tvb.size();i++) assert(tObjIn.tvb[i] == tObjOut.tvb[i]); igl::serialize_xml(tPairIn,file); igl::deserialize_xml(tPairOut,file); assert(tPairIn.first == tPairOut.first); assert(tPairIn.second == tPairOut.second); igl::serialize_xml(tVector1In,file); igl::deserialize_xml(tVector1Out,file); for(unsigned int i=0;i<tVector1In.size();i++) assert(tVector1In[i] == tVector1Out[i]); igl::serialize_xml(tVector2In,file); igl::deserialize_xml(tVector2Out,file); for(unsigned int i=0;i<tVector2In.size();i++) { assert(tVector2In[i].first == tVector2Out[i].first); assert(tVector2In[i].second == tVector2Out[i].second); } igl::serialize_xml(tSetIn,file); igl::deserialize_xml(tSetOut,file); assert(tSetIn.size() == tSetOut.size()); igl::serialize_xml(tMapIn,file); igl::deserialize_xml(tMapOut,file); assert(tMapIn.size() == tMapOut.size()); igl::serialize_xml(tDenseMatrixIn,file); igl::deserialize_xml(tDenseMatrixOut,file); assert((tDenseMatrixIn - tDenseMatrixOut).sum() == 0); igl::serialize_xml(tDenseRowMatrixIn,file); igl::deserialize_xml(tDenseRowMatrixOut,file); assert((tDenseRowMatrixIn - tDenseRowMatrixOut).sum() == 0); igl::serialize_xml(tSparseMatrixIn,file); igl::deserialize_xml(tSparseMatrixOut,file); assert((tSparseMatrixIn - tSparseMatrixOut).sum() == 0); igl::serialize_xml(testB,file); igl::deserialize_xml(testC,file); assert(testB.ts == testC.ts); assert(testB.tvt.size() == testC.tvt.size()); for(unsigned int i=0;i<testB.tvt.size();i++) { assert(testB.tvt[i]->ts == testC.tvt[i]->ts); assert(testB.tvt[i]->tvt.size() == testC.tvt[i]->tvt.size()); assert(testB.tvt[i]->tt == testC.tvt[i]->tt); } assert(testB.tt->ts == testC.tt->ts); assert(testB.tt->tvt.size() == testC.tt->tvt.size()); assert(testB.tt->tt == testC.tt->tt); // big data test /*std::vector<std::vector<float> > bigDataIn,bigDataOut; for(unsigned int i=0;i<10000;i++) { std::vector<float> v; for(unsigned int j=0;j<10000;j++) { v.push_back(j); } bigDataIn.push_back(v); } igl::Timer timer; timer.start(); igl::serialize_xml(bigDataIn,"bigDataIn",file,igl::SERIALIZE_BINARY); timer.stop(); std::cout << "ser: " << timer.getElapsedTimeInMilliSec() << std::endl; timer.start(); igl::deserialize_xml(bigDataOut,"bigDataIn",file); timer.stop(); std::cout << "des: " << timer.getElapsedTimeInMilliSec() << std::endl; char c; std::cin >> c;*/ std::cout << "All tests run successfully!\n"; }
int main(int argc, char *argv[]) { using namespace Eigen; using namespace std; igl::readOBJ("../shared/armadillo.obj",V,F); U=V; MatrixXd W; igl::readDMAT("../shared/armadillo-weights.dmat",W); igl::lbs_matrix_column(V,W,M); // Cluster according to weights VectorXi G; { VectorXi S; VectorXd D; igl::partition(W,50,G,S,D); } // vertices corresponding to handles (those with maximum weight) { VectorXd maxW; igl::mat_max(W,1,maxW,b); } // Precomputation for FAST cout<<"Initializing Fast Automatic Skinning Transformations..."<<endl; // number of weights const int m = W.cols(); Aeq.resize(m*3,m*3*(3+1)); vector<Triplet<double> > ijv; for(int i = 0;i<m;i++) { RowVector4d h**o; h**o << V.row(b(i)),1.; for(int d = 0;d<3;d++) { for(int c = 0;c<(3+1);c++) { ijv.push_back(Triplet<double>(3*i + d,i + c*m*3 + d*m, h**o(c))); } } } Aeq.setFromTriplets(ijv.begin(),ijv.end()); igl::arap_dof_precomputation(V,F,M,G,arap_dof_data); igl::arap_dof_recomputation(VectorXi(),Aeq,arap_dof_data); // Initialize MatrixXd Istack = MatrixXd::Identity(3,3+1).replicate(1,m); igl::columnize(Istack,m,2,L); // Precomputation for ARAP cout<<"Initializing ARAP..."<<endl; arap_data.max_iter = 1; igl::arap_precomputation(V,F,V.cols(),b,arap_data); // Grouped arap cout<<"Initializing ARAP with grouped edge-sets..."<<endl; arap_grouped_data.max_iter = 2; arap_grouped_data.G = G; igl::arap_precomputation(V,F,V.cols(),b,arap_grouped_data); // bounding box diagonal bbd = (V.colwise().maxCoeff()- V.colwise().minCoeff()).norm(); // Plot the mesh with pseudocolors igl::Viewer viewer; viewer.data.set_mesh(U, F); viewer.data.add_points(igl::slice(V,b,1),sea_green); viewer.core.show_lines = false; viewer.callback_pre_draw = &pre_draw; viewer.callback_key_down = &key_down; viewer.core.is_animating = false; viewer.core.animation_max_fps = 30.; cout<< "Press [space] to toggle animation."<<endl<< "Press '0' to reset pose."<<endl<< "Press '.' to switch to next deformation method."<<endl<< "Press ',' to switch to previous deformation method."<<endl; viewer.launch(); }
inline void resize(Eigen::SparseMatrix<T, options> & m, std::size_t new_rows, std::size_t new_cols) { m.resize(new_rows, new_cols); }
IGL_INLINE void igl::cotmatrix( const Eigen::MatrixBase<DerivedV> & V, const Eigen::MatrixBase<DerivedF> & F, Eigen::SparseMatrix<Scalar>& L) { using namespace Eigen; using namespace std; L.resize(V.rows(),V.rows()); Matrix<int,Dynamic,2> edges; int simplex_size = F.cols(); // 3 for triangles, 4 for tets assert(simplex_size == 3 || simplex_size == 4); if(simplex_size == 3) { // This is important! it could decrease the comptuation time by a factor of 2 // Laplacian for a closed 2d manifold mesh will have on average 7 entries per // row L.reserve(10*V.rows()); edges.resize(3,2); edges << 1,2, 2,0, 0,1; }else if(simplex_size == 4) { L.reserve(17*V.rows()); edges.resize(6,2); edges << 1,2, 2,0, 0,1, 3,0, 3,1, 3,2; }else { return; } // Gather cotangents Matrix<Scalar,Dynamic,Dynamic> C; cotmatrix_entries(V,F,C); vector<Triplet<Scalar> > IJV; IJV.reserve(F.rows()*edges.rows()*4); // Loop over triangles for(int i = 0; i < F.rows(); i++) { // loop over edges of element for(int e = 0;e<edges.rows();e++) { int source = F(i,edges(e,0)); int dest = F(i,edges(e,1)); IJV.push_back(Triplet<Scalar>(source,dest,C(i,e))); IJV.push_back(Triplet<Scalar>(dest,source,C(i,e))); IJV.push_back(Triplet<Scalar>(source,source,-C(i,e))); IJV.push_back(Triplet<Scalar>(dest,dest,-C(i,e))); } } L.setFromTriplets(IJV.begin(),IJV.end()); }
void Mesh::elasticEnergy(const VectorXd &q, const VectorXd &g, double &energyB, double &energyS, VectorXd &gradq, Eigen::SparseMatrix<double> &hessq, Eigen::SparseMatrix<double> &gradggradq, int derivativesRequested) const { assert(q.size() == numdofs()); assert(g.size() == numedges()); energyB = energyS = 0; if(derivativesRequested & ElasticEnergy::DR_DQ) { gradq.resize(numdofs()); gradq.setZero(); if(derivativesRequested & ElasticEnergy::DR_HQ) hessq.resize(numdofs(), numdofs()); } if(derivativesRequested & ElasticEnergy::DR_DGDQ) { gradggradq.resize(numedges(), numdofs()); } vector<Tr> Hqcoeffs; vector<Tr> Hgcoeffs; vector<Tr> dgdqcoeffs; // bending energy for(OMMesh::VertexIter vi = mesh_->vertices_begin(); vi != mesh_->vertices_end(); ++vi) { if(mesh_->is_boundary(vi.handle())) continue; vector<int> spokeidx; vector<int> rightoppidx; vector<int> nbidx; for(OMMesh::VertexOHalfedgeIter voh = mesh_->voh_iter(vi.handle()); voh; ++voh) { OMMesh::HalfedgeHandle heh = voh.handle(); int eidx = mesh_->edge_handle(heh).idx(); spokeidx.push_back(eidx); OMMesh::VertexOHalfedgeIter nextoh = voh; ++nextoh; if(!nextoh) nextoh = mesh_->voh_iter(vi.handle()); OMMesh::VertexHandle nextvert = mesh_->to_vertex_handle(nextoh.handle()); OMMesh::HalfedgeHandle opp = mesh_->next_halfedge_handle(heh);; if(mesh_->to_vertex_handle(opp) != nextvert) { opp = mesh_->prev_halfedge_handle(mesh_->opposite_halfedge_handle(heh)); assert(mesh_->from_vertex_handle(opp) == nextvert); } int oidx = mesh_->edge_handle(opp).idx(); rightoppidx.push_back(oidx); OMMesh::VertexHandle vh = mesh_->to_vertex_handle(heh); nbidx.push_back(vh.idx()); } int centidx = vi.handle().idx(); energyB += ElasticEnergy::bendingEnergy(q, g, centidx, nbidx, spokeidx, rightoppidx, gradq, Hqcoeffs, dgdqcoeffs, params_, derivativesRequested); } // Stretching energy for(OMMesh::FaceIter it = mesh_->faces_begin(); it != mesh_->faces_end(); ++it) { int qidx[3]; int gidx[3]; int idx=0; for(OMMesh::FaceHalfedgeIter fhi = mesh_->fh_iter(it.handle()); fhi; ++fhi) { assert(idx < 3); OMMesh::HalfedgeHandle heh = fhi.handle(); OMMesh::EdgeHandle eh = mesh_->edge_handle(heh); OMMesh::VertexHandle from = mesh_->from_vertex_handle(heh); gidx[idx] = eh.idx(); qidx[(idx+1)%3] = from.idx(); idx++; } assert(idx == 3); energyS += ElasticEnergy::stretchingEnergy(q, g, qidx, gidx, gradq, Hqcoeffs, dgdqcoeffs, params_, derivativesRequested); } if(derivativesRequested & ElasticEnergy::DR_HQ) hessq.setFromTriplets(Hqcoeffs.begin(), Hqcoeffs.end()); if(derivativesRequested & ElasticEnergy::DR_DGDQ) gradggradq.setFromTriplets(dgdqcoeffs.begin(), dgdqcoeffs.end()); }
IGL_INLINE void igl::slice_tets( const Eigen::PlainObjectBase<DerivedV>& V, const Eigen::PlainObjectBase<DerivedT>& T, const Eigen::PlainObjectBase<Derivedplane> & plane, Eigen::PlainObjectBase<DerivedU>& U, Eigen::PlainObjectBase<DerivedG>& G, Eigen::PlainObjectBase<DerivedJ>& J, Eigen::SparseMatrix<BCType> & BC) { using namespace Eigen; using namespace std; assert(V.cols() == 3 && "V should be #V by 3"); assert(T.cols() == 4 && "T should be #T by 4"); assert(plane.size() == 4 && "Plane equation should be 4 coefficients"); // number of tets const size_t m = T.rows(); typedef typename DerivedV::Scalar Scalar; typedef typename DerivedT::Scalar Index; typedef Matrix<Scalar,Dynamic,1> VectorXS; typedef Matrix<Scalar,Dynamic,4> MatrixX4S; typedef Matrix<Scalar,Dynamic,3> MatrixX3S; typedef Matrix<Scalar,Dynamic,2> MatrixX2S; typedef Matrix<Index,Dynamic,4> MatrixX4I; typedef Matrix<Index,Dynamic,3> MatrixX3I; typedef Matrix<Index,Dynamic,1> VectorXI; typedef Matrix<bool,Dynamic,1> VectorXb; // Value of plane's implicit function at all vertices VectorXS IV = (V.col(0)*plane(0) + V.col(1)*plane(1) + V.col(2)*plane(2)).array() + plane(3); MatrixX4S IT(m,4); for(size_t t = 0;t<m;t++) { for(size_t c = 0;c<4;c++) { IT(t,c) = IV(T(t,c)); } } const auto & extract_rows = []( const PlainObjectBase<DerivedT> & T, const MatrixX4S & IT, const VectorXb & I, MatrixX4I & TI, MatrixX4S & ITI, VectorXI & JI) { const Index num_I = std::count(I.data(),I.data()+I.size(),true); TI.resize(num_I,4); ITI.resize(num_I,4); JI.resize(num_I,1); { size_t k = 0; for(size_t t = 0;t<(size_t)T.rows();t++) { if(I(t)) { TI.row(k) = T.row(t); ITI.row(k) = IT.row(t); JI(k) = t; k++; } } assert(k == num_I); } }; VectorXb I13 = (IT.array()<0).rowwise().count()==1; VectorXb I31 = (IT.array()>0).rowwise().count()==1; VectorXb I22 = (IT.array()<0).rowwise().count()==2; MatrixX4I T13,T31,T22; MatrixX4S IT13,IT31,IT22; VectorXI J13,J31,J22; extract_rows(T,IT,I13,T13,IT13,J13); extract_rows(T,IT,I31,T31,IT31,J31); extract_rows(T,IT,I22,T22,IT22,J22); const auto & apply_sort = [] ( const MatrixX4I & T, const MatrixX4I & sJ, MatrixX4I & sT) { sT.resize(T.rows(),4); for(size_t t = 0;t<(size_t)T.rows();t++) { for(size_t c = 0;c<4;c++) { sT(t,c) = T(t,sJ(t,c)); } } }; const auto & one_below = [&V,&apply_sort]( const MatrixX4I & T, const MatrixX4S & IT, MatrixX3I & G, SparseMatrix<BCType> & BC) { // Number of tets const size_t m = T.rows(); MatrixX4S sIT; MatrixX4I sJ; sort(IT,2,true,sIT,sJ); MatrixX4I sT; apply_sort(T,sJ,sT); MatrixX3S lambda = sIT.rightCols(3).array() / (sIT.rightCols(3).colwise()-sIT.col(0)).array(); vector<Triplet<BCType> > IJV; IJV.reserve(m*3*2); for(size_t c = 0;c<3;c++) { for(size_t t = 0;t<(size_t)m;t++) { IJV.push_back(Triplet<BCType>(c*m+t, sT(t,0), lambda(t,c))); IJV.push_back(Triplet<BCType>(c*m+t,sT(t,c+1),1-lambda(t,c))); } } BC.resize(m*3,V.rows()); BC.reserve(m*3*2); BC.setFromTriplets(IJV.begin(),IJV.end()); G.resize(m,3); for(size_t c = 0;c<3;c++) { G.col(c).setLinSpaced(m,0+c*m,(m-1)+c*m); } }; const auto & two_below = [&V,&apply_sort]( const MatrixX4I & T, const MatrixX4S & IT, MatrixX3I & G, SparseMatrix<BCType> & BC) { // Number of tets const size_t m = T.rows(); MatrixX4S sIT; MatrixX4I sJ; sort(IT,2,true,sIT,sJ); MatrixX4I sT; apply_sort(T,sJ,sT); MatrixX2S lambda = sIT.rightCols(2).array() / (sIT.rightCols(2).colwise()-sIT.col(0)).array(); MatrixX2S gamma = sIT.rightCols(2).array() / (sIT.rightCols(2).colwise()-sIT.col(1)).array(); vector<Triplet<BCType> > IJV; IJV.reserve(m*4*2); for(size_t c = 0;c<2;c++) { for(size_t t = 0;t<(size_t)m;t++) { IJV.push_back(Triplet<BCType>(0*2*m+c*m+t, sT(t,0), lambda(t,c))); IJV.push_back(Triplet<BCType>(0*2*m+c*m+t,sT(t,c+2),1-lambda(t,c))); IJV.push_back(Triplet<BCType>(1*2*m+c*m+t, sT(t,1), gamma(t,c))); IJV.push_back(Triplet<BCType>(1*2*m+c*m+t,sT(t,c+2),1- gamma(t,c))); } } BC.resize(m*4,V.rows()); BC.reserve(m*4*2); BC.setFromTriplets(IJV.begin(),IJV.end()); G.resize(2*m,3); G.block(0,0,m,1) = VectorXI::LinSpaced(m,0+0*m,(m-1)+0*m); G.block(0,1,m,1) = VectorXI::LinSpaced(m,0+1*m,(m-1)+1*m); G.block(0,2,m,1) = VectorXI::LinSpaced(m,0+3*m,(m-1)+3*m); G.block(m,0,m,1) = VectorXI::LinSpaced(m,0+0*m,(m-1)+0*m); G.block(m,1,m,1) = VectorXI::LinSpaced(m,0+3*m,(m-1)+3*m); G.block(m,2,m,1) = VectorXI::LinSpaced(m,0+2*m,(m-1)+2*m); }; MatrixX3I G13,G31,G22; SparseMatrix<BCType> BC13,BC31,BC22; one_below(T13,IT13,G13,BC13); one_below(T31,-IT31,G31,BC31); two_below(T22,IT22,G22,BC22); BC = cat(1,cat(1,BC13,BC31),BC22); U = BC*V; G.resize(G13.rows()+G31.rows()+G22.rows(),3); G<<G13,(G31.array()+BC13.rows()),(G22.array()+BC13.rows()+BC31.rows()); MatrixX3S N; per_face_normals(U,G,N); Matrix<Scalar,1,3> planeN(plane(0),plane(1),plane(2)); VectorXb flip = (N.array().rowwise() * planeN.array()).rowwise().sum()<0; for(size_t g = 0;g<(size_t)G.rows();g++) { if(flip(g)) { G.row(g) = G.row(g).reverse().eval(); } } J.resize(G.rows()); J<<J13,J31,J22,J22; }
TEST_F(TsProductTimings, benchmark ) { std::cerr<<"=== Matrix-Matrix Products:"<<std::endl; double start, stop; matMultiplication.clear(); start = get_time(); matMultiplication = mat * matMultiplier; stop = get_time(); std::cerr<<"Mat:\t\t"<<stop-start<<" (ms)"<<std::endl; fullMultiplication.clear(); start = get_time(); fullMat.mul( fullMultiplication, fullMultiplier ); stop = get_time(); std::cerr<<"Full:\t\t"<<stop-start<<" (ms)"<<std::endl; crsMultiplication.clear(); start = get_time(); crs1.mul( crsMultiplication, crsMultiplier ); stop = get_time(); std::cerr<<"CRS:\t\t"<<stop-start<<" (ms)"<<std::endl; eiBaseMultiplication.clear(); start = get_time(); eiBase.mul( eiBaseMultiplication, eiBaseMultiplier ); stop = get_time(); std::cerr<<"Eigen Base ST:\t\t"<<stop-start<<" (ms)"<<std::endl; #ifdef USING_OMP_PRAGMAS eiBaseMultiplication.clear(); start = get_time(); eiBase.mul_MT( eiBaseMultiplication, eiBaseMultiplier ); stop = get_time(); std::cerr<<"Eigen Base MT:\t\t"<<stop-start<<" (ms)"<<std::endl; #endif start = get_time(); eiDenseMultiplication = eiBase.compressedMatrix * eiDenseMultiplier; stop = get_time(); std::cerr<<"Eigen Sparse*Dense:\t\t"<<stop-start<<" (ms)"<<std::endl; #ifdef USING_OMP_PRAGMAS start = get_time(); eiDenseMultiplication.noalias() = component::linearsolver::mul_EigenSparseDenseMatrix_MT( eiBase.compressedMatrix, eiDenseMultiplier, omp_get_max_threads()/2 ); stop = get_time(); std::cerr<<"Eigen Sparse*Dense MT:\t\t"<<stop-start<<" (ms)"<<std::endl; #endif std::cerr<<"=== Eigen Matrix-Vector Products:"<<std::endl; unsigned nbrows = 100, nbcols; std::cerr<<"=== nb rows:"<<nbrows<<std::endl; for( int j=1; j<300 ; j+=30 ) { nbcols = 100 * j; std::cerr<<"=== nb cols:"<<nbcols<<std::endl; Eigen::SparseMatrix<SReal,Eigen::RowMajor> A; A.resize(nbrows,nbcols); #define NBCOLSRHS 1 Eigen::Matrix<SReal, Eigen::Dynamic, NBCOLSRHS> res, rhs; rhs.resize(nbcols,NBCOLSRHS); res.resize(nbrows,NBCOLSRHS); sofa::helper::RandomGenerator randomGenerator; randomGenerator.initSeed( (long)time(0) ); for( unsigned j=0; j<nbcols; j++) { Real random = randomGenerator.random<Real>( (Real) -1, (Real) 1 ); for( unsigned i=0; i<NBCOLSRHS; i++) rhs.coeffRef(j,i) = random; for( unsigned i=0; i<nbrows; i++) { if( random > -0.5 && random < 0.5 ) A.coeffRef(i,j)=random; } } double min=std::numeric_limits<double>::max(), max=0, sum=0; for( int i=0; i<100 ; ++i ) { start = get_time(); res.noalias() = A * rhs; stop = get_time(); double current = stop-start; sum+=current; if( current<min ) min=current; if( current>max ) max=current; } std::cerr<<"ST: "<<sum/100.0<<" "<<min<<" "<<max<<std::endl; #ifdef USING_OMP_PRAGMAS min=std::numeric_limits<double>::max(), max=0, sum=0; for( int i=0; i<100 ; ++i ) { start = get_time(); // res.noalias() = typename Eigen::SparseDenseProductReturnType_MT<Eigen::SparseMatrix<SReal,Eigen::RowMajor>,Eigen::Matrix<SReal, Eigen::Dynamic, 1> >::Type( A.derived(), rhs.derived() ); // component::linearsolver::mul_EigenSparseDenseMatrix_MT( res, A, rhs ); res.noalias() = component::linearsolver::mul_EigenSparseDenseMatrix_MT( A, rhs ); stop = get_time(); double current = stop-start; sum+=current; if( current<min ) min=current; if( current>max ) max=current; } std::cerr<<"MT: "<<sum/100.0<<" "<<min<<" "<<max<<std::endl; #endif } ASSERT_TRUE( true ); }