// This file is part of libigl, a simple c++ geometry processing library. // // Copyright (C) 2013 Alec Jacobson // // This Source Code Form is subject to the terms of the Mozilla Public License // v. 2.0. If a copy of the MPL was not distributed with this file, You can // obtain one at http://mozilla.org/MPL/2.0/. #include "active_set.h" #include "min_quad_with_fixed.h" #include "slice.h" #include "slice_into.h" #include "cat.h" //#include "matlab_format.h" #include #include #include template < typename AT, typename DerivedB, typename Derivedknown, typename DerivedY, typename AeqT, typename DerivedBeq, typename AieqT, typename DerivedBieq, typename Derivedlx, typename Derivedux, typename DerivedZ > IGL_INLINE igl::SolverStatus igl::active_set( const Eigen::SparseMatrix& A, const Eigen::PlainObjectBase & B, const Eigen::PlainObjectBase & known, const Eigen::PlainObjectBase & Y, const Eigen::SparseMatrix& Aeq, const Eigen::PlainObjectBase & Beq, const Eigen::SparseMatrix& Aieq, const Eigen::PlainObjectBase & Bieq, const Eigen::PlainObjectBase & p_lx, const Eigen::PlainObjectBase & p_ux, const igl::active_set_params & params, Eigen::PlainObjectBase & Z ) { //#define ACTIVE_SET_CPP_DEBUG #if defined(ACTIVE_SET_CPP_DEBUG) && !defined(_MSC_VER) # warning "ACTIVE_SET_CPP_DEBUG" #endif using namespace Eigen; using namespace std; SolverStatus ret = SOLVER_STATUS_ERROR; const int n = A.rows(); assert(n == A.cols() && "A must be square"); // Discard const qualifiers //if(B.size() == 0) //{ // B = DerivedB::Zero(n,1); //} assert(n == B.rows() && "B.rows() must match A.rows()"); assert(B.cols() == 1 && "B must be a column vector"); assert(Y.cols() == 1 && "Y must be a column vector"); assert((Aeq.size() == 0 && Beq.size() == 0) || Aeq.cols() == n); assert((Aeq.size() == 0 && Beq.size() == 0) || Aeq.rows() == Beq.rows()); assert((Aeq.size() == 0 && Beq.size() == 0) || Beq.cols() == 1); assert((Aieq.size() == 0 && Bieq.size() == 0) || Aieq.cols() == n); assert((Aieq.size() == 0 && Bieq.size() == 0) || Aieq.rows() == Bieq.rows()); assert((Aieq.size() == 0 && Bieq.size() == 0) || Bieq.cols() == 1); Eigen::Matrix lx; Eigen::Matrix ux; if(p_lx.size() == 0) { lx = Derivedlx::Constant( n,1,-numeric_limits::max()); }else { lx = p_lx; } if(p_ux.size() == 0) { ux = Derivedux::Constant( n,1,numeric_limits::max()); }else { ux = p_ux; } assert(lx.rows() == n && "lx must have n rows"); assert(ux.rows() == n && "ux must have n rows"); assert(ux.cols() == 1 && "lx must be a column vector"); assert(lx.cols() == 1 && "ux must be a column vector"); assert((ux.array()-lx.array()).minCoeff() > 0 && "ux(i) must be > lx(i)"); if(Z.size() != 0) { // Initial guess should have correct size assert(Z.rows() == n && "Z must have n rows"); assert(Z.cols() == 1 && "Z must be a column vector"); } assert(known.cols() == 1 && "known must be a column vector"); // Number of knowns const int nk = known.size(); // Initialize active sets typedef int BOOL; #define TRUE 1 #define FALSE 0 Matrix as_lx = Matrix::Constant(n,1,FALSE); Matrix as_ux = Matrix::Constant(n,1,FALSE); Matrix as_ieq = Matrix::Constant(Aieq.rows(),1,FALSE); // Keep track of previous Z for comparison DerivedZ old_Z; old_Z = DerivedZ::Constant( n,1,numeric_limits::max()); int iter = 0; while(true) { #ifdef ACTIVE_SET_CPP_DEBUG cout<<"Iteration: "< 0) { for(int z = 0;z < n;z++) { if(Z(z) < lx(z)) { new_as_lx += (as_lx(z)?0:1); //new_as_lx++; as_lx(z) = TRUE; } if(Z(z) > ux(z)) { new_as_ux += (as_ux(z)?0:1); //new_as_ux++; as_ux(z) = TRUE; } } if(Aieq.rows() > 0) { DerivedZ AieqZ; AieqZ = Aieq*Z; for(int a = 0;a Bieq(a)) { new_as_ieq += (as_ieq(a)?0:1); as_ieq(a) = TRUE; } } } #ifdef ACTIVE_SET_CPP_DEBUG cout<<" new_as_lx: "< Aeq_i,Aieq_i; slice(Aieq,as_ieq_list,1,Aieq_i); // Append to equality constraints cat(1,Aeq,Aieq_i,Aeq_i); min_quad_with_fixed_data data; #ifndef NDEBUG { // NO DUPES! Matrix fixed = Matrix::Constant(n,1,FALSE); for(int k = 0;k 0 && Aeq_i.rows() > Aeq.rows()) { cerr<<" *Are you sure rows of [Aeq;Aieq] are linearly independent?*"<< endl; } ret = SOLVER_STATUS_ERROR; break; } #ifdef ACTIVE_SET_CPP_DEBUG cout<<" min_quad_with_fixed_solve"< Ak; // Slow slice(A,known_i,1,Ak); DerivedB Bk; slice(B,known_i,Bk); MatrixXd Lambda_known_i = -(0.5*Ak*Z + 0.5*Bk); // reverse the lambda values for lx Lambda_known_i.block(nk,0,as_lx_count,1) = (-1*Lambda_known_i.block(nk,0,as_lx_count,1)).eval(); // Extract Lagrange multipliers for Aieq_i (always at back of sol) VectorXd Lambda_Aieq_i(Aieq_i.rows(),1); for(int l = 0;l0 && iter>=params.max_iter) { ret = SOLVER_STATUS_MAX_ITER; break; } } return ret; } #ifdef IGL_STATIC_LIBRARY // Explicit template instantiation template igl::SolverStatus igl::active_set, Eigen::Matrix, Eigen::Matrix, double, Eigen::Matrix, double, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::SparseMatrix const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::SparseMatrix const&, Eigen::PlainObjectBase > const&, Eigen::SparseMatrix const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, igl::active_set_params const&, Eigen::PlainObjectBase >&); template igl::SolverStatus igl::active_set, Eigen::Matrix, Eigen::Matrix, double, Eigen::Matrix, double, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::SparseMatrix const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::SparseMatrix const&, Eigen::PlainObjectBase > const&, Eigen::SparseMatrix const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, igl::active_set_params const&, Eigen::PlainObjectBase >&); #endif