ProblemStatus ColaModel::solve_numeric() { solve(false); // 1. determine original binding constraints std::vector<int> binding; int num_rows = getNumRows(); int orig_num_rows = num_rows - total_num_cuts_; int num_cols = getNumCols(); int * cstat = new int[num_cols]; int * rstat = new int[num_rows]; getBasisStatus(cstat, rstat); for (int i=0; i<orig_num_rows; ++i) { if (rstat[i]==2 or rstat[i]==3) { binding.push_back(i); } } int num_binding = binding.size(); delete[] cstat; delete[] rstat; // 2. compute AA^T // A is sparse and instance of CoinPackedMatrix // 2.1 get A CoinPackedMatrix const * mat = getMatrixByRow(); CoinPackedMatrix * A = new CoinPackedMatrix(false, 500, 500); std::vector<int>::const_iterator it; for (it=binding.begin(); it!=binding.end(); ++it) { int first = mat->getVectorFirst(*it); int last = mat->getVectorLast(*it); int num_elem = last-first; int const * mat_cols = mat->getIndices() + first; double const * mat_value = mat->getElements() + first; A->appendRow(CoinPackedVector(num_elem, mat_cols, mat_value)); } // 2.2 Compute AAt CoinPackedMatrix * AAt = new CoinPackedMatrix(); double * Aa_i = new double[num_binding]; int * Aa_i_cols = new int[num_binding]; double * Aa_i_vals = new double[num_binding]; for (it=binding.begin(); it!=binding.end(); ++it) { // A times row i of A int first = mat->getVectorFirst(*it); int last = mat->getVectorLast(*it); int num_elem = last-first; int const * mat_cols = mat->getIndices() + first; double const * mat_value = mat->getElements() + first; A->times(CoinPackedVector(num_elem, mat_cols, mat_value), Aa_i); // sparsify and insert Aa_i int Aa_i_size = 0; for (int i=0; i<num_binding; ++i) { if (Aa_i[i]!=0.0) { Aa_i_cols[Aa_i_size] = i; Aa_i_vals[Aa_i_size] = Aa_i[i]; Aa_i_size++; } } AAt->appendCol(CoinPackedVector(Aa_i_size, Aa_i_cols, Aa_i_vals)); } delete[] Aa_i; delete[] Aa_i_cols; delete[] Aa_i_vals; //AAt->dumpMatrix(); // 3. compute Ac double * Ac = new double[num_binding]; double const * obj = getObjCoefficients(); int obj_size; int * obj_cols = new int[num_cols]; double * obj_vals = new double[num_cols]; for (int i=0; i<num_cols; ++i) { if (obj[i]!=0) { obj_cols[obj_size] = i; obj_vals[obj_size] = obj[i]; obj_size++; } } A->times(CoinPackedVector(obj_size, obj_cols, obj_vals), Ac); delete[] obj_cols; delete[] obj_vals; // 4. compute (b-Ac) double * b = new double[num_binding]; int k=0; for (it=binding.begin(); it!=binding.end(); ++it) { b[k] = getRightHandSide()[*it]; k++; } double * b_Ac = new double[num_binding]; for (int i=0; i<num_binding; ++i) { b_Ac[i] = b[i] - Ac[i]; } // 5. solve AA^Ty=(b-Ac) // 5.1 get AAt in lower triangular format double ** AAt_dense = new double*[num_binding]; for (int i=0; i<num_binding; ++i) { AAt_dense[i] = new double[num_binding](); } int const * AAt_cols = AAt->getIndices(); double const * AAt_value = AAt->getElements(); for (int i=0; i<num_binding; ++i) { // get row i int first = AAt->getVectorFirst(i); int last = AAt->getVectorLast(i); //int num_elem = last-first; for (int j=first; j<last; ++j) { AAt_dense[i][AAt_cols[j]] = AAt_value[j]; } } // 5.2 call lapack routine to solve the system double * y = new double[num_binding]; lapack_solve(AAt_dense, b_Ac, y, num_binding); // 6. compute d <- c+A^Ty // in other words x <- c + A'(AA')^{-1}b - A'(AA')^{-1}Ac when // we insert for y. // 6.1 compute Aty double * Aty = new double[num_cols]; A->transposeTimes(y, Aty); // 6.2 compute d <- c+A^Ty double * dir = new double[num_cols]; double const * cur_sol = getColSolution(); for (int i=0; i<num_cols; ++i) { dir[i] = -obj[i] - Aty[i]; } // 7. go along direction until we hit boundry, ie. compute step_size double step_size = 0.0; int num_cones = getNumCones(); imp_solution_ = new double[num_cols]; std::copy(cur_sol, cur_sol+num_cols, imp_solution_); double * par_sol; double * par_dir; for (int i=0; i<num_cones; ++i) { int cone_size = cones_[i]->size(); LorentzCone * con = dynamic_cast<LorentzCone*>(cones_[i]); int const * members = con->members(); par_sol = new double[cone_size]; par_dir = new double[cone_size]; // 7.1 compute step size // 7.2 compute a in ax^2+bx+c=0 // 7.3 compute b in ax^2+bx+c=0 // 7.4 compute c in ax^2+bx+c=0 for (int j=0; j<con->size(); j++) { par_sol[j] = cur_sol[members[j]]; par_dir[j] = dir[members[j]]; } double feas_i = par_sol[0]*par_sol[0]-std::inner_product(par_sol+1, par_sol+cone_size, par_sol+1, 0.0); if (feas_i > options_->get_dbl_option(TOL)) { delete[] par_sol; delete[] par_dir; continue; } double a = par_dir[0]*par_dir[0]; double b = par_sol[0]*par_dir[0]; double c = par_sol[0]*par_sol[0]; a = a - std::inner_product(par_dir+1, par_dir+con->size(), par_dir+1, 0.0); b = b - std::inner_product(par_sol+1, par_sol+con->size(), par_dir+1, 0.0); b = 2.0*b; c = c - std::inner_product(par_sol+1, par_sol+con->size(), par_sol+1, 0.0); // 7.5 compute step size double alpha1 = (-b+sqrt(b*b-4.0*a*c))/(2.0*a); double alpha2 = (-b-sqrt(b*b-4.0*a*c))/(2.0*a); double alpha=alpha1; std::cout << "alpha1 " << alpha1 << std::endl; std::cout << "alpha2 " << alpha2 << std::endl; // if (alpha2<alpha1) // alpha=alpha2; for (int j=0; j<con->size(); j++) { imp_solution_[members[j]] = cur_sol[members[j]] + alpha*par_dir[j]; } delete[] par_sol; delete[] par_dir; // get related portion of direction // get related portion of solution } delete A; delete AAt; delete[] Ac; delete[] b; delete[] b_Ac; for (int i=0; i<num_binding; ++i) { delete[] AAt_dense[i]; } delete[] AAt_dense; delete[] y; delete[] Aty; delete[] dir; // remove all the cuts and add a cut using the improved solution int * indices = new int[total_num_cuts_]; for (int i=0; i<total_num_cuts_; ++i) { indices[i] = orig_num_rows+i; } deleteRows(total_num_cuts_, indices); delete[] indices; total_num_cuts_ = 0; num_lp_solved_ = 0; std::fill(num_cuts_, num_cuts_+num_cones, 0); // separate from imp_solution Separate * sep = new Separate(cones_, imp_solution_, getNumCols(), options_); // returns true if given point is feasible for all cones. int feasible = sep->is_feasible(); while(!feasible) { // number of cuts generated // std::cout << "ColaModel: " << sep->cuts()->size() << " cuts generated." << std::endl; // add all the cuts generated // Add all the cuts generated std::vector<CoinPackedVector*> cut = sep->cuts(); std::vector<double> rhs = sep->rhs(); std::vector<int> gen_cone = sep->generating_cone(); int num_cuts = cut.size(); for (int i=0; i<num_cuts; ++i) { addRow(*cut[i], -getInfinity(), rhs[i]); // print cut // end of cut print total_num_cuts_++; num_cuts_[gen_cone[i]]++; } // if (num_lp_solved_%2==0) { // clean_redundant_constraints(); // } // resolve the problem num_lp_solved_++; OsiClpSolverInterface::resolve(); // update problem status update_problem_status(); // check problem status if (soco_status_!=OPTIMAL) break; delete sep; // chec if the new solution is feasible for cones sep = new Separate(cones_, getColSolution(), getNumCols(), options_); feasible = sep->is_feasible(); } delete sep; // update problem status update_problem_status(); // report feasibility of imp_solution_ double lhs = 0.0; double lhs_real = 0.0; std::cout << "Conic Constraints feasibility report" << std::endl; std::cout << std::setw(5) << std::left << "Cone"; // todo(aykut) this is not true all the time, what if cone is rotated. std::cout << std::setw(20) << std::left << "x1^2-sum x_i^2" << std::setw(20) << std::left << "x1-||x_{2:n}||" << std::endl; const double * full_sol = imp_solution_; //double * par_sol; for (int i=0; i<num_cones; ++i) { int cone_size = cones_[i]->size(); LorentzCone * con = dynamic_cast<LorentzCone*>(cones_[i]); const int * members = con->members(); par_sol = new double[cone_size]; for (int j=0; j<cone_size; ++j) { par_sol[j] = full_sol[members[j]]; } if (con->type()==LORENTZ) { lhs = par_sol[0]*par_sol[0] - std::inner_product(par_sol+1, par_sol+cone_size, par_sol+1, 0.0); lhs_real = par_sol[0] -sqrt(std::inner_product(par_sol+1, par_sol+cone_size, par_sol+1, 0.0)); } else if (con->type()==RLORENTZ) { lhs = 2.0*par_sol[0]*par_sol[1] - std::inner_product(par_sol+2, par_sol+cone_size, par_sol+2, 0.0); lhs_real = lhs; } std::cout << std::setw(5) << std::left << i << std::setw(20) << std::left << lhs << std::setw(20) << std::left << lhs_real << std::endl; delete[] par_sol; } return soco_status_; }
void ColaModel::resolve() { solve(true); update_problem_status(); }
ProblemStatus ColaModel::solve(bool resolve) { // todo(aykut) now we should check if the cone related data is initialized // properly. This is a problem when the user does not read problem from mps // file but builds the model herself using cola as a library. if (num_cuts_==0) { int nOfCones = getNumCones(); if (num_cuts_==0) { num_cuts_ = new int[nOfCones](); } if (num_supports_==0) { num_supports_ = new int[nOfCones](); } } if (first_solve_) { initialSolve(); first_solve_ = false; } // solve linear problem bool feasible = false; Separate * sep; // add nonnegativity of leading variables std::vector<Cone*>::const_iterator it; for (it=cones_.begin(); it!=cones_.end(); ++it) { (*it)->relax(*this); } // ===== End Of adding nonnegativity of leading variables //writeMps("initial", "mps"); num_lp_solved_++; if (resolve==false) { // if this function is called from OsiConicSolverInterface::initialSolve then OsiClpSolverInterface::initialSolve(); } else { // if it is called from OsiConicSolverInterface::resolve OsiClpSolverInterface::resolve(); } // check problem status update_problem_status(); if ((soco_status_!=OPTIMAL) && (soco_status_!=DUAL_INFEASIBLE)) return soco_status_; // if problem is unbounded add supporting hyperplanes for each cone using // objective coefficients. // todo(aykut) I guess SOCO is unbounded if LP is unbounded after all these // supporting hyperplanes. Check if this is true theoretically. if (soco_status_==DUAL_INFEASIBLE) { if (options_->get_int_option(LOG_LEVEL)>0) { std::cout << "Cola: Problem without conic constraints is unbounded. Adding" " supporting hyperplanes to resolve..." << std::endl; } while (soco_status_==DUAL_INFEASIBLE) { // check if primal is infeasible, then the problem is infeasible if (isProvenPrimalInfeasible()) { // Both LP primal and dual is infeasible, conic problem is infeasible std::cout << "Cola: Conic problem is infeasible." << std::endl << "Cola: Terminating..."; } // get one ray // todo(aykut) for now we get only one ray std::vector<double*> rays = getPrimalRays(1); const double * vec = 0; if (!rays.empty() and rays[0]!=0) { vec = rays[0]; } else { std::cout << "Cola: Warning! " << "LP is unbounded but solver did not return a " "direction of unboundedness." << std::endl << "Cola: Trying to generate supports using objective " "function coefficients..." << std::endl; vec = getObjCoefficients(); } // PRINT UNBDDNESS DIRECTION // std::cout << "Unboundedness direction is " << std::endl << "["; // for (int i=0; i<getNumCols(); ++i) { // std::cout << std::setw(10) << vec[i] << "; "; // } // std::cout << "]" << std::endl; // END OF DIRECTION PRINT sep = new Separate(cones_, vec, getNumCols(), options_); // returns true if direction is feasible for all cones. feasible = sep->is_feasible(); if (feasible) { // primal ray is feasible for all cone constraints, // problem is unbounded delete sep; soco_status_ = DUAL_INFEASIBLE; return DUAL_INFEASIBLE; } else { // Add all the cuts generated std::vector<CoinPackedVector*> cut = sep->cuts(); std::vector<double> rhs = sep->rhs(); std::vector<int> gen_cone = sep->generating_cone(); int num_cuts = cut.size(); for (int i=0; i<num_cuts; ++i) { addRow(*cut[i], -getInfinity(), rhs[i]); // print cut // end of cut print total_num_supports_++; num_supports_[gen_cone[i]]++; } } // todo(aykut) delete all rays not just first one. if (!rays.empty()) { for(int i=0; i<rays.size(); ++i) delete[] rays[i]; rays.clear(); } delete sep; num_lp_solved_++; OsiClpSolverInterface::resolve(); // update soco_status_ update_problem_status(); } } if (soco_status_!=OPTIMAL) { // it means it is not optimal after resolving unbounded directions std::cout << "Cola: Problem status is not optimal after adding " "supporting hyperplanes." << std::endl; std::cout << "Cola: Terminating..." << std::endl; return soco_status_; } // when we reached here, it means the problem is not unbounded anymore. // todo(aykut) pick the cone and all those logs and stuff. it can all go to separate. sep = new Separate(cones_, getColSolution(), getNumCols(), options_); // returns true if given point is feasible for all cones. feasible = sep->is_feasible(); while(!feasible) { // number of cuts generated // std::cout << "ColaModel: " << sep->cuts()->size() << " cuts generated." << std::endl; // add all the cuts generated // Add all the cuts generated std::vector<CoinPackedVector*> cut = sep->cuts(); std::vector<double> rhs = sep->rhs(); std::vector<int> gen_cone = sep->generating_cone(); int num_cuts = cut.size(); for (int i=0; i<num_cuts; ++i) { addRow(*cut[i], -getInfinity(), rhs[i]); // print cut // end of cut print total_num_cuts_++; num_cuts_[gen_cone[i]]++; } // if (num_lp_solved_%2==0) { // clean_redundant_constraints(); // } // resolve the problem num_lp_solved_++; OsiClpSolverInterface::resolve(); // update problem status update_problem_status(); // check problem status if (soco_status_!=OPTIMAL) break; delete sep; // chec if the new solution is feasible for cones sep = new Separate(cones_, getColSolution(), getNumCols(), options_); feasible = sep->is_feasible(); } delete sep; // update problem status update_problem_status(); // clean redundant constraints // clean_redundant_constraints(); return soco_status_; }
void ColaModel::initialSolveOA() { first_solve_ = false; solve(false); update_problem_status(); }
void ColaModel::initialSolveOA() { solve(false); update_problem_status(); }