31 const Eigen::SparseMatrix<T>& A2,
32 const Eigen::MatrixBase<Derivedknown> & known,
33 const Eigen::SparseMatrix<T>& Aeq,
39 using namespace Eigen;
41 const Eigen::SparseMatrix<T> A = 0.5*A2;
42#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG
54 assert(n == Aeq.cols() &&
"#Aeq.cols() should match A.rows()");
57 assert(known.cols() == 1 &&
"known should be a vector");
58 assert(A.rows() == n &&
"A should be square");
59 assert(A.cols() == n &&
"A should be square");
62 int kr = known.size();
64 assert((kr == 0 || known.minCoeff() >= 0)&&
"known indices should be in [0,n)");
65 assert((kr == 0 || known.maxCoeff() < n) &&
"known indices should be in [0,n)");
66 assert(neq <= n &&
"Number of equality constraints should be less than DOFs");
71 data.
known = known.template cast<int>();
75 std::vector<bool> unknown_mask;
76 unknown_mask.resize(n,
true);
77 for(
int i = 0;i<kr;i++)
79 unknown_mask[known(i, 0)] =
false;
82 for(
int i = 0;i<n;i++)
92 for(
int i = 0;i<neq;i++)
113 assert(Auu.size() != 0 && Auu.rows() > 0 &&
"There should be at least one unknown.");
125 "Auu should be symmetric if positive definite");
130 Matrix<T,Eigen::Dynamic,Eigen::Dynamic> AuuV;
131 find(Auu,AuuI,AuuJ,AuuV);
139#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG
144 assert(data.
Aequ.rows() == neq &&
145 "#Rows in Aequ should match #constraints");
147 "#cols in Aequ should match #unknowns");
148 data.
AeqTQR.compute(data.
Aequ.transpose().eval());
149#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG
152 switch(data.
AeqTQR.info())
156 case Eigen::NumericalIssue:
157 cerr<<
"Error: Numerical issue."<<endl;
159 case Eigen::InvalidInput:
160 cerr<<
"Error: Invalid input."<<endl;
163 cerr<<
"Error: Other."<<endl;
168 "Rank of reduced constraints should be <= #original constraints");
178#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG
179 cout<<
" Aeq_li=true"<<endl;
182 SparseMatrix<T> new_A;
183 SparseMatrix<T> AeqT = Aeq.transpose();
184 SparseMatrix<T> Z(neq,neq);
186 new_A =
cat(1,
cat(2, A, AeqT ),
192 SparseMatrix<T> Aulk,Akul;
204 SparseMatrix<T> AkulT = Akul.transpose();
205 data.
preY = Aulk + AkulT;
214#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG
215 cout<<
" factorize"<<endl;
217 if(data.
Auu_pd && neq == 0)
219#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG
222 data.
llt.compute(Auu);
223 switch(data.
llt.info())
227 case Eigen::NumericalIssue:
228 cerr<<
"Error: Numerical issue."<<endl;
231 cerr<<
"Error: Other."<<endl;
237#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG
238 cout<<
" ldlt/lu"<<endl;
246#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG
249 data.
ldlt.compute(NA);
250 switch(data.
ldlt.info())
254 case Eigen::NumericalIssue:
255 cerr<<
"Error: Numerical issue."<<endl;
258 cerr<<
"Error: Other."<<endl;
264#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG
271 switch(data.
lu.info())
275 case Eigen::NumericalIssue:
276 cerr<<
"Error: Numerical issue."<<endl;
278 case Eigen::InvalidInput:
279 cerr<<
"Error: Invalid Input."<<endl;
282 cerr<<
"Error: Other."<<endl;
290#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG
291 cout<<
" Aeq_li=false"<<endl;
294 const int nu = data.
unknown.size();
299 SparseMatrix<T> AeqTR,AeqTQ;
300 AeqTR = data.
AeqTQR.matrixR();
302 AeqTR.prune(
static_cast<T
>(0.0));
303#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG
304 cout<<
" matrixQ"<<endl;
308 AeqTQ = data.
AeqTQR.matrixQ();
309#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG
310 cout<<
" prune"<<endl;
311 cout<<
" nnz: "<<AeqTQ.nonZeros()<<endl;
314 AeqTQ.prune(
static_cast<T
>(0.0));
318#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG
319 cout<<
" nnz: "<<AeqTQ.nonZeros()<<endl;
322 SparseMatrix<T> I(neq,neq);
325 data.
AeqTET = data.
AeqTQR.colsPermutation().transpose() * I;
326 assert(AeqTR.rows() == nu &&
"#rows in AeqTR should match #unknowns");
327 assert(AeqTR.cols() == neq &&
"#cols in AeqTR should match #constraints");
328 assert(AeqTQ.rows() == nu &&
"#rows in AeqTQ should match #unknowns");
329 assert(AeqTQ.cols() == nu &&
"#cols in AeqTQ should match #unknowns");
331#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG
332 cout<<
" slice"<<endl;
334 data.
AeqTQ1 = AeqTQ.topLeftCorner(nu,nc);
337 data.
AeqTR1 = AeqTR.topLeftCorner(nc,nc);
341 data.
AeqTQ2 = AeqTQ.bottomRightCorner(nu,nu-nc);
343#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG
349#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG
350 cout<<
" factorize"<<endl;
353 data.
llt.compute(QRAuu);
354 switch(data.
llt.info())
358 case Eigen::NumericalIssue:
359 cerr<<
"Error: Numerical issue."<<endl;
362 cerr<<
"Error: Other."<<endl;
367#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG
368 cout<<
" smash"<<endl;
375 SparseMatrix<T> AkuT = Aku.transpose();
376 data.
preY = Auk + AkuT;
380 assert(data.
Aeqk.rows() == neq);
381 assert(data.
Aeqk.cols() == data.
known.size());
396 const Eigen::MatrixBase<DerivedB> & B,
397 const Eigen::MatrixBase<DerivedY> & Y,
398 const Eigen::MatrixBase<DerivedBeq> & Beq,
399 Eigen::PlainObjectBase<DerivedZ> & Z,
400 Eigen::PlainObjectBase<Derivedsol> & sol)
403 using namespace Eigen;
404 typedef Matrix<T,Dynamic,Dynamic> MatrixXT;
406 int kr = data.
known.size();
409 assert(kr == Y.rows());
413 assert(B.cols() == 1 || B.cols() == cols);
414 assert(Beq.size() == 0 || Beq.cols() == 1 || Beq.cols() == cols);
417 Z.resize(data.
n,cols);
419 for(
int i = 0;i < kr;i++)
421 for(
int j = 0;j < cols;j++)
423 Z(data.
known(i),j) = Y(i,j);
432 MatrixXT BBeq(B.rows() + Beq.rows(),cols);
435 BBeq.topLeftCorner(B.rows(),cols) = B.replicate(1,B.cols()==cols?1:cols);
439 BBeq.bottomLeftCorner(Beq.rows(),cols) = -2.0*Beq.replicate(1,Beq.cols()==cols?1:cols);
450 NB = data.
preY * Y + BBequlcols;
458 sol = data.
llt.solve(NB);
461 sol = data.
ldlt.solve(NB);
465 sol = data.
lu.solve(NB);
468 cerr<<
"Error: invalid solver type"<<endl;
476 for(
int i = 0;i<(sol.rows()-neq);i++)
478 for(
int j = 0;j<sol.cols();j++)
490 data.
AeqTET * (-data.
Aeqk * Y + Beq.replicate(1,Beq.cols()==cols?1:cols));
492 MatrixXT Bu = B(data.
unknown,Eigen::all);
494 NB = -0.5*(Bu.replicate(1,B.cols()==cols?1:cols) + data.
preY * Y);
496 const int nc = data.
AeqTQR.rank();
497 const int neq = Beq.rows();
498 eff_Beq = eff_Beq.topLeftCorner(nc,cols).eval();
499 data.
AeqTR1T.template triangularView<Lower>().solveInPlace(eff_Beq);
502 lambda_0 = data.
AeqTQ1 * eff_Beq;
507 lambda = data.
llt.solve(QRB);
510 solu = data.
AeqTQ2 * lambda + lambda_0;
512 Derivedsol solLambda;
514 Derivedsol temp1,temp2;
516 data.
AeqTR1.template triangularView<Upper>().solveInPlace(temp1);
518 temp2 = Derivedsol::Zero(neq,cols);
519 temp2.topLeftCorner(nc,cols) = temp1;
521 solLambda = data.
AeqTE * temp2;
524 assert(data.
unknown.size() == solu.rows());
525 assert(cols == solu.cols());
526 assert(data.
neq == neq);
527 assert(data.
neq == solLambda.rows());
528 assert(cols == solLambda.cols());
529 sol.resize(data.
unknown.size()+data.
neq,cols);
530 sol.block(0,0,solu.rows(),solu.cols()) = solu;
531 sol.block(solu.rows(),0,solLambda.rows(),solLambda.cols()) = solLambda;
532 for(
int u = 0;u<data.
unknown.size();u++)
534 for(
int j = 0;j<Z.cols();j++)
536 Z(data.
unknown(u),j) = solu(u,j);
588 const Eigen::Matrix<Scalar,n,n> & H,
589 const Eigen::Matrix<Scalar,n,1> & f,
590 const Eigen::Array<bool,n,1> & k,
591 const Eigen::Matrix<Scalar,n,1> & bc,
592 const Eigen::Matrix<Scalar,m,n> & A,
593 const Eigen::Matrix<Scalar,m,1> & b)
595 const auto dyn_n = n == Eigen::Dynamic ? H.rows() : n;
596 const auto dyn_m = m == Eigen::Dynamic ? A.rows() : m;
597 constexpr const int nn = n == Eigen::Dynamic ? Eigen::Dynamic : n+m;
598 const auto dyn_nn = nn == Eigen::Dynamic ? dyn_n+dyn_m : nn;
601 return igl::min_quad_with_fixed<Scalar,n,Hpd>(H,f,k,bc);
606 const auto make_HH = [&]()
609 constexpr const int nn = n == Eigen::Dynamic ? Eigen::Dynamic : n+m;
610 Eigen::Matrix<Scalar,nn,nn> HH =
611 Eigen::Matrix<Scalar,nn,nn>::Zero(dyn_nn,dyn_nn);
612 HH.topLeftCorner(dyn_n,dyn_n) = H;
613 HH.bottomLeftCorner(dyn_m,dyn_n) = A;
614 HH.topRightCorner(dyn_n,dyn_m) = A.transpose();
617 const Eigen::Matrix<Scalar,nn,nn> HH = make_HH();
618 const auto make_ff = [&]()
621 constexpr const int nn = n == Eigen::Dynamic ? Eigen::Dynamic : n+m;
622 Eigen::Matrix<Scalar,nn,1> ff(dyn_nn);
627 const Eigen::Matrix<Scalar,nn,1> ff = make_ff();
628 const auto make_kk = [&]()
631 constexpr const int nn = n == Eigen::Dynamic ? Eigen::Dynamic : n+m;
632 Eigen::Array<bool,nn,1> kk =
633 Eigen::Array<bool,nn,1>::Constant(dyn_nn,1,
false);
637 const Eigen::Array<bool,nn,1> kk = make_kk();
638 const auto make_bcbc= [&]()
641 constexpr const int nn = n == Eigen::Dynamic ? Eigen::Dynamic : n+m;
642 Eigen::Matrix<Scalar,nn,1> bcbc(dyn_nn);
643 bcbc.head(dyn_n) = bc;
646 const Eigen::Matrix<Scalar,nn,1> bcbc = make_bcbc();
647 const Eigen::Matrix<Scalar,nn,1> xx =
648 min_quad_with_fixed<Scalar,nn,false>(HH,ff,kk,bcbc);
649 return xx.head(dyn_n);
654 const Eigen::Matrix<Scalar,n,n> & H,
655 const Eigen::Matrix<Scalar,n,1> & f,
656 const Eigen::Array<bool,n,1> & k,
657 const Eigen::Matrix<Scalar,n,1> & bc)
659 assert(H.isApprox(H.transpose(),1e-7));
660 assert(H.rows() == H.cols());
661 assert(H.rows() == f.size());
662 assert(H.rows() == k.size());
663 assert(H.rows() == bc.size());
664 const auto kcount = k.count();
666 if(kcount == (Eigen::Dynamic?H.rows():n))
674 typedef Eigen::Matrix<Scalar,n,n> MatrixSn;
676 std::conditional<Hpd,Eigen::LLT<MatrixSn>,Eigen::CompleteOrthogonalDecomposition<MatrixSn>>::type
678 return Solver(H).solve(-f);
681 if( (Eigen::Dynamic?H.rows():n)-kcount == 1)
685 for(
int i=0;i<k.size();i++){
if(!k(i)){ u=i;
break; } }
690 Eigen::Matrix<Scalar,n,1> x = bc;
692 for(
int i=0;i<k.size();i++){
if(i!=u){ x(u)-=bc(i)*H(i,u); } }
703 case 0: assert(
false &&
"Handled above.");
return Eigen::Matrix<Scalar,n,1>();
708 const bool D = (n-1<=0)||(1>=n)||(n>16);
709 return min_quad_with_fixed<Scalar,D?Eigen::Dynamic:n,D?Eigen::Dynamic:1,Hpd>(H,f,k,bc);
713 const bool D = (n-2<=0)||(2>=n)||(n>16);
714 return min_quad_with_fixed<Scalar,D?Eigen::Dynamic:n,D?Eigen::Dynamic:2,Hpd>(H,f,k,bc);
718 const bool D = (n-3<=0)||(3>=n)||(n>16);
719 return min_quad_with_fixed<Scalar,D?Eigen::Dynamic:n,D?Eigen::Dynamic:3,Hpd>(H,f,k,bc);
723 const bool D = (n-4<=0)||(4>=n)||(n>16);
724 return min_quad_with_fixed<Scalar,D?Eigen::Dynamic:n,D?Eigen::Dynamic:4,Hpd>(H,f,k,bc);
728 const bool D = (n-5<=0)||(5>=n)||(n>16);
729 return min_quad_with_fixed<Scalar,D?Eigen::Dynamic:n,D?Eigen::Dynamic:5,Hpd>(H,f,k,bc);
733 const bool D = (n-6<=0)||(6>=n)||(n>16);
734 return min_quad_with_fixed<Scalar,D?Eigen::Dynamic:n,D?Eigen::Dynamic:6,Hpd>(H,f,k,bc);
738 const bool D = (n-7<=0)||(7>=n)||(n>16);
739 return min_quad_with_fixed<Scalar,D?Eigen::Dynamic:n,D?Eigen::Dynamic:7,Hpd>(H,f,k,bc);
743 const bool D = (n-8<=0)||(8>=n)||(n>16);
744 return min_quad_with_fixed<Scalar,D?Eigen::Dynamic:n,D?Eigen::Dynamic:8,Hpd>(H,f,k,bc);
748 const bool D = (n-9<=0)||(9>=n)||(n>16);
749 return min_quad_with_fixed<Scalar,D?Eigen::Dynamic:n,D?Eigen::Dynamic:9,Hpd>(H,f,k,bc);
753 const bool D = (n-10<=0)||(10>=n)||(n>16);
754 return min_quad_with_fixed<Scalar,D?Eigen::Dynamic:n,D?Eigen::Dynamic:10,Hpd>(H,f,k,bc);
758 const bool D = (n-11<=0)||(11>=n)||(n>16);
759 return min_quad_with_fixed<Scalar,D?Eigen::Dynamic:n,D?Eigen::Dynamic:11,Hpd>(H,f,k,bc);
763 const bool D = (n-12<=0)||(12>=n)||(n>16);
764 return min_quad_with_fixed<Scalar,D?Eigen::Dynamic:n,D?Eigen::Dynamic:12,Hpd>(H,f,k,bc);
768 const bool D = (n-13<=0)||(13>=n)||(n>16);
769 return min_quad_with_fixed<Scalar,D?Eigen::Dynamic:n,D?Eigen::Dynamic:13,Hpd>(H,f,k,bc);
773 const bool D = (n-14<=0)||(14>=n)||(n>16);
774 return min_quad_with_fixed<Scalar,D?Eigen::Dynamic:n,D?Eigen::Dynamic:14,Hpd>(H,f,k,bc);
778 const bool D = (n-15<=0)||(15>=n)||(n>16);
779 return min_quad_with_fixed<Scalar,D?Eigen::Dynamic:n,D?Eigen::Dynamic:15,Hpd>(H,f,k,bc);
783 const bool D = (n-16<=0)||(16>=n)||(n>16);
784 return min_quad_with_fixed<Scalar,D?Eigen::Dynamic:n,D?Eigen::Dynamic:16,Hpd>(H,f,k,bc);
787 return min_quad_with_fixed<Scalar,Eigen::Dynamic,Eigen::Dynamic,Hpd>(H,f,k,bc);
793 const Eigen::Matrix<Scalar,n,n> & H,
794 const Eigen::Matrix<Scalar,n,1> & f,
795 const Eigen::Array<bool,n,1> & k,
796 const Eigen::Matrix<Scalar,n,1> & bc)
799 static_assert(kcount==Eigen::Dynamic || kcount>0 ,
"");
800 static_assert(kcount==Eigen::Dynamic || kcount<n ,
"");
801 const int ucount = n==Eigen::Dynamic ? Eigen::Dynamic : n-kcount;
802 static_assert(kcount==Eigen::Dynamic || ucount+kcount == n ,
"");
803 static_assert((n==Eigen::Dynamic) == (ucount==Eigen::Dynamic),
"");
804 static_assert((kcount==Eigen::Dynamic) == (ucount==Eigen::Dynamic),
"");
805 assert((n==Eigen::Dynamic) || n == H.rows());
806 assert((kcount==Eigen::Dynamic) || kcount == k.count());
807 typedef Eigen::Matrix<Scalar,ucount,ucount> MatrixSuu;
808 typedef Eigen::Matrix<Scalar,ucount,kcount> MatrixSuk;
809 typedef Eigen::Matrix<Scalar,n,1> VectorSn;
810 typedef Eigen::Matrix<Scalar,ucount,1> VectorSu;
811 typedef Eigen::Matrix<Scalar,kcount,1> VectorSk;
812 const auto dyn_n = n==Eigen::Dynamic ? H.rows() : n;
813 const auto dyn_kcount = kcount==Eigen::Dynamic ? k.count() : kcount;
814 const auto dyn_ucount = ucount==Eigen::Dynamic ? dyn_n- dyn_kcount : ucount;
817 MatrixSuu Huu(dyn_ucount,dyn_ucount);
818 MatrixSuk Huk(dyn_ucount,dyn_kcount);
819 VectorSu mrhs(dyn_ucount);
820 VectorSk bck(dyn_kcount);
824 for(
int i = 0;i<dyn_n;i++)
835 for(
int j = 0;j<dyn_n;j++)
853 std::conditional<Hpd,
854 Eigen::LLT<MatrixSuu>,
863 Eigen::CompleteOrthogonalDecomposition<MatrixSuu>>::type
865 VectorSu xu = Solver(Huu).solve(-mrhs);
870 for(
int i = 0;i<dyn_n;i++)