Controller::Controller(dynamics::SkeletonDynamics* _skel, const vector<int> &_actuatedDofs, const VectorXd &_kP, const VectorXd &_kD, const vector<int> &_ankleDofs, const VectorXd &_anklePGains, const VectorXd &_ankleDGains) : mSkel(_skel), mKp(_kP.asDiagonal()), mKd(_kD.asDiagonal()), mAnkleDofs(_ankleDofs), mAnklePGains(_anklePGains), mAnkleDGains(_ankleDGains), mTrajectory(NULL) { const int nDof = mSkel->getNumDofs(); mSelectionMatrix = MatrixXd::Zero(nDof, nDof); for (int i = 0; i < _actuatedDofs.size(); i++) { mSelectionMatrix(_actuatedDofs[i], _actuatedDofs[i]) = 1.0; } mDesiredDofs.resize(nDof); for (int i = 0; i < nDof; i++) { mDesiredDofs[i] = mSkel->getDof(i)->getValue(); } Vector3d com = mSkel->getWorldCOM(); double cop = 0.0; mPreOffset = com[0] - cop; }
VectorXd lsq_weigh_nonneg(const MatrixXd& A, const VectorXd& b, const VectorXd& w) { const unsigned m = A.rows(); const unsigned n = A.cols(); if(b.size() != m || w.size() != m || n < 1 || m < 1) { std::cerr<<"#error in lsq_weigh_nonneg: If A is a m by n matrix, then b and w must have length m. We also want n >= 1 and m >= 1. A is "<< m <<" by "<< n <<", b has length "<< b.size() <<" and w has length "<< w.size() <<"."<<std::endl; throw std::invalid_argument("lsq_weigh_nonneg: dimension mismatch"); } // initialization const MatrixXd H = A.transpose() * w.asDiagonal() * A; const VectorXd f = - A.transpose() * w.asDiagonal() * b; VectorXd x = VectorXd::Zero(n), mu = f; // iterate double relerr; do { for(unsigned k = 0; k < n; ++k) { const double xtmp = x(k); x(k) -= mu(k) / H(k,k); if(x(k) < 0) x(k) = 0; const double d = x(k) - xtmp; if(d != 0) mu += d * H.col(k); } relerr = 0; for(unsigned k = 0; k < n; ++k) { if(x(k) != 0) { double err = mu(k) / x(k); if(err < 0) err = -err; if(err > relerr) relerr = err; } } } while(relerr >= 1e-2); // update non-zero columns with more costly, but also more precise calculation const VectorXi p = find(x.array() > 0); const VectorXd xp = lscov(pick_col(A, p), b, w); if(find(xp.array() >= 0).all()) set_ind(x, p, xp); return x; }
VectorXd svdSolve( JacobiSVD<MatrixXd> & svd,VectorXd & ref, double * rankPtr = NULL, double EPS=1e-6 ) { typedef JacobiSVD<MatrixXd> SVDType; const JacobiSVD<MatrixXd>::MatrixUType &U = svd.matrixU(); const JacobiSVD<MatrixXd>::MatrixVType &V = svd.matrixV(); const JacobiSVD<MatrixXd>::SingularValuesType &s = svd.singularValues(); //std::cout << (MATLAB)U<< (MATLAB)s<<(MATLAB)V << std::endl; const int N=V.rows(),M=U.rows(),S=std::min(M,N); int rank=0; while( rank<S && s[rank]>EPS ) rank++; VectorXd sinv = s.head(rank).array().inverse(); //std::cout << "U = " << (MATLAB)U.leftCols(rank) << std::endl; //std::cout << "V = " << (MATLAB)V.leftCols(rank) << std::endl; //std::cout << "S = " << (MATLAB)(MatrixXd)sinv.asDiagonal() << std::endl; VectorXd x; x = V.leftCols(rank) * sinv.asDiagonal() * U.leftCols(rank).transpose() * ref; if(rankPtr!=NULL) *rankPtr = rank; return x; }
void Spectral::generate_kernel_matrix(){ // Fill kernel matrix K.resize(X.rows(),X.rows()); for(unsigned int i = 0; i < X.rows(); i++){ for(unsigned int j = i; j < X.rows(); j++){ K(i,j) = K(j,i) = kernel(X.row(i),X.row(j)); //if(i == 0) cout << K(i,j) << " "; } } // Normalise kernel matrix VectorXd d = K.rowwise().sum(); for(unsigned int i = 0; i < d.rows(); i++){ d(i) = 1.0/sqrt(d(i)); } auto F = d.asDiagonal(); MatrixXd l = (K * F); for(unsigned int i = 0; i < l.rows(); i++){ for(unsigned int j = 0; j < l.cols(); j++){ l(i,j) = l(i,j) * d(i); } } K = l; }
void eigs_sym_Cpp(MatrixXd &M, VectorXd &init_resid, int k, int m, double &time_used, double &prec_err) { double start, end; start = get_wall_time(); DenseGenMatProd<double> op(M); SymEigsSolver< double, LARGEST_MAGN, DenseGenMatProd<double> > eigs(&op, k, m); eigs.init(init_resid.data()); int nconv = eigs.compute(); int niter = eigs.num_iterations(); int nops = eigs.num_operations(); VectorXd evals = eigs.eigenvalues(); MatrixXd evecs = eigs.eigenvectors(); /* std::cout << "computed eigenvalues D = \n" << evals.transpose() << std::endl; std::cout << "first 5 rows of computed eigenvectors U = \n" << evecs.topRows<5>() << std::endl; std::cout << "nconv = " << nconv << std::endl; std::cout << "niter = " << niter << std::endl; std::cout << "nops = " << nops << std::endl; */ end = get_wall_time(); time_used = (end - start) * 1000; MatrixXd err = M * evecs - evecs * evals.asDiagonal(); prec_err = err.cwiseAbs().maxCoeff(); }
SparseMatrix<double> compute_M2_topic( SparseMatrix<double> data ){ cout << "Computing M2 topic..." << endl; int n = data.rows(); int na = data.cols(); SparseMatrix<double> M2(na,na); for (int t = 0; t < n; ++t){ cout << t << endl; VectorXd c = data.row(t); SparseVector<double> c_sp = data.row(t); MatrixXd temp = c.asDiagonal(); M2 += (c_sp*c_sp.transpose() - temp.sparseView()); } M2 *= (alpha0+1.)/n; SparseVector<double> M1 = compute_M1_topic(data).sparseView(); cout << M2.cols() << endl; cout << M2.rows() << endl; cout << M1.size() << endl; SparseMatrix<double> aux = alpha0 * ( M1 * M1.transpose() ); cout << aux.cols() << endl; cout << aux.rows() << endl; M2 = M2 - aux; return M2; }
// ZCA of genotypes void RandomPCA::zca_whiten(bool transpose) { verbose && std::cout << timestamp() << " Whitening begin" << std::endl; VectorXd s = 1 / d.array(); MatrixXd Dinv = s.asDiagonal(); if(transpose) W.noalias() = U * Dinv * U.transpose() * X.transpose(); else W.noalias() = U * Dinv * U.transpose() * X; verbose && std::cout << timestamp() << " Whitening done (" << dim(W) << ")" << std::endl; }
void pseudoinverse(const MatrixXd& A, MatrixXd& P) { JacobiSVD<MatrixXd> svd(A, ComputeThinU | ComputeThinV); VectorXd invSingularVals = svd.singularValues(); const double tolerance = 1e-6; for (int i = 0; i < invSingularVals.size(); i++) if (fabs(invSingularVals(i)) > tolerance) invSingularVals(i) = 1.0/invSingularVals(i); else invSingularVals(i) = 0.0; P = svd.matrixV() * invSingularVals.asDiagonal() * svd.matrixU().transpose(); }
MatrixXd CMT::pInverse(const MatrixXd& matrix) { if(matrix.size() == 0) return matrix.transpose(); JacobiSVD<MatrixXd> svd(matrix, ComputeThinU | ComputeThinV); VectorXd svInv = svd.singularValues(); for(int i = 0; i < svInv.size(); ++i) if(svInv[i] > 1e-8) svInv[i] = 1. / svInv[i]; return svd.matrixV() * svInv.asDiagonal() * svd.matrixU().transpose(); }
//************************************************************************************************** Eigen::MatrixRXd wholeBodyReach::pinvDampedEigen(const Eigen::Ref<Eigen::MatrixRXd> &A, double damp) { // allocate memory int m = A.rows(), n = A.cols(), k = m<n?m:n; VectorXd SpinvD = VectorXd::Zero(k); // compute decomposition JacobiSVD<MatrixRXd> svd(A, ComputeThinU | ComputeThinV); // default Eigen SVD VectorXd sv = svd.singularValues(); // compute pseudoinverse of singular value matrix double damp2 = damp*damp; for (int c=0;c<k; c++) SpinvD(c) = sv(c) / (sv(c)*sv(c) + damp2); // compute damped pseudoinverse return svd.matrixV() * SpinvD.asDiagonal() * svd.matrixU().transpose(); }
MatrixXd compute_w( SparseMatrix<double> M2, int KHID ){ cout << "Computing the whitening matrix..." << endl; int m = M2.rows(); cout << "Calculating SVD..." << endl; JacobiSVD<MatrixXd> svd( M2, ComputeThinU ); cout << "SVD successfully calculated" << endl; VectorXd E = svd.singularValues(); E = E.head(KHID); E = E.array().sqrt().inverse().matrix(); MatrixXd E_diag = E.asDiagonal(); MatrixXd U = svd.matrixU(); U = U.block(0,0,m,KHID); cout << U.rows() << endl; cout << U.cols() << endl; return U*E_diag; }
void LAR::train(const MatrixXd& data ) { LINE; LINE; cout << "Data Dimension : " << data.rows() << " X " << data.cols() << endl; LINE; cout << endl; //Training data double trainRatio = 2.8 / 3; int breakPoint = (int)(data.rows() * trainRatio), col = data.cols(), row = data.rows(); MatrixXd X_(breakPoint, col); X_ << data.block(0, 0, breakPoint, col - 1), MatrixXd::Ones(breakPoint, 1); MatrixXd Y = data.block(0, col - 1, breakPoint, 1); //testing MatrixXd Xts(row - breakPoint, col); Xts = data.block(breakPoint, 0, row - breakPoint, col - 1), MatrixXd::Ones(row - breakPoint, 1); MatrixXd Yts = data.block(breakPoint, col - 1, row - breakPoint, 1); //Least absolute error regression //initialize the parameter VectorXd beta_new = VectorXd::Zero(col); VectorXd beta_old = VectorXd::Ones(col); cout << "Iteratively weighted least square regression:" << endl << endl; int i = 0; while ((beta_new - beta_old).norm()>0.01) { beta_old = beta_new; //Parameter estiamtion -- iteratively weighted least square VectorXd weight = 1 / (Y - X_*beta_old).array().abs(); MatrixXd C = weight.asDiagonal(); beta_new = (X_.transpose()*C*X_).inverse()*X_.transpose()*C*Y; cout << "Training iteration: " << setw(3) << ++i << " , current coefficients: " << beta_new.transpose() << endl; } //prediction on test set LINE; cout << "Result: " << endl << endl; beta = beta_new.head(beta_new.size()-1); cout << " Coefficients for X are: " << beta << endl; offset = beta_new(beta_new.size() - 1); cout << " Offset term is: " << offset << endl; LINE; LINE; }
MatrixXd rbf_kernel(MatrixXd& X, const double sigma, bool rbf_center, bool verbose) { unsigned int n = X.rows(); VectorXd norms = X.array().square().rowwise().sum(); VectorXd ones = VectorXd::Ones(n); MatrixXd R = norms * ones.transpose(); MatrixXd D = R + R.transpose() - 2 * X * X.transpose(); D = D.array() / (-1 * sigma * sigma); MatrixXd K = D.array().exp(); if(rbf_center) { verbose && std::cout << timestamp() << " Centering RBF kernel" << std::endl; MatrixXd M = ones * ones.transpose() / n; MatrixXd I = ones.asDiagonal(); K = (I - M) * K * (I - M); } return K; }
VectorXd PatchFit::lls(MatrixXd J, VectorXd b) { // check input dimensions if (J.rows() != b.rows()) cerr << "Wrong dimensions" << endl; VectorXd a (J.cols()); //output parameters JacobiSVD<MatrixXd> svd(J, ComputeThinU | ComputeThinV); VectorXd sv = svd.singularValues(); MatrixXd V = svd.matrixV(); VectorXd pv = sv.array().inverse(); VectorXd pvSq = pv.array()*pv.array(); if (b.any()) a = V * pvSq.asDiagonal() * V.adjoint() * J.adjoint() * b; else a = V.rightCols(1); return a; }
MatrixXd sample_MME_multiple_diagR( MatrixXd Y, SpMat W, SpMat chol_C, VectorXd pe, MSpMat chol_K_inv, VectorXd tot_Eta_prec, MatrixXd randn_theta, MatrixXd randn_e ){ MatrixXd theta_star = chol_K_inv.triangularView<Upper>().solve(randn_theta); MatrixXd e_star = randn_e * pe.cwiseSqrt().cwiseInverse().asDiagonal(); MatrixXd W_theta_star = W * theta_star; MatrixXd Y_resid = Y - W_theta_star - e_star; MatrixXd WtRiy = W.transpose() * (Y_resid * pe.asDiagonal()); MatrixXd theta_tilda = chol_C.transpose().triangularView<Upper>().solve(chol_C.triangularView<Lower>().solve(WtRiy)); MatrixXd theta = theta_tilda * tot_Eta_prec.cwiseInverse().asDiagonal() + theta_star; return theta; }
int setupAndSolveQP(NewQPControllerData *pdata, std::shared_ptr<drake::lcmt_qp_controller_input> qp_input, double t, Map<VectorXd> &q, Map<VectorXd> &qd, const Ref<Matrix<bool, Dynamic, 1>> &b_contact_force, QPControllerOutput *qp_output, std::shared_ptr<QPControllerDebugData> debug) { // The primary solve loop for our controller. This constructs and solves a Quadratic Program and produces the instantaneous desired torques, along with reference positions, velocities, and accelerations. It mirrors the Matlab implementation in atlasControllers.InstantaneousQPController.setupAndSolveQP(), and more documentation can be found there. // Note: argument `debug` MAY be set to NULL, which signals that no debug information is requested. // look up the param set by name AtlasParams *params; std::map<string,AtlasParams>::iterator it; it = pdata->param_sets.find(qp_input->param_set_name); if (it == pdata->param_sets.end()) { mexWarnMsgTxt("Got a param set I don't recognize! Using standing params instead"); it = pdata->param_sets.find("standing"); if (it == pdata->param_sets.end()) { mexErrMsgTxt("Could not fall back to standing parameters either. I have to give up here."); } } // cout << "using params set: " + it->first + ", "; params = &(it->second); // mexPrintf("Kp_accel: %f, ", params->Kp_accel); int nu = pdata->B.cols(); int nq = pdata->r->num_positions; // zmp_data Map<Matrix<double, 4, 4, RowMajor>> A_ls(&qp_input->zmp_data.A[0][0]); Map<Matrix<double, 4, 2, RowMajor>> B_ls(&qp_input->zmp_data.B[0][0]); Map<Matrix<double, 2, 4, RowMajor>> C_ls(&qp_input->zmp_data.C[0][0]); Map<Matrix<double, 2, 2, RowMajor>> D_ls(&qp_input->zmp_data.D[0][0]); Map<Matrix<double, 4, 1>> x0(&qp_input->zmp_data.x0[0][0]); Map<Matrix<double, 2, 1>> y0(&qp_input->zmp_data.y0[0][0]); Map<Matrix<double, 2, 1>> u0(&qp_input->zmp_data.u0[0][0]); Map<Matrix<double, 2, 2, RowMajor>> R_ls(&qp_input->zmp_data.R[0][0]); Map<Matrix<double, 2, 2, RowMajor>> Qy(&qp_input->zmp_data.Qy[0][0]); Map<Matrix<double, 4, 4, RowMajor>> S(&qp_input->zmp_data.S[0][0]); Map<Matrix<double, 4, 1>> s1(&qp_input->zmp_data.s1[0][0]); Map<Matrix<double, 4, 1>> s1dot(&qp_input->zmp_data.s1dot[0][0]); // // whole_body_data if (qp_input->whole_body_data.num_positions != nq) mexErrMsgTxt("number of positions doesn't match num_dof for this robot"); Map<VectorXd> q_des(qp_input->whole_body_data.q_des.data(), nq); Map<VectorXd> condof(qp_input->whole_body_data.constrained_dofs.data(), qp_input->whole_body_data.num_constrained_dofs); PIDOutput pid_out = wholeBodyPID(pdata, t, q, qd, q_des, ¶ms->whole_body); qp_output->q_ref = pid_out.q_ref; // mu // NOTE: we're using the same mu for all supports double mu; if (qp_input->num_support_data == 0) { mu = 1.0; } else { mu = qp_input->support_data[0].mu; for (int i=1; i < qp_input->num_support_data; i++) { if (qp_input->support_data[i].mu != mu) { mexWarnMsgTxt("Currently, we assume that all supports have the same value of mu"); } } } const int dim = 3, // 3D nd = 2*m_surface_tangents; // for friction cone approx, hard coded for now assert(nu+6 == nq); vector<DesiredBodyAcceleration> desired_body_accelerations; desired_body_accelerations.resize(qp_input->num_tracked_bodies); Vector6d body_pose_des, body_v_des, body_vdot_des; Vector6d body_vdot; for (int i=0; i < qp_input->num_tracked_bodies; i++) { int body_id0 = qp_input->body_motion_data[i].body_id - 1; double weight = params->body_motion[body_id0].weight; desired_body_accelerations[i].body_id0 = body_id0; Map<Matrix<double, 6, 4,RowMajor>>coefs_rowmaj(&qp_input->body_motion_data[i].coefs[0][0]); Matrix<double, 6, 4> coefs = coefs_rowmaj; evaluateCubicSplineSegment(t - qp_input->body_motion_data[i].ts[0], coefs, body_pose_des, body_v_des, body_vdot_des); desired_body_accelerations[i].body_vdot = bodyMotionPD(pdata->r, q, qd, body_id0, body_pose_des, body_v_des, body_vdot_des, params->body_motion[body_id0].Kp, params->body_motion[body_id0].Kd); desired_body_accelerations[i].weight = weight; desired_body_accelerations[i].accel_bounds = params->body_motion[body_id0].accel_bounds; // mexPrintf("body: %d, vdot: %f %f %f %f %f %f weight: %f\n", body_id0, // desired_body_accelerations[i].body_vdot(0), // desired_body_accelerations[i].body_vdot(1), // desired_body_accelerations[i].body_vdot(2), // desired_body_accelerations[i].body_vdot(3), // desired_body_accelerations[i].body_vdot(4), // desired_body_accelerations[i].body_vdot(5), // weight); // mexPrintf("tracking body: %d, coefs[:,0]: %f %f %f %f %f %f coefs(", body_id0, } int n_body_accel_eq_constraints = 0; for (int i=0; i < desired_body_accelerations.size(); i++) { if (desired_body_accelerations[i].weight < 0) n_body_accel_eq_constraints++; } MatrixXd R_DQyD_ls = R_ls + D_ls.transpose()*Qy*D_ls; pdata->r->doKinematics(q,false,qd); //--------------------------------------------------------------------- vector<SupportStateElement> available_supports = loadAvailableSupports(qp_input); vector<SupportStateElement> active_supports = getActiveSupports(pdata->r, pdata->map_ptr, q, qd, available_supports, b_contact_force, params->contact_threshold, pdata->default_terrain_height); int num_active_contact_pts=0; for (vector<SupportStateElement>::iterator iter = active_supports.begin(); iter!=active_supports.end(); iter++) { num_active_contact_pts += iter->contact_pts.size(); } pdata->r->HandC(q,qd,(MatrixXd*)nullptr,pdata->H,pdata->C,(MatrixXd*)nullptr,(MatrixXd*)nullptr,(MatrixXd*)nullptr); pdata->H_float = pdata->H.topRows(6); pdata->H_act = pdata->H.bottomRows(nu); pdata->C_float = pdata->C.head(6); pdata->C_act = pdata->C.tail(nu); bool include_angular_momentum = (params->W_kdot.array().maxCoeff() > 1e-10); if (include_angular_momentum) { pdata->r->getCMM(q,qd,pdata->Ag,pdata->Agdot); pdata->Ak = pdata->Ag.topRows(3); pdata->Akdot = pdata->Agdot.topRows(3); } Vector3d xcom; // consider making all J's into row-major pdata->r->getCOM(xcom); pdata->r->getCOMJac(pdata->J); pdata->r->getCOMJacDot(pdata->Jdot); pdata->J_xy = pdata->J.topRows(2); pdata->Jdot_xy = pdata->Jdot.topRows(2); MatrixXd Jcom,Jcomdot; if (x0.size()==6) { Jcom = pdata->J; Jcomdot = pdata->Jdot; } else { Jcom = pdata->J_xy; Jcomdot = pdata->Jdot_xy; } MatrixXd B,JB,Jp,Jpdot,normals; int nc = contactConstraintsBV(pdata->r,num_active_contact_pts,mu,active_supports,pdata->map_ptr,B,JB,Jp,Jpdot,normals,pdata->default_terrain_height); int neps = nc*dim; VectorXd x_bar,xlimp; MatrixXd D_float(6,JB.cols()), D_act(nu,JB.cols()); if (nc>0) { if (x0.size()==6) { // x,y,z com xlimp.resize(6); xlimp.topRows(3) = xcom; xlimp.bottomRows(3) = Jcom*qd; } else { xlimp.resize(4); xlimp.topRows(2) = xcom.topRows(2); xlimp.bottomRows(2) = Jcom*qd; } x_bar = xlimp-x0; D_float = JB.topRows(6); D_act = JB.bottomRows(nu); } int nf = nc*nd; // number of contact force variables int nparams = nq+nf+neps; Vector3d kdot_des; if (include_angular_momentum) { VectorXd k = pdata->Ak*qd; kdot_des = -params->Kp_ang*k; // TODO: parameterize } //---------------------------------------------------------------------- // QP cost function ---------------------------------------------------- // // min: ybar*Qy*ybar + ubar*R*ubar + (2*S*xbar + s1)*(A*x + B*u) + // w_qdd*quad(qddot_ref - qdd) + w_eps*quad(epsilon) + // w_grf*quad(beta) + quad(kdot_des - (A*qdd + Adot*qd)) VectorXd f(nparams); { if (nc > 0) { // NOTE: moved Hqp calcs below, because I compute the inverse directly for FastQP (and sparse Hqp for gurobi) VectorXd tmp = C_ls*xlimp; VectorXd tmp1 = Jcomdot*qd; MatrixXd tmp2 = R_DQyD_ls*Jcom; pdata->fqp = tmp.transpose()*Qy*D_ls*Jcom; // mexPrintf("fqp head: %f %f %f\n", pdata->fqp(0), pdata->fqp(1), pdata->fqp(2)); pdata->fqp += tmp1.transpose()*tmp2; pdata->fqp += (S*x_bar + 0.5*s1).transpose()*B_ls*Jcom; pdata->fqp -= u0.transpose()*tmp2; pdata->fqp -= y0.transpose()*Qy*D_ls*Jcom; pdata->fqp -= (params->whole_body.w_qdd.array()*pid_out.qddot_des.array()).matrix().transpose(); if (include_angular_momentum) { pdata->fqp += qd.transpose()*pdata->Akdot.transpose()*params->W_kdot*pdata->Ak; pdata->fqp -= kdot_des.transpose()*params->W_kdot*pdata->Ak; } f.head(nq) = pdata->fqp.transpose(); } else { f.head(nq) = -pid_out.qddot_des; } } f.tail(nf+neps) = VectorXd::Zero(nf+neps); int neq = 6+neps+6*n_body_accel_eq_constraints+qp_input->whole_body_data.num_constrained_dofs; MatrixXd Aeq = MatrixXd::Zero(neq,nparams); VectorXd beq = VectorXd::Zero(neq); // constrained floating base dynamics // H_float*qdd - J_float'*lambda - Dbar_float*beta = -C_float Aeq.topLeftCorner(6,nq) = pdata->H_float; beq.topRows(6) = -pdata->C_float; if (nc>0) { Aeq.block(0,nq,6,nc*nd) = -D_float; } if (nc > 0) { // relative acceleration constraint Aeq.block(6,0,neps,nq) = Jp; Aeq.block(6,nq,neps,nf) = MatrixXd::Zero(neps,nf); // note: obvious sparsity here Aeq.block(6,nq+nf,neps,neps) = MatrixXd::Identity(neps,neps); // note: obvious sparsity here beq.segment(6,neps) = (-Jpdot -params->Kp_accel*Jp)*qd; } // add in body spatial equality constraints // VectorXd body_vdot; MatrixXd orig = MatrixXd::Zero(4,1); orig(3,0) = 1; int equality_ind = 6+neps; MatrixXd Jb(6,nq); MatrixXd Jbdot(6,nq); for (int i=0; i<desired_body_accelerations.size(); i++) { if (desired_body_accelerations[i].weight < 0) { // negative implies constraint if (!inSupport(active_supports,desired_body_accelerations[i].body_id0)) { pdata->r->forwardJac(desired_body_accelerations[i].body_id0,orig,1,Jb); pdata->r->forwardJacDot(desired_body_accelerations[i].body_id0,orig,1,Jbdot); for (int j=0; j<6; j++) { if (!std::isnan(desired_body_accelerations[i].body_vdot(j))) { Aeq.block(equality_ind,0,1,nq) = Jb.row(j); beq[equality_ind++] = -Jbdot.row(j)*qd + desired_body_accelerations[i].body_vdot(j); } } } } } if (qp_input->whole_body_data.num_constrained_dofs>0) { // add joint acceleration constraints for (int i=0; i<qp_input->whole_body_data.num_constrained_dofs; i++) { Aeq(equality_ind,(int)condof[i]-1) = 1; beq[equality_ind++] = pid_out.qddot_des[(int)condof[i]-1]; } } int n_ineq = 2*nu+2*6*desired_body_accelerations.size(); MatrixXd Ain = MatrixXd::Zero(n_ineq,nparams); // note: obvious sparsity here VectorXd bin = VectorXd::Zero(n_ineq); // linear input saturation constraints // u=B_act'*(H_act*qdd + C_act - Jz_act'*z - Dbar_act*beta) // using transpose instead of inverse because B is orthogonal Ain.topLeftCorner(nu,nq) = pdata->B_act.transpose()*pdata->H_act; Ain.block(0,nq,nu,nc*nd) = -pdata->B_act.transpose()*D_act; bin.head(nu) = -pdata->B_act.transpose()*pdata->C_act + pdata->umax; Ain.block(nu,0,nu,nparams) = -1*Ain.block(0,0,nu,nparams); bin.segment(nu,nu) = pdata->B_act.transpose()*pdata->C_act - pdata->umin; int constraint_start_index = 2*nu; for (int i=0; i<desired_body_accelerations.size(); i++) { pdata->r->forwardJac(desired_body_accelerations[i].body_id0,orig,1,Jb); pdata->r->forwardJacDot(desired_body_accelerations[i].body_id0,orig,1,Jbdot); Ain.block(constraint_start_index,0,6,pdata->r->num_positions) = Jb; bin.segment(constraint_start_index,6) = -Jbdot*qd + desired_body_accelerations[i].accel_bounds.max; constraint_start_index += 6; Ain.block(constraint_start_index,0,6,pdata->r->num_positions) = -Jb; bin.segment(constraint_start_index,6) = Jbdot*qd - desired_body_accelerations[i].accel_bounds.min; constraint_start_index += 6; } for (int i=0; i<n_ineq; i++) { // remove inf constraints---needed by gurobi if (std::isinf(double(bin(i)))) { Ain.row(i) = 0*Ain.row(i); bin(i)=0; } } GRBmodel * model = nullptr; int info=-1; // set obj,lb,up VectorXd lb(nparams), ub(nparams); lb.head(nq) = pdata->qdd_lb; ub.head(nq) = pdata->qdd_ub; lb.segment(nq,nf) = VectorXd::Zero(nf); ub.segment(nq,nf) = 1e3*VectorXd::Ones(nf); lb.tail(neps) = -params->slack_limit*VectorXd::Ones(neps); ub.tail(neps) = params->slack_limit*VectorXd::Ones(neps); VectorXd alpha(nparams); MatrixXd Qnfdiag(nf,1), Qneps(neps,1); vector<MatrixXd*> QBlkDiag( nc>0 ? 3 : 1 ); // nq, nf, neps // this one is for gurobi VectorXd w = (params->whole_body.w_qdd.array() + REG).matrix(); #ifdef USE_MATRIX_INVERSION_LEMMA double max_body_accel_weight = -numeric_limits<double>::infinity(); for (int i=0; i < desired_body_accelerations.size(); i++) { max_body_accel_weight = max(max_body_accel_weight, desired_body_accelerations[i].weight); } bool include_body_accel_cost_terms = desired_body_accelerations.size() > 0 && max_body_accel_weight > 1e-10; if (pdata->use_fast_qp > 0 && !include_angular_momentum && !include_body_accel_cost_terms) { // TODO: update to include angular momentum, body accel objectives. // We want Hqp inverse, which I can compute efficiently using the // matrix inversion lemma (see wikipedia): // inv(A + U'CV) = inv(A) - inv(A)*U* inv([ inv(C)+ V*inv(A)*U ]) V inv(A) if (nc>0) { MatrixXd Wi = ((1/(params->whole_body.w_qdd.array() + REG)).matrix()).asDiagonal(); if (R_DQyD_ls.trace()>1e-15) { // R_DQyD_ls is not zero pdata->Hqp = Wi - Wi*Jcom.transpose()*(R_DQyD_ls.inverse() + Jcom*Wi*Jcom.transpose()).inverse()*Jcom*Wi; } } else { pdata->Hqp = MatrixXd::Constant(nq,1,1/(1+REG)); } #ifdef TEST_FAST_QP if (nc>0) { MatrixXd Hqp_test(nq,nq); MatrixXd W = w.asDiagonal(); Hqp_test = (Jcom.transpose()*R_DQyD_ls*Jcom + W).inverse(); if (((Hqp_test-pdata->Hqp).array().abs()).maxCoeff() > 1e-6) { mexErrMsgTxt("Q submatrix inverse from matrix inversion lemma does not match direct Q inverse."); } } #endif Qnfdiag = MatrixXd::Constant(nf,1,1/REG); Qneps = MatrixXd::Constant(neps,1,1/(.001+REG)); QBlkDiag[0] = &pdata->Hqp; if (nc>0) { QBlkDiag[1] = &Qnfdiag; QBlkDiag[2] = &Qneps; // quadratic slack var cost, Q(nparams-neps:end,nparams-neps:end)=eye(neps) } MatrixXd Ain_lb_ub(n_ineq+2*nparams,nparams); VectorXd bin_lb_ub(n_ineq+2*nparams); Ain_lb_ub << Ain, // note: obvious sparsity here -MatrixXd::Identity(nparams,nparams), MatrixXd::Identity(nparams,nparams); bin_lb_ub << bin, -lb, ub; info = fastQPThatTakesQinv(QBlkDiag, f, Aeq, beq, Ain_lb_ub, bin_lb_ub, pdata->state.active, alpha); //if (info<0) mexPrintf("fastQP info = %d. Calling gurobi.\n", info); } else { #endif if (nc>0) { pdata->Hqp = Jcom.transpose()*R_DQyD_ls*Jcom; if (include_angular_momentum) { pdata->Hqp += pdata->Ak.transpose()*params->W_kdot*pdata->Ak; } pdata->Hqp += params->whole_body.w_qdd.asDiagonal(); pdata->Hqp += REG*MatrixXd::Identity(nq,nq); } else { pdata->Hqp = (1+REG)*MatrixXd::Identity(nq,nq); } // add in body spatial acceleration cost terms for (int i=0; i<desired_body_accelerations.size(); i++) { if (desired_body_accelerations[i].weight > 0) { if (!inSupport(active_supports,desired_body_accelerations[i].body_id0)) { pdata->r->forwardJac(desired_body_accelerations[i].body_id0,orig,1,Jb); pdata->r->forwardJacDot(desired_body_accelerations[i].body_id0,orig,1,Jbdot); for (int j=0; j<6; j++) { if (!std::isnan(desired_body_accelerations[i].body_vdot[j])) { pdata->Hqp += desired_body_accelerations[i].weight*(Jb.row(j)).transpose()*Jb.row(j); f.head(nq) += desired_body_accelerations[i].weight*(qd.transpose()*Jbdot.row(j).transpose() - desired_body_accelerations[i].body_vdot[j])*Jb.row(j).transpose(); } } } } } Qnfdiag = MatrixXd::Constant(nf,1,params->w_grf+REG); Qneps = MatrixXd::Constant(neps,1,params->w_slack+REG); QBlkDiag[0] = &pdata->Hqp; if (nc>0) { QBlkDiag[1] = &Qnfdiag; QBlkDiag[2] = &Qneps; // quadratic slack var cost, Q(nparams-neps:end,nparams-neps:end)=eye(neps) } MatrixXd Ain_lb_ub(n_ineq+2*nparams,nparams); VectorXd bin_lb_ub(n_ineq+2*nparams); Ain_lb_ub << Ain, // note: obvious sparsity here -MatrixXd::Identity(nparams,nparams), MatrixXd::Identity(nparams,nparams); bin_lb_ub << bin, -lb, ub; if (pdata->use_fast_qp > 0) { // set up and call fastqp info = fastQP(QBlkDiag, f, Aeq, beq, Ain_lb_ub, bin_lb_ub, pdata->state.active, alpha); //if (info<0) mexPrintf("fastQP info=%d... calling Gurobi.\n", info); } else { // use gurobi active set model = gurobiActiveSetQP(pdata->env,QBlkDiag,f,Aeq,beq,Ain,bin,lb,ub,pdata->state.vbasis,pdata->state.vbasis_len,pdata->state.cbasis,pdata->state.cbasis_len,alpha); CGE(GRBgetintattr(model,"NumVars",&(pdata->state.vbasis_len)), pdata->env); CGE(GRBgetintattr(model,"NumConstrs",&(pdata->state.cbasis_len)), pdata->env); info=66; //info = -1; } if (info<0) { model = gurobiQP(pdata->env,QBlkDiag,f,Aeq,beq,Ain,bin,lb,ub,pdata->state.active,alpha); int status; CGE(GRBgetintattr(model, "Status", &status), pdata->env); //if (status!=2) mexPrintf("Gurobi reports non-optimal status = %d\n", status); } #ifdef USE_MATRIX_INVERSION_LEMMA } #endif //---------------------------------------------------------------------- // Solve for inputs ---------------------------------------------------- qp_output->qdd = alpha.head(nq); VectorXd beta = alpha.segment(nq,nc*nd); // use transpose because B_act is orthogonal qp_output->u = pdata->B_act.transpose()*(pdata->H_act*qp_output->qdd + pdata->C_act - D_act*beta); //y = pdata->B_act.jacobiSvd(ComputeThinU|ComputeThinV).solve(pdata->H_act*qdd + pdata->C_act - Jz_act.transpose()*lambda - D_act*beta); bool foot_contact[2]; foot_contact[0] = b_contact_force(pdata->rpc.body_ids.r_foot) == 1; foot_contact[1] = b_contact_force(pdata->rpc.body_ids.l_foot) == 1; qp_output->qd_ref = velocityReference(pdata, t, q, qd, qp_output->qdd, foot_contact, &(params->vref_integrator), &(pdata->rpc)); // Remember t for next time around pdata->state.t_prev = t; // If a debug pointer was passed in, fill it with useful data if (debug) { debug->active_supports.resize(active_supports.size()); for (int i=0; i < active_supports.size(); i++) { debug->active_supports[i] = active_supports[i]; } debug->nc = nc; debug->normals = normals; debug->B = B; debug->alpha = alpha; debug->f = f; debug->Aeq = Aeq; debug->beq = beq; debug->Ain_lb_ub = Ain_lb_ub; debug->bin_lb_ub = bin_lb_ub; debug->Qnfdiag = Qnfdiag; debug->Qneps = Qneps; debug->x_bar = x_bar; debug->S = S; debug->s1 = s1; debug->s1dot = s1dot; debug->s2dot = qp_input->zmp_data.s2dot; debug->A_ls = A_ls; debug->B_ls = B_ls; debug->Jcom = Jcom; debug->Jcomdot = Jcomdot; debug->beta = beta; } // if we used gurobi, clean up if (model) { GRBfreemodel(model); } // GRBfreeenv(env); return info; }
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { int error; if (nrhs<1) mexErrMsgTxt("usage: ptr = QPControllermex(0,control_obj,robot_obj,...); alpha=QPControllermex(ptr,...,...)"); if (nlhs<1) mexErrMsgTxt("take at least one output... please."); struct QPControllerData* pdata; mxArray* pm; double* pr; int i,j; if (mxGetScalar(prhs[0])==0) { // then construct the data object and return pdata = new struct QPControllerData; // get control object properties const mxArray* pobj = prhs[1]; pm = myGetProperty(pobj,"slack_limit"); pdata->slack_limit = mxGetScalar(pm); pm = myGetProperty(pobj,"W_kdot"); assert(mxGetM(pm)==3); assert(mxGetN(pm)==3); pdata->W_kdot.resize(mxGetM(pm),mxGetN(pm)); memcpy(pdata->W_kdot.data(),mxGetPr(pm),sizeof(double)*mxGetM(pm)*mxGetN(pm)); pm= myGetProperty(pobj,"w_grf"); pdata->w_grf = mxGetScalar(pm); pm= myGetProperty(pobj,"w_slack"); pdata->w_slack = mxGetScalar(pm); pm = myGetProperty(pobj,"Kp_ang"); pdata->Kp_ang = mxGetScalar(pm); pm = myGetProperty(pobj,"Kp_accel"); pdata->Kp_accel = mxGetScalar(pm); pm= myGetProperty(pobj,"n_body_accel_inputs"); pdata->n_body_accel_inputs = (int) mxGetScalar(pm); pm= myGetProperty(pobj,"n_body_accel_bounds"); pdata->n_body_accel_bounds = (int) mxGetScalar(pm); mxArray* body_accel_bounds = myGetProperty(pobj,"body_accel_bounds"); Vector6d vecbound; for (int i=0; i<pdata->n_body_accel_bounds; i++) { pdata->accel_bound_body_idx.push_back((int) mxGetScalar(mxGetField(body_accel_bounds,i,"body_idx"))-1); pm = mxGetField(body_accel_bounds,i,"min_acceleration"); assert(mxGetM(pm)==6); assert(mxGetN(pm)==1); memcpy(vecbound.data(),mxGetPr(pm),sizeof(double)*6); pdata->min_body_acceleration.push_back(vecbound); pm = mxGetField(body_accel_bounds,i,"max_acceleration"); assert(mxGetM(pm)==6); assert(mxGetN(pm)==1); memcpy(vecbound.data(),mxGetPr(pm),sizeof(double)*6); pdata->max_body_acceleration.push_back(vecbound); } pm = myGetProperty(pobj,"body_accel_input_weights"); pdata->body_accel_input_weights.resize(pdata->n_body_accel_inputs); memcpy(pdata->body_accel_input_weights.data(),mxGetPr(pm),sizeof(double)*pdata->n_body_accel_inputs); pdata->n_body_accel_eq_constraints = 0; for (int i=0; i<pdata->n_body_accel_inputs; i++) { if (pdata->body_accel_input_weights(i) < 0) pdata->n_body_accel_eq_constraints++; } // get robot mex model ptr if (!mxIsNumeric(prhs[2]) || mxGetNumberOfElements(prhs[2])!=1) mexErrMsgIdAndTxt("Drake:QPControllermex:BadInputs","the third argument should be the robot mex ptr"); memcpy(&(pdata->r),mxGetData(prhs[2]),sizeof(pdata->r)); pdata->B.resize(mxGetM(prhs[3]),mxGetN(prhs[3])); memcpy(pdata->B.data(),mxGetPr(prhs[3]),sizeof(double)*mxGetM(prhs[3])*mxGetN(prhs[3])); int nq = pdata->r->num_dof, nu = pdata->B.cols(); pm = myGetProperty(pobj,"w_qdd"); pdata->w_qdd.resize(nq); memcpy(pdata->w_qdd.data(),mxGetPr(pm),sizeof(double)*nq); pdata->umin.resize(nu); pdata->umax.resize(nu); memcpy(pdata->umin.data(),mxGetPr(prhs[4]),sizeof(double)*nu); memcpy(pdata->umax.data(),mxGetPr(prhs[5]),sizeof(double)*nu); pdata->B_act.resize(nu,nu); pdata->B_act = pdata->B.bottomRows(nu); // get the map ptr back from matlab if (!mxIsNumeric(prhs[6]) || mxGetNumberOfElements(prhs[6])!=1) mexErrMsgIdAndTxt("Drake:QPControllermex:BadInputs","the seventh argument should be the map ptr"); memcpy(&pdata->map_ptr,mxGetPr(prhs[6]),sizeof(pdata->map_ptr)); // pdata->map_ptr = NULL; if (!pdata->map_ptr) mexWarnMsgTxt("Map ptr is NULL. Assuming flat terrain at z=0"); // create gurobi environment error = GRBloadenv(&(pdata->env),NULL); // set solver params (http://www.gurobi.com/documentation/5.5/reference-manual/node798#sec:Parameters) mxArray* psolveropts = myGetProperty(pobj,"gurobi_options"); int method = (int) mxGetScalar(myGetField(psolveropts,"method")); CGE ( GRBsetintparam(pdata->env,"outputflag",0), pdata->env ); CGE ( GRBsetintparam(pdata->env,"method",method), pdata->env ); // CGE ( GRBsetintparam(pdata->env,"method",method), pdata->env ); CGE ( GRBsetintparam(pdata->env,"presolve",0), pdata->env ); if (method==2) { CGE ( GRBsetintparam(pdata->env,"bariterlimit",20), pdata->env ); CGE ( GRBsetintparam(pdata->env,"barhomogeneous",0), pdata->env ); CGE ( GRBsetdblparam(pdata->env,"barconvtol",0.0005), pdata->env ); } mxClassID cid; if (sizeof(pdata)==4) cid = mxUINT32_CLASS; else if (sizeof(pdata)==8) cid = mxUINT64_CLASS; else mexErrMsgIdAndTxt("Drake:constructModelmex:PointerSize","Are you on a 32-bit machine or 64-bit machine??"); plhs[0] = mxCreateNumericMatrix(1,1,cid,mxREAL); memcpy(mxGetData(plhs[0]),&pdata,sizeof(pdata)); // preallocate some memory pdata->H.resize(nq,nq); pdata->H_float.resize(6,nq); pdata->H_act.resize(nu,nq); pdata->C.resize(nq); pdata->C_float.resize(6); pdata->C_act.resize(nu); pdata->J.resize(3,nq); pdata->Jdot.resize(3,nq); pdata->J_xy.resize(2,nq); pdata->Jdot_xy.resize(2,nq); pdata->Hqp.resize(nq,nq); pdata->fqp.resize(nq); pdata->Ag.resize(6,nq); pdata->Agdot.resize(6,nq); pdata->Ak.resize(3,nq); pdata->Akdot.resize(3,nq); pdata->vbasis_len = 0; pdata->cbasis_len = 0; pdata->vbasis = NULL; pdata->cbasis = NULL; return; } // first get the ptr back from matlab if (!mxIsNumeric(prhs[0]) || mxGetNumberOfElements(prhs[0])!=1) mexErrMsgIdAndTxt("Drake:QPControllermex:BadInputs","the first argument should be the ptr"); memcpy(&pdata,mxGetData(prhs[0]),sizeof(pdata)); // for (i=0; i<pdata->r->num_bodies; i++) // mexPrintf("body %d (%s) has %d contact points\n", i, pdata->r->bodies[i].linkname.c_str(), pdata->r->bodies[i].contact_pts.cols()); int nu = pdata->B.cols(), nq = pdata->r->num_dof; const int dim = 3, // 3D nd = 2*m_surface_tangents; // for friction cone approx, hard coded for now assert(nu+6 == nq); int narg=1; int use_fast_qp = (int) mxGetScalar(prhs[narg++]); Map< VectorXd > qddot_des(mxGetPr(prhs[narg++]),nq); double *q = mxGetPr(prhs[narg++]); double *qd = &q[nq]; vector<VectorXd,aligned_allocator<VectorXd>> body_accel_inputs; for (int i=0; i<pdata->n_body_accel_inputs; i++) { assert(mxGetM(prhs[narg])==7); assert(mxGetN(prhs[narg])==1); VectorXd v = VectorXd::Zero(7,1); memcpy(v.data(),mxGetPr(prhs[narg++]),sizeof(double)*7); body_accel_inputs.push_back(v); } int num_condof; VectorXd condof; if (!mxIsEmpty(prhs[narg])) { assert(mxGetN(prhs[narg])==1); num_condof=mxGetM(prhs[narg]); condof = VectorXd::Zero(num_condof); memcpy(condof.data(),mxGetPr(prhs[narg++]),sizeof(double)*num_condof); } else { num_condof=0; narg++; // skip over empty vector } int desired_support_argid = narg++; Map<MatrixXd> A_ls(mxGetPr(prhs[narg]),mxGetM(prhs[narg]),mxGetN(prhs[narg])); narg++; Map<MatrixXd> B_ls(mxGetPr(prhs[narg]),mxGetM(prhs[narg]),mxGetN(prhs[narg])); narg++; Map<MatrixXd> Qy (mxGetPr(prhs[narg]),mxGetM(prhs[narg]),mxGetN(prhs[narg])); narg++; Map<MatrixXd> R_ls(mxGetPr(prhs[narg]),mxGetM(prhs[narg]),mxGetN(prhs[narg])); narg++; Map<MatrixXd> C_ls(mxGetPr(prhs[narg]),mxGetM(prhs[narg]),mxGetN(prhs[narg])); narg++; Map<MatrixXd> D_ls(mxGetPr(prhs[narg]),mxGetM(prhs[narg]),mxGetN(prhs[narg])); narg++; Map<MatrixXd> S (mxGetPr(prhs[narg]),mxGetM(prhs[narg]),mxGetN(prhs[narg])); narg++; Map<VectorXd> s1(mxGetPr(prhs[narg]),mxGetM(prhs[narg])); narg++; Map<VectorXd> s1dot(mxGetPr(prhs[narg]),mxGetM(prhs[narg])); narg++; double s2dot = mxGetScalar(prhs[narg++]); Map<VectorXd> x0(mxGetPr(prhs[narg]),mxGetM(prhs[narg])); narg++; Map<VectorXd> u0(mxGetPr(prhs[narg]),mxGetM(prhs[narg])); narg++; Map<VectorXd> y0(mxGetPr(prhs[narg]),mxGetM(prhs[narg])); narg++; Map<VectorXd> qdd_lb(mxGetPr(prhs[narg]),mxGetM(prhs[narg])); narg++; Map<VectorXd> qdd_ub(mxGetPr(prhs[narg]),mxGetM(prhs[narg])); narg++; memcpy(pdata->w_qdd.data(),mxGetPr(prhs[narg++]),sizeof(double)*nq); double mu = mxGetScalar(prhs[narg++]); double terrain_height = mxGetScalar(prhs[narg++]); // nonzero if we're using DRCFlatTerrainMap MatrixXd R_DQyD_ls = R_ls + D_ls.transpose()*Qy*D_ls; pdata->r->doKinematics(q,false,qd); //--------------------------------------------------------------------- // Compute active support from desired supports ----------------------- vector<SupportStateElement> active_supports; set<int> contact_bodies; // redundant, clean up later int num_active_contact_pts=0; if (!mxIsEmpty(prhs[desired_support_argid])) { VectorXd phi; mxArray* mxBodies = myGetField(prhs[desired_support_argid],"bodies"); if (!mxBodies) mexErrMsgTxt("couldn't get bodies"); double* pBodies = mxGetPr(mxBodies); mxArray* mxContactPts = myGetField(prhs[desired_support_argid],"contact_pts"); if (!mxContactPts) mexErrMsgTxt("couldn't get contact points"); mxArray* mxContactSurfaces = myGetField(prhs[desired_support_argid],"contact_surfaces"); if (!mxContactSurfaces) mexErrMsgTxt("couldn't get contact surfaces"); double* pContactSurfaces = mxGetPr(mxContactSurfaces); for (i=0; i<mxGetNumberOfElements(mxBodies);i++) { mxArray* mxBodyContactPts = mxGetCell(mxContactPts,i); int nc = mxGetNumberOfElements(mxBodyContactPts); if (nc<1) continue; SupportStateElement se; se.body_idx = (int) pBodies[i]-1; pr = mxGetPr(mxBodyContactPts); for (j=0; j<nc; j++) { se.contact_pt_inds.insert((int)pr[j]-1); } se.contact_surface = (int) pContactSurfaces[i]-1; active_supports.push_back(se); num_active_contact_pts += nc; contact_bodies.insert((int)se.body_idx); } } pdata->r->HandC(q,qd,(MatrixXd*)NULL,pdata->H,pdata->C,(MatrixXd*)NULL,(MatrixXd*)NULL,(MatrixXd*)NULL); pdata->H_float = pdata->H.topRows(6); pdata->H_act = pdata->H.bottomRows(nu); pdata->C_float = pdata->C.head(6); pdata->C_act = pdata->C.tail(nu); bool include_angular_momentum = (pdata->W_kdot.array().maxCoeff() > 1e-10); if (include_angular_momentum) { pdata->r->getCMM(q,qd,pdata->Ag,pdata->Agdot); pdata->Ak = pdata->Ag.topRows(3); pdata->Akdot = pdata->Agdot.topRows(3); } Vector3d xcom; // consider making all J's into row-major pdata->r->getCOM(xcom); pdata->r->getCOMJac(pdata->J); pdata->r->getCOMJacDot(pdata->Jdot); pdata->J_xy = pdata->J.topRows(2); pdata->Jdot_xy = pdata->Jdot.topRows(2); MatrixXd Jcom,Jcomdot; if (x0.size()==6) { Jcom = pdata->J; Jcomdot = pdata->Jdot; } else { Jcom = pdata->J_xy; Jcomdot = pdata->Jdot_xy; } Map<VectorXd> qdvec(qd,nq); MatrixXd B,JB,Jp,Jpdot,normals; int nc = contactConstraintsBV(pdata->r,num_active_contact_pts,mu,active_supports,pdata->map_ptr,B,JB,Jp,Jpdot,normals,terrain_height); int neps = nc*dim; VectorXd x_bar,xlimp; MatrixXd D_float(6,JB.cols()), D_act(nu,JB.cols()); if (nc>0) { if (x0.size()==6) { // x,y,z com xlimp.resize(6); xlimp.topRows(3) = xcom; xlimp.bottomRows(3) = Jcom*qdvec; } else { xlimp.resize(4); xlimp.topRows(2) = xcom.topRows(2); xlimp.bottomRows(2) = Jcom*qdvec; } x_bar = xlimp-x0; D_float = JB.topRows(6); D_act = JB.bottomRows(nu); } int nf = nc*nd; // number of contact force variables int nparams = nq+nf+neps; Vector3d kdot_des; if (include_angular_momentum) { VectorXd k = pdata->Ak*qdvec; kdot_des = -pdata->Kp_ang*k; // TODO: parameterize } //---------------------------------------------------------------------- // QP cost function ---------------------------------------------------- // // min: ybar*Qy*ybar + ubar*R*ubar + (2*S*xbar + s1)*(A*x + B*u) + // w_qdd*quad(qddot_ref - qdd) + w_eps*quad(epsilon) + // w_grf*quad(beta) + quad(kdot_des - (A*qdd + Adot*qd)) VectorXd f(nparams); { if (nc > 0) { // NOTE: moved Hqp calcs below, because I compute the inverse directly for FastQP (and sparse Hqp for gurobi) VectorXd tmp = C_ls*xlimp; VectorXd tmp1 = Jcomdot*qdvec; MatrixXd tmp2 = R_DQyD_ls*Jcom; pdata->fqp = tmp.transpose()*Qy*D_ls*Jcom; pdata->fqp += tmp1.transpose()*tmp2; pdata->fqp += (S*x_bar + 0.5*s1).transpose()*B_ls*Jcom; pdata->fqp -= u0.transpose()*tmp2; pdata->fqp -= y0.transpose()*Qy*D_ls*Jcom; pdata->fqp -= (pdata->w_qdd.array()*qddot_des.array()).matrix().transpose(); if (include_angular_momentum) { pdata->fqp += qdvec.transpose()*pdata->Akdot.transpose()*pdata->W_kdot*pdata->Ak; pdata->fqp -= kdot_des.transpose()*pdata->W_kdot*pdata->Ak; } f.head(nq) = pdata->fqp.transpose(); } else { f.head(nq) = -qddot_des; } } f.tail(nf+neps) = VectorXd::Zero(nf+neps); int neq = 6+neps+6*pdata->n_body_accel_eq_constraints+num_condof; MatrixXd Aeq = MatrixXd::Zero(neq,nparams); VectorXd beq = VectorXd::Zero(neq); // constrained floating base dynamics // H_float*qdd - J_float'*lambda - Dbar_float*beta = -C_float Aeq.topLeftCorner(6,nq) = pdata->H_float; beq.topRows(6) = -pdata->C_float; if (nc>0) { Aeq.block(0,nq,6,nc*nd) = -D_float; } if (nc > 0) { // relative acceleration constraint Aeq.block(6,0,neps,nq) = Jp; Aeq.block(6,nq,neps,nf) = MatrixXd::Zero(neps,nf); // note: obvious sparsity here Aeq.block(6,nq+nf,neps,neps) = MatrixXd::Identity(neps,neps); // note: obvious sparsity here beq.segment(6,neps) = (-Jpdot -pdata->Kp_accel*Jp)*qdvec; } // add in body spatial equality constraints VectorXd body_vdot; MatrixXd orig = MatrixXd::Zero(4,1); orig(3,0) = 1; int body_idx; int equality_ind = 6+neps; MatrixXd Jb(6,nq); MatrixXd Jbdot(6,nq); for (int i=0; i<pdata->n_body_accel_inputs; i++) { if (pdata->body_accel_input_weights(i) < 0) { // negative implies constraint body_vdot = body_accel_inputs[i].bottomRows(6); body_idx = (int)(body_accel_inputs[i][0])-1; if (!inSupport(active_supports,body_idx)) { pdata->r->forwardJac(body_idx,orig,1,Jb); pdata->r->forwardJacDot(body_idx,orig,1,Jbdot); for (int j=0; j<6; j++) { if (!std::isnan(body_vdot[j])) { Aeq.block(equality_ind,0,1,nq) = Jb.row(j); beq[equality_ind++] = -Jbdot.row(j)*qdvec + body_vdot[j]; } } } } } if (num_condof>0) { // add joint acceleration constraints for (int i=0; i<num_condof; i++) { Aeq(equality_ind,(int)condof[i]-1) = 1; beq[equality_ind++] = qddot_des[(int)condof[i]-1]; } } int n_ineq = 2*nu+2*6*pdata->n_body_accel_bounds; MatrixXd Ain = MatrixXd::Zero(n_ineq,nparams); // note: obvious sparsity here VectorXd bin = VectorXd::Zero(n_ineq); // linear input saturation constraints // u=B_act'*(H_act*qdd + C_act - Jz_act'*z - Dbar_act*beta) // using transpose instead of inverse because B is orthogonal Ain.topLeftCorner(nu,nq) = pdata->B_act.transpose()*pdata->H_act; Ain.block(0,nq,nu,nc*nd) = -pdata->B_act.transpose()*D_act; bin.head(nu) = -pdata->B_act.transpose()*pdata->C_act + pdata->umax; Ain.block(nu,0,nu,nparams) = -1*Ain.block(0,0,nu,nparams); bin.segment(nu,nu) = pdata->B_act.transpose()*pdata->C_act - pdata->umin; int body_index; int constraint_start_index = 2*nu; for (int i=0; i<pdata->n_body_accel_bounds; i++) { body_index = pdata->accel_bound_body_idx[i]; pdata->r->forwardJac(body_index,orig,1,Jb); pdata->r->forwardJacDot(body_index,orig,1,Jbdot); Ain.block(constraint_start_index,0,6,pdata->r->num_dof) = Jb; bin.segment(constraint_start_index,6) = -Jbdot*qdvec + pdata->max_body_acceleration[i]; constraint_start_index += 6; Ain.block(constraint_start_index,0,6,pdata->r->num_dof) = -Jb; bin.segment(constraint_start_index,6) = Jbdot*qdvec - pdata->min_body_acceleration[i]; constraint_start_index += 6; } for (int i=0; i<n_ineq; i++) { // remove inf constraints---needed by gurobi if (std::isinf(double(bin(i)))) { Ain.row(i) = 0*Ain.row(i); bin(i)=0; } } GRBmodel * model = NULL; int info=-1; // set obj,lb,up VectorXd lb(nparams), ub(nparams); lb.head(nq) = qdd_lb; ub.head(nq) = qdd_ub; lb.segment(nq,nf) = VectorXd::Zero(nf); ub.segment(nq,nf) = 1e3*VectorXd::Ones(nf); lb.tail(neps) = -pdata->slack_limit*VectorXd::Ones(neps); ub.tail(neps) = pdata->slack_limit*VectorXd::Ones(neps); VectorXd alpha(nparams); MatrixXd Qnfdiag(nf,1), Qneps(neps,1); vector<MatrixXd*> QBlkDiag( nc>0 ? 3 : 1 ); // nq, nf, neps // this one is for gurobi VectorXd w = (pdata->w_qdd.array() + REG).matrix(); #ifdef USE_MATRIX_INVERSION_LEMMA bool include_body_accel_cost_terms = pdata->n_body_accel_inputs > 0 && pdata->body_accel_input_weights.array().maxCoeff() > 1e-10; if (use_fast_qp > 0 && !include_angular_momentum && !include_body_accel_cost_terms) { // TODO: update to include angular momentum, body accel objectives. // We want Hqp inverse, which I can compute efficiently using the // matrix inversion lemma (see wikipedia): // inv(A + U'CV) = inv(A) - inv(A)*U* inv([ inv(C)+ V*inv(A)*U ]) V inv(A) if (nc>0) { MatrixXd Wi = ((1/(pdata->w_qdd.array() + REG)).matrix()).asDiagonal(); if (R_DQyD_ls.trace()>1e-15) { // R_DQyD_ls is not zero pdata->Hqp = Wi - Wi*Jcom.transpose()*(R_DQyD_ls.inverse() + Jcom*Wi*Jcom.transpose()).inverse()*Jcom*Wi; } } else { pdata->Hqp = MatrixXd::Constant(nq,1,1/(1+REG)); } #ifdef TEST_FAST_QP if (nc>0) { MatrixXd Hqp_test(nq,nq); MatrixXd W = w.asDiagonal(); Hqp_test = (Jcom.transpose()*R_DQyD_ls*Jcom + W).inverse(); if (((Hqp_test-pdata->Hqp).array().abs()).maxCoeff() > 1e-6) { mexErrMsgTxt("Q submatrix inverse from matrix inversion lemma does not match direct Q inverse."); } } #endif Qnfdiag = MatrixXd::Constant(nf,1,1/REG); Qneps = MatrixXd::Constant(neps,1,1/(.001+REG)); QBlkDiag[0] = &pdata->Hqp; if (nc>0) { QBlkDiag[1] = &Qnfdiag; QBlkDiag[2] = &Qneps; // quadratic slack var cost, Q(nparams-neps:end,nparams-neps:end)=eye(neps) } MatrixXd Ain_lb_ub(n_ineq+2*nparams,nparams); VectorXd bin_lb_ub(n_ineq+2*nparams); Ain_lb_ub << Ain, // note: obvious sparsity here -MatrixXd::Identity(nparams,nparams), MatrixXd::Identity(nparams,nparams); bin_lb_ub << bin, -lb, ub; info = fastQPThatTakesQinv(QBlkDiag, f, Aeq, beq, Ain_lb_ub, bin_lb_ub, pdata->active, alpha); //if (info<0) mexPrintf("fastQP info = %d. Calling gurobi.\n", info); } else { #endif if (nc>0) { pdata->Hqp = Jcom.transpose()*R_DQyD_ls*Jcom; if (include_angular_momentum) { pdata->Hqp += pdata->Ak.transpose()*pdata->W_kdot*pdata->Ak; } pdata->Hqp += pdata->w_qdd.asDiagonal(); pdata->Hqp += REG*MatrixXd::Identity(nq,nq); } else { pdata->Hqp = (1+REG)*MatrixXd::Identity(nq,nq); } // add in body spatial acceleration cost terms double w_i; for (int i=0; i<pdata->n_body_accel_inputs; i++) { w_i=pdata->body_accel_input_weights(i); if (w_i > 0) { body_vdot = body_accel_inputs[i].bottomRows(6); body_idx = (int)(body_accel_inputs[i][0])-1; if (!inSupport(active_supports,body_idx)) { pdata->r->forwardJac(body_idx,orig,1,Jb); pdata->r->forwardJacDot(body_idx,orig,1,Jbdot); for (int j=0; j<6; j++) { if (!std::isnan(body_vdot[j])) { pdata->Hqp += w_i*(Jb.row(j)).transpose()*Jb.row(j); f.head(nq) += w_i*(qdvec.transpose()*Jbdot.row(j).transpose() - body_vdot[j])*Jb.row(j).transpose(); } } } } } Qnfdiag = MatrixXd::Constant(nf,1,pdata->w_grf+REG); Qneps = MatrixXd::Constant(neps,1,pdata->w_slack+REG); QBlkDiag[0] = &pdata->Hqp; if (nc>0) { QBlkDiag[1] = &Qnfdiag; QBlkDiag[2] = &Qneps; // quadratic slack var cost, Q(nparams-neps:end,nparams-neps:end)=eye(neps) } MatrixXd Ain_lb_ub(n_ineq+2*nparams,nparams); VectorXd bin_lb_ub(n_ineq+2*nparams); Ain_lb_ub << Ain, // note: obvious sparsity here -MatrixXd::Identity(nparams,nparams), MatrixXd::Identity(nparams,nparams); bin_lb_ub << bin, -lb, ub; if (use_fast_qp > 0) { // set up and call fastqp info = fastQP(QBlkDiag, f, Aeq, beq, Ain_lb_ub, bin_lb_ub, pdata->active, alpha); //if (info<0) mexPrintf("fastQP info=%d... calling Gurobi.\n", info); } else { // use gurobi active set model = gurobiActiveSetQP(pdata->env,QBlkDiag,f,Aeq,beq,Ain,bin,lb,ub,pdata->vbasis,pdata->vbasis_len,pdata->cbasis,pdata->cbasis_len,alpha); CGE(GRBgetintattr(model,"NumVars",&pdata->vbasis_len), pdata->env); CGE(GRBgetintattr(model,"NumConstrs",&pdata->cbasis_len), pdata->env); info=66; //info = -1; } if (info<0) { model = gurobiQP(pdata->env,QBlkDiag,f,Aeq,beq,Ain,bin,lb,ub,pdata->active,alpha); int status; CGE(GRBgetintattr(model, "Status", &status), pdata->env); //if (status!=2) mexPrintf("Gurobi reports non-optimal status = %d\n", status); } #ifdef USE_MATRIX_INVERSION_LEMMA } #endif //---------------------------------------------------------------------- // Solve for inputs ---------------------------------------------------- VectorXd y(nu); VectorXd qdd = alpha.head(nq); VectorXd beta = alpha.segment(nq,nc*nd); // use transpose because B_act is orthogonal y = pdata->B_act.transpose()*(pdata->H_act*qdd + pdata->C_act - D_act*beta); //y = pdata->B_act.jacobiSvd(ComputeThinU|ComputeThinV).solve(pdata->H_act*qdd + pdata->C_act - Jz_act.transpose()*lambda - D_act*beta); if (nlhs>0) { plhs[0] = eigenToMatlab(y); } if (nlhs>1) { plhs[1] = eigenToMatlab(qdd); } if (nlhs>2) { plhs[2] = mxCreateNumericMatrix(1,1,mxINT32_CLASS,mxREAL); memcpy(mxGetData(plhs[2]),&info,sizeof(int)); } if (nlhs>3) { plhs[3] = mxCreateDoubleMatrix(1,active_supports.size(),mxREAL); pr = mxGetPr(plhs[3]); int i=0; for (vector<SupportStateElement>::iterator iter = active_supports.begin(); iter!=active_supports.end(); iter++) { pr[i++] = (double) (iter->body_idx + 1); } } if (nlhs>4) { plhs[4] = eigenToMatlab(alpha); } if (nlhs>5) { plhs[5] = eigenToMatlab(pdata->Hqp); } if (nlhs>6) { plhs[6] = eigenToMatlab(f); } if (nlhs>7) { plhs[7] = eigenToMatlab(Aeq); } if (nlhs>8) { plhs[8] = eigenToMatlab(beq); } if (nlhs>9) { plhs[9] = eigenToMatlab(Ain_lb_ub); } if (nlhs>10) { plhs[10] = eigenToMatlab(bin_lb_ub); } if (nlhs>11) { plhs[11] = eigenToMatlab(Qnfdiag); } if (nlhs>12) { plhs[12] = eigenToMatlab(Qneps); } if (nlhs>13) { double Vdot; if (nc>0) // note: Sdot is 0 for ZMP/double integrator dynamics, so we omit that term here Vdot = ((2*x_bar.transpose()*S + s1.transpose())*(A_ls*x_bar + B_ls*(Jcomdot*qdvec + Jcom*qdd)) + s1dot.transpose()*x_bar)(0) + s2dot; else Vdot = 0; plhs[13] = mxCreateDoubleScalar(Vdot); } if (nlhs>14) { RigidBodyManipulator* r = pdata->r; VectorXd individual_cops = individualSupportCOPs(r, active_supports, normals, B, beta); plhs[14] = eigenToMatlab(individual_cops); } if (model) { GRBfreemodel(model); } // GRBfreeenv(env); }
CFeatures* CJade::apply(CFeatures* features) { ASSERT(features); SG_REF(features); SGMatrix<float64_t> X = ((CDenseFeatures<float64_t>*)features)->get_feature_matrix(); int n = X.num_rows; int T = X.num_cols; int m = n; Map<MatrixXd> EX(X.matrix,n,T); // Mean center X VectorXd mean = (EX.rowwise().sum() / (float64_t)T); MatrixXd SPX = EX.colwise() - mean; MatrixXd cov = (SPX * SPX.transpose()) / (float64_t)T; #ifdef DEBUG_JADE std::cout << "cov" << std::endl; std::cout << cov << std::endl; #endif // Whitening & Projection onto signal subspace SelfAdjointEigenSolver<MatrixXd> eig; eig.compute(cov); #ifdef DEBUG_JADE std::cout << "eigenvectors" << std::endl; std::cout << eig.eigenvectors() << std::endl; std::cout << "eigenvalues" << std::endl; std::cout << eig.eigenvalues().asDiagonal() << std::endl; #endif // Scaling VectorXd scales = eig.eigenvalues().cwiseSqrt(); MatrixXd B = scales.cwiseInverse().asDiagonal() * eig.eigenvectors().transpose(); #ifdef DEBUG_JADE std::cout << "whitener" << std::endl; std::cout << B << std::endl; #endif // Sphering SPX = B * SPX; // Estimation of the cumulant matrices int dimsymm = (m * ( m + 1)) / 2; // Dim. of the space of real symm matrices int nbcm = dimsymm; // number of cumulant matrices m_cumulant_matrix = SGMatrix<float64_t>(m,m*nbcm); // Storage for cumulant matrices Map<MatrixXd> CM(m_cumulant_matrix.matrix,m,m*nbcm); MatrixXd R(m,m); R.setIdentity(); MatrixXd Qij = MatrixXd::Zero(m,m); // Temp for a cum. matrix VectorXd Xim = VectorXd::Zero(m); // Temp VectorXd Xjm = VectorXd::Zero(m); // Temp VectorXd Xijm = VectorXd::Zero(m); // Temp int Range = 0; for (int im = 0; im < m; im++) { Xim = SPX.row(im); Xijm = Xim.cwiseProduct(Xim); Qij = SPX.cwiseProduct(Xijm.replicate(1,m).transpose()) * SPX.transpose() / (float)T - R - 2*R.col(im)*R.col(im).transpose(); CM.block(0,Range,m,m) = Qij; Range = Range + m; for (int jm = 0; jm < im; jm++) { Xjm = SPX.row(jm); Xijm = Xim.cwiseProduct(Xjm); Qij = SPX.cwiseProduct(Xijm.replicate(1,m).transpose()) * SPX.transpose() / (float)T - R.col(im)*R.col(jm).transpose() - R.col(jm)*R.col(im).transpose(); CM.block(0,Range,m,m) = sqrt(2)*Qij; Range = Range + m; } } #ifdef DEBUG_JADE std::cout << "cumulatant matrices" << std::endl; std::cout << CM << std::endl; #endif // Stack cumulant matrix into ND Array index_t * M_dims = SG_MALLOC(index_t, 3); M_dims[0] = m; M_dims[1] = m; M_dims[2] = nbcm; SGNDArray< float64_t > M(M_dims, 3); for (int i = 0; i < nbcm; i++) { Map<MatrixXd> EM(M.get_matrix(i),m,m); EM = CM.block(0,i*m,m,m); } // Diagonalize SGMatrix<float64_t> Q = CJADiagOrth::diagonalize(M, m_mixing_matrix, tol, max_iter); Map<MatrixXd> EQ(Q.matrix,m,m); EQ = -1 * EQ.inverse(); #ifdef DEBUG_JADE std::cout << "diagonalizer" << std::endl; std::cout << EQ << std::endl; #endif // Separating matrix SGMatrix<float64_t> sep_matrix = SGMatrix<float64_t>(m,m); Map<MatrixXd> C(sep_matrix.matrix,m,m); C = EQ.transpose() * B; // Sort VectorXd A = (B.inverse()*EQ).cwiseAbs2().colwise().sum(); bool swap = false; do { swap = false; for (int j = 1; j < n; j++) { if ( A(j) < A(j-1) ) { std::swap(A(j),A(j-1)); C.col(j).swap(C.col(j-1)); swap = true; } } } while(swap); for (int j = 0; j < m/2; j++) C.row(j).swap( C.row(m-1-j) ); // Fix Signs VectorXd signs = VectorXd::Zero(m); for (int i = 0; i < m; i++) { if( C(i,0) < 0 ) signs(i) = -1; else signs(i) = 1; } C = signs.asDiagonal() * C; #ifdef DEBUG_JADE std::cout << "un mixing matrix" << std::endl; std::cout << C << std::endl; #endif // Unmix EX = C * EX; m_mixing_matrix = SGMatrix<float64_t>(m,m); Map<MatrixXd> Emixing_matrix(m_mixing_matrix.matrix,m,m); Emixing_matrix = C.inverse(); return features; }
/** create a matrix with designed eigenvalues. * A V = V E */ inline MatrixXd matE(const VectorXd &e){ int n = e.size(); MatrixXd V(MatrixXd::Random(n, n)); return V * e.asDiagonal() * V.inverse(); }
void RandomPCA::pca(MatrixXd &X, int method, bool transpose, unsigned int ndim, unsigned int nextra, unsigned int maxiter, double tol, long seed, int kernel, double sigma, bool rbf_center, unsigned int rbf_sample, bool save_kernel, bool do_orth, bool do_loadings) { unsigned int N; if(kernel != KERNEL_LINEAR) { transpose = false; verbose && std::cout << timestamp() << " Kernel not linear, can't transpose" << std::endl; } verbose && std::cout << timestamp() << " Transpose: " << (transpose ? "yes" : "no") << std::endl; if(transpose) { if(stand_method != STANDARDIZE_NONE) X_meansd = standardize_transpose(X, stand_method, verbose); N = X.cols(); } else { if(stand_method != STANDARDIZE_NONE) X_meansd = standardize(X, stand_method, verbose); N = X.rows(); } unsigned int total_dim = ndim + nextra; MatrixXd R = make_gaussian(X.cols(), total_dim, seed); MatrixXd Y = X * R; verbose && std::cout << timestamp() << " dim(Y): " << dim(Y) << std::endl; normalize(Y); MatrixXd Yn; verbose && std::cout << timestamp() << " dim(X): " << dim(X) << std::endl; MatrixXd K; if(kernel == KERNEL_RBF) { if(sigma == 0) { unsigned int med_samples = fminl(rbf_sample, N); double med = median_dist(X, med_samples, seed, verbose); sigma = sqrt(med); } verbose && std::cout << timestamp() << " Using RBF kernel with sigma=" << sigma << std::endl; K.noalias() = rbf_kernel(X, sigma, rbf_center, verbose); } else { verbose && std::cout << timestamp() << " Using linear kernel" << std::endl; K.noalias() = X * X.transpose() / (N - 1); } //trace = K.diagonal().array().sum() / (N - 1); trace = K.diagonal().array().sum(); verbose && std::cout << timestamp() << " Trace(K): " << trace << " (N: " << N << ")" << std::endl; verbose && std::cout << timestamp() << " dim(K): " << dim(K) << std::endl; if(save_kernel) { verbose && std::cout << timestamp() << " saving K" << std::endl; save_text("kernel.txt", K); } for(unsigned int iter = 0 ; iter < maxiter ; iter++) { verbose && std::cout << timestamp() << " iter " << iter; Yn.noalias() = K * Y; if(do_orth) { verbose && std::cout << " (orthogonalising)"; ColPivHouseholderQR<MatrixXd> qr(Yn); MatrixXd I = MatrixXd::Identity(Yn.rows(), Yn.cols()); Yn = qr.householderQ() * I; Yn.conservativeResize(NoChange, Yn.cols()); } else normalize(Yn); double diff = (Y - Yn).array().square().sum() / Y.size(); verbose && std::cout << " " << diff << std::endl; Y.noalias() = Yn; if(diff < tol) break; } verbose && std::cout << timestamp() << " QR begin" << std::endl; ColPivHouseholderQR<MatrixXd> qr(Y); MatrixXd Q = MatrixXd::Identity(Y.rows(), Y.cols()); Q = qr.householderQ() * Q; Q.conservativeResize(NoChange, Y.cols()); verbose && std::cout << timestamp() << " dim(Q): " << dim(Q) << std::endl; verbose && std::cout << timestamp() << " QR done" << std::endl; MatrixXd B = Q.transpose() * X; verbose && std::cout << timestamp() << " dim(B): " << dim(B) << std::endl; MatrixXd Et; pca_small(B, method, Et, d, verbose); verbose && std::cout << timestamp() << " dim(Et): " << dim(Et) << std::endl; d = d.array() / (N - 1); if(transpose) { V.noalias() = Q * Et; // We divide P by sqrt(N - 1) since X has not been divided // by it (but B has) P.noalias() = X.transpose() * V; VectorXd s = 1 / (d.array().sqrt() * sqrt(N - 1)); MatrixXd Dinv = s.asDiagonal(); U = P * Dinv; } else { // P = U D = X V U.noalias() = Q * Et; P.noalias() = U * d.asDiagonal(); if(do_loadings) { VectorXd s = 1 / (d.array().sqrt() * sqrt(N - 1)); MatrixXd Dinv = s.asDiagonal(); V = X.transpose() * U * Dinv; } } P.conservativeResize(NoChange, ndim); U.conservativeResize(NoChange, ndim); V.conservativeResize(NoChange, ndim); d.conservativeResize(ndim); pve = d.array() / trace; }
//#define IGL_LINPROG_VERBOSE IGL_INLINE bool igl::linprog( const Eigen::VectorXd & c, const Eigen::MatrixXd & _A, const Eigen::VectorXd & b, const int k, Eigen::VectorXd & x) { // This is a very literal translation of // http://www.mathworks.com/matlabcentral/fileexchange/2166-introduction-to-linear-algebra/content/strang/linprog.m using namespace Eigen; using namespace std; bool success = true; // number of constraints const int m = _A.rows(); // number of original variables const int n = _A.cols(); // number of iterations int it = 0; // maximum number of iterations //const int MAXIT = 10*m; const int MAXIT = 100*m; // residual tolerance const double tol = 1e-10; const auto & sign = [](const Eigen::VectorXd & B) -> Eigen::VectorXd { Eigen::VectorXd Bsign(B.size()); for(int i = 0;i<B.size();i++) { Bsign(i) = B(i)>0?1:(B(i)<0?-1:0); } return Bsign; }; // initial (inverse) basis matrix VectorXd Dv = sign(sign(b).array()+0.5); Dv.head(k).setConstant(1.); MatrixXd D = Dv.asDiagonal(); // Incorporate slack variables MatrixXd A(_A.rows(),_A.cols()+D.cols()); A<<_A,D; // Initial basis VectorXi B = igl::colon<int>(n,n+m-1); // non-basis, may turn out that vector<> would be better here VectorXi N = igl::colon<int>(0,n-1); int j; double bmin = b.minCoeff(&j); int phase; VectorXd xb; VectorXd s; VectorXi J; if(k>0 && bmin<0) { phase = 1; xb = VectorXd::Ones(m); // super cost s.resize(n+m+1); s<<VectorXd::Zero(n+k),VectorXd::Ones(m-k+1); N.resize(n+1); N<<igl::colon<int>(0,n-1),B(j); J.resize(B.size()-1); // [0 1 2 3 4] // ^ // [0 1] // [3 4] J.head(j) = B.head(j); J.tail(B.size()-j-1) = B.tail(B.size()-j-1); B(j) = n+m; MatrixXd AJ; igl::slice(A,J,2,AJ); const VectorXd a = b - AJ.rowwise().sum(); { MatrixXd old_A = A; A.resize(A.rows(),A.cols()+a.cols()); A<<old_A,a; } D.col(j) = -a/a(j); D(j,j) = 1./a(j); }else if(k==m) { phase = 2; xb = b; s.resize(c.size()+m); // cost function s<<c,VectorXd::Zero(m); }else //k = 0 or bmin >=0 { phase = 1; xb = b.array().abs(); s.resize(n+m); // super cost s<<VectorXd::Zero(n+k),VectorXd::Ones(m-k); } while(phase<3) { double df = -1; int t = std::numeric_limits<int>::max(); // Lagrange mutipliers fro Ax=b VectorXd yb = D.transpose() * igl::slice(s,B); while(true) { if(MAXIT>0 && it>=MAXIT) { #ifdef IGL_LINPROG_VERBOSE cerr<<"linprog: warning! maximum iterations without convergence."<<endl; #endif success = false; break; } // no freedom for minimization if(N.size() == 0) { break; } // reduced costs VectorXd sN = igl::slice(s,N); MatrixXd AN = igl::slice(A,N,2); VectorXd r = sN - AN.transpose() * yb; int q; // determine new basic variable double rmin = r.minCoeff(&q); // optimal! infinity norm if(rmin>=-tol*(sN.array().abs().maxCoeff()+1)) { break; } // increment iteration count it++; // apply Bland's rule to avoid cycling if(df>=0) { if(MAXIT == -1) { #ifdef IGL_LINPROG_VERBOSE cerr<<"linprog: warning! degenerate vertex"<<endl; #endif success = false; } igl::find((r.array()<0).eval(),J); double Nq = igl::slice(N,J).minCoeff(); // again seems like q is assumed to be a scalar though matlab code // could produce a vector for multiple matches (N.array()==Nq).cast<int>().maxCoeff(&q); } VectorXd d = D*A.col(N(q)); VectorXi I; igl::find((d.array()>tol).eval(),I); if(I.size() == 0) { #ifdef IGL_LINPROG_VERBOSE cerr<<"linprog: warning! solution is unbounded"<<endl; #endif // This seems dubious: it=-it; success = false; break; } VectorXd xbd = igl::slice(xb,I).array()/igl::slice(d,I).array(); // new use of r int p; { double r; r = xbd.minCoeff(&p); p = I(p); // apply Bland's rule to avoid cycling if(df>=0) { igl::find((xbd.array()==r).eval(),J); double Bp = igl::slice(B,igl::slice(I,J)).minCoeff(); // idiotic way of finding index in B of Bp // code down the line seems to assume p is a scalar though the matlab // code could find a vector of matches) (B.array()==Bp).cast<int>().maxCoeff(&p); } // update x xb -= r*d; xb(p) = r; // change in f df = r*rmin; } // row vector RowVectorXd v = D.row(p)/d(p); yb += v.transpose() * (s(N(q)) - d.transpose()*igl::slice(s,B)); d(p)-=1; // update inverse basis matrix D = D - d*v; t = B(p); B(p) = N(q); if(t>(n+k-1)) { // remove qth entry from N VectorXi old_N = N; N.resize(N.size()-1); N.head(q) = old_N.head(q); N.head(q) = old_N.head(q); N.tail(old_N.size()-q-1) = old_N.tail(old_N.size()-q-1); }else { N(q) = t; } } // iterative refinement xb = (xb+D*(b-igl::slice(A,B,2)*xb)).eval(); // must be due to rounding VectorXi I; igl::find((xb.array()<0).eval(),I); if(I.size()>0) { // so correct VectorXd Z = VectorXd::Zero(I.size(),1); igl::slice_into(Z,I,xb); } // B, xb,n,m,res=A(:,B)*xb-b if(phase == 2 || it<0) { break; } if(xb.transpose()*igl::slice(s,B) > tol) { it = -it; #ifdef IGL_LINPROG_VERBOSE cerr<<"linprog: warning, no feasible solution"<<endl; #endif success = false; break; } // re-initialize for Phase 2 phase = phase+1; s*=1e6*c.array().abs().maxCoeff(); s.head(n) = c; } x.resize(std::max(B.maxCoeff()+1,n)); igl::slice_into(xb,B,x); x = x.head(n).eval(); return success; }