#include "min_quad_with_fixed.h" #include "slice.h" #include "is_symmetric.h" #include "find.h" #include "sparse.h" #include "repmat.h" #include "lu_lagrange.h" #include "full.h" #include "matlab_format.h" #include "EPS.h" #include "cat.h" //#include // Bug in unsupported/Eigen/SparseExtra needs iostream first #include #include #include #include #include template IGL_INLINE bool igl::min_quad_with_fixed_precompute( const Eigen::SparseMatrix& A, const Eigen::PlainObjectBase & known, const Eigen::SparseMatrix& Aeq, const bool pd, min_quad_with_fixed_data & data ) { using namespace Eigen; using namespace std; using namespace igl; // number of rows int n = A.rows(); // cache problem size data.n = n; int neq = Aeq.rows(); // default is to have 0 linear equality constraints if(Aeq.size() != 0) { assert(n == Aeq.cols()); } assert(A.rows() == n); assert(A.cols() == n); // number of known rows int kr = known.size(); assert(kr == 0 || known.minCoeff() >= 0); assert(kr == 0 || known.maxCoeff() < n); assert(neq <= n); // cache known data.known = known; // get list of unknown indices data.unknown.resize(n-kr); std::vector unknown_mask; unknown_mask.resize(n,true); for(int i = 0;i Auu; igl::slice(A,data.unknown,data.unknown,Auu); // Positive definiteness is *not* determined, rather it is given as a // parameter data.Auu_pd = pd; if(data.Auu_pd) { // PD implies symmetric data.Auu_sym = true; assert(igl::is_symmetric(Auu,igl::EPS())); }else { // determine if A(unknown,unknown) is symmetric and/or positive definite data.Auu_sym = igl::is_symmetric(Auu,igl::EPS()); } // Append lagrange multiplier quadratic terms SparseMatrix new_A; SparseMatrix AeqT = Aeq.transpose(); SparseMatrix Z(neq,neq); // This is a bit slower. But why isn't cat fast? new_A = cat(1, cat(2, A, AeqT ), cat(2, Aeq, Z )); //cout< AI; //Matrix AJ; //Matrix AV; //// Slow //igl::find(A,AI,AJ,AV); //Matrix AeqI(0,1); //Matrix AeqJ(0,1); //Matrix AeqV(0,1); //if(neq > 0) //{ // // Slow // igl::find(Aeq,AeqI,AeqJ,AeqV); //} //Matrix new_AI(AV.size()+AeqV.size()*2); //Matrix new_AJ(AV.size()+AeqV.size()*2); //Matrix new_AV(AV.size()+AeqV.size()*2); //new_AI << AI, (AeqI.array()+n).matrix(), AeqJ; //new_AJ << AJ, AeqJ, (AeqI.array()+n).matrix(); //new_AV << AV, AeqV, AeqV; //// Slow //igl::sparse(new_AI,new_AJ,new_AV,n+neq,n+neq,new_A); //cout< 0) { SparseMatrix Aulk,Akul; // Slow igl::slice(new_A,data.unknown_lagrange,data.known,Aulk); //// This doesn't work!!! //data.preY = Aulk + Akul.transpose(); // Slow if(data.Auu_sym) { data.preY = Aulk*2; }else { igl::slice(new_A,data.known,data.unknown_lagrange,Akul); SparseMatrix AkulT = Akul.transpose(); data.preY = Aulk + AkulT; } }else { data.preY.resize(data.unknown_lagrange.size(),0); } // Positive definite and no equality constraints (Postive definiteness // implies symmetric) if(data.Auu_pd && neq == 0) { data.llt.compute(Auu); switch(data.llt.info()) { case Eigen::Success: break; case Eigen::NumericalIssue: cerr<<"Error: Numerical issue."<::LLT; }else { // Either not PD or there are equality constraints SparseMatrix NA; igl::slice(new_A,data.unknown_lagrange,data.unknown_lagrange,NA); data.NA = NA; // Ideally we'd use LDLT but Eigen doesn't support positive semi-definite // matrices: // http://forum.kde.org/viewtopic.php?f=74&t=106962&p=291990#p291990 if(data.Auu_sym && false) { data.ldlt.compute(NA); switch(data.ldlt.info()) { case Eigen::Success: break; case Eigen::NumericalIssue: cerr<<"Error: Numerical issue."<::LDLT; }else { // Resort to LU // Bottleneck >1/2 data.lu.compute(NA); MatrixXd NAf; full(NA,NAf); //std::cout<<"NA=["<::LU; } } return true; } template < typename T, typename DerivedB, typename DerivedY, typename DerivedBeq, typename DerivedZ> IGL_INLINE bool igl::min_quad_with_fixed_solve( const min_quad_with_fixed_data & data, const Eigen::PlainObjectBase & B, const Eigen::PlainObjectBase & Y, const Eigen::PlainObjectBase & Beq, Eigen::PlainObjectBase & Z) { using namespace std; // number of known rows int kr = data.known.size(); if(kr!=0) { assert(kr == Y.rows()); } // number of columns to solve int cols = Y.cols(); assert(B.cols() == 1); assert(Beq.size() == 0 || Beq.cols() == 1); // number of lagrange multipliers aka linear equality constraints int neq = data.lagrange.size(); // append lagrange multiplier rhs's Eigen::Matrix BBeq(B.size() + Beq.size()); BBeq << B, (Beq*-2.0); // Build right hand side Eigen::Matrix BBequl; igl::slice(BBeq,data.unknown_lagrange,BBequl); Eigen::Matrix BBequlcols; igl::repmat(BBequl,1,cols,BBequlcols); Eigen::Matrix NB; if(kr == 0) { NB = BBequlcols; }else { NB = data.preY * Y + BBequlcols; } // resize output Z.resize(data.n,cols); // Set known values for(int i = 0;i < kr;i++) { for(int j = 0;j < cols;j++) { Z(data.known(i),j) = Y(i,j); } } //std::cout<<"NB=["< sol; //cout<::LLT: sol = data.llt.solve(NB); break; case igl::min_quad_with_fixed_data::LDLT: sol = data.ldlt.solve(NB); break; case igl::min_quad_with_fixed_data::LU: // Not a bottleneck sol = data.lu.solve(NB); break; default: cerr<<"Error: invalid solver type"<, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(igl::min_quad_with_fixed_data const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); template bool igl::min_quad_with_fixed_precompute >(Eigen::SparseMatrix const&, Eigen::PlainObjectBase > const&, Eigen::SparseMatrix const&, bool, igl::min_quad_with_fixed_data&); #endif