[Cbc] Writing intermediate solutions via a CbcEventHandler
Luís Borges de Oliveira
lbo at siscog.pt
Fri Aug 19 13:48:01 EDT 2016
Hello,
I'm trying to write intermediate solutions using a CbcEventHandler
similarly to what is done in Cbc/examples/driver4.cpp. However, I'd like
to output the solution to the initial, non-preprocessed model. I've
tried to replicate what it is done in CbcMain1, after the B&B search
finishes, in particular calling CglPreProcess::postProcess, along with
some more handwaving based on what Cbc's nextBestSolution command does.
Alas, it's not working out. Not only am I not getting a solution with
the same number of columns as the original model, but accessing the the
ClpSimplex's columnNames segfaults at some point.
Here's the code I have so far. Any hints you provide would be very
useful at this point! Am I in the right track, or should I be doing
something completely different? (E.g., I've considered grabbing the
solution to the preprocessed model and feed it to
computeCompleteSolution() from CbcMipStartIO.cpp, assuming I can get
accurate variable names from the preprocessed model.)
#include <algorithm>
#include <fstream>
#include <sstream>
#include "CbcModel.hpp"
#include "OsiClpSolverInterface.hpp"
#include "CbcSolver.hpp"
#include "CbcEventHandler.hpp"
#include "CglPreProcess.hpp"
extern CglPreProcess*cbcPreProcessPointer;
class SolutionWriter :public CbcEventHandler {
CbcModel*original_model_;
string solution_prefix_;
string solution_directory_;
std::set<int>seen_solutions_; int external_solution_id_ = 1;
public:
virtual CbcEventHandler::CbcAction event(CbcEvent whichEvent) {
// If in sub tree carry on if (!model_->parentModel()) {
int solution_id = model_->getSolutionCount();
if ((whichEvent == solution || whichEvent == heuristicSolution)
&& seen_solutions_.find(solution_id) == seen_solutions_.end()) {
seen_solutions_.insert(solution_id);
const double*incumbent_solution = model_->bestSolution();
auto solver =dynamic_cast<OsiClpSolverInterface*> (model_->solver());
ClpSimplex*current_lp_solver = solver->getModelPtr();
ClpSimplex lp_solver{*current_lp_solver};
solver->swapModelPtr(&lp_solver);
double*lp_solver_solution = lp_solver.primalColumnSolution();
double*lp_solver_lower = lp_solver.columnLower();
double*lp_solver_upper = lp_solver.columnUpper();
int lp_solver_number_columns = lp_solver.numberColumns();
memcpy(lp_solver_solution, incumbent_solution,
lp_solver_number_columns *sizeof(double));
for (int i = 0; i < lp_solver_number_columns; i++) {
if (solver->isInteger(i)) {
double x = floor(lp_solver_solution[i] + 0.5);
lp_solver_lower[i] = lp_solver_upper[i] = x;
}
}
lp_solver.allSlackBasis();
lp_solver.initialSolve();
lp_solver.computeObjectiveValue(false);
cbcPreProcessPointer->postProcess(*solver);
// write solution
// XXX: some wishful thinking here: hoping we would see the // original number of columns at this point. lp_solver_number_columns = lp_solver.numberColumns();
const double*solution = solver->getColSolution();
const double*reduced_costs = solver->getReducedCost();
assert(solution && reduced_costs);
auto column_names = lp_solver.columnNames();
string::size_type max_name_length = 0;
for (auto const&name: *column_names) {
max_name_length =std::max(max_name_length, name.length());
}
stringstream filename;
filename << solution_directory_
<< solution_prefix_
<< external_solution_id_++
<<".txt";
{
ofstream out(filename.str());
if (!out.is_open()) {
std::cout <<"Couldn't open "
<< filename.str() <<" for writing " << endl;
abort();
}
char buf[100];
snprintf(buf,sizeof buf,"Incumbent - objective value %.8f\n",
lp_solver.getObjValue());
out << buf;
for (int i = 0; i < lp_solver_number_columns; i++) {
if (fabs(solution[i]) > 1.0e-8) {
auto&name = (*column_names)[i];
string padding(std::max(max_name_length, name.length())
- name.length(),' ');
char buf[100];
snprintf(buf,sizeof buf,"%7d %s%s %15.8g %15.8g\n",
i,
name.c_str(),
padding.c_str(),
solution[i],
reduced_costs[i]);
out << buf;
}
}
}
std::cout <<"[SolutionWriter] Solution saved to " << filename.str() <<std::endl;
solver->swapModelPtr(current_lp_solver);
}
}
return noAction;// carry on }
SolutionWriter() =delete;
SolutionWriter(const SolutionWriter&) =default;
SolutionWriter(const SolutionWriter&&) =delete;
SolutionWriter(CbcModel*model,
CbcModel*original,
const string&solution_prefix ="solution",
const string&solution_directory =".")
: CbcEventHandler(model),
original_model_(original),
solution_prefix_(solution_prefix),
solution_directory_(solution_directory) {
if (solution_directory_.back() !='/') solution_directory_.append("/");
}
virtual CbcEventHandler*clone()const override {
return new SolutionWriter(*this);
}
};
Thanks in advance,
Luís
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://list.coin-or.org/pipermail/cbc/attachments/20160819/fd01385e/attachment.html>
More information about the Cbc
mailing list