<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
</head>
<body bgcolor="#FFFFFF" text="#000000">
Hello,<br>
<br>
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.<br>
<br>
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.<br>
<br>
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.)<br>
<br>
<pre style="color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><span class="preprocessor" style="color: rgb(72, 61, 139);">#include</span> <span class="string" style="color: rgb(139, 34, 82);"><algorithm></span>
<span class="preprocessor" style="color: rgb(72, 61, 139);">#include</span> <span class="string" style="color: rgb(139, 34, 82);"><fstream></span>
<span class="preprocessor" style="color: rgb(72, 61, 139);">#include</span> <span class="string" style="color: rgb(139, 34, 82);"><sstream></span>
<span class="preprocessor" style="color: rgb(72, 61, 139);">#include</span> <span class="string" style="color: rgb(139, 34, 82);">"CbcModel.hpp"</span>
<span class="preprocessor" style="color: rgb(72, 61, 139);">#include</span> <span class="string" style="color: rgb(139, 34, 82);">"OsiClpSolverInterface.hpp"</span>
<span class="preprocessor" style="color: rgb(72, 61, 139);">#include</span> <span class="string" style="color: rgb(139, 34, 82);">"CbcSolver.hpp"</span>
<span class="preprocessor" style="color: rgb(72, 61, 139);">#include</span> <span class="string" style="color: rgb(139, 34, 82);">"CbcEventHandler.hpp"</span>
<span class="preprocessor" style="color: rgb(72, 61, 139);">#include</span> <span class="string" style="color: rgb(139, 34, 82);">"CglPreProcess.hpp"</span>
<span class="keyword" style="color: rgb(160, 32, 240);">extern</span> <span class="type" style="color: rgb(34, 139, 34);">CglPreProcess</span>* <span class="variable-name" style="color: rgb(160, 82, 45);">cbcPreProcessPointer</span>;
<span class="keyword" style="color: rgb(160, 32, 240);">class</span> <span class="type" style="color: rgb(34, 139, 34);">SolutionWriter</span> : <span class="keyword" style="color: rgb(160, 32, 240);">public</span> <span class="type" style="color: rgb(34, 139, 34);">CbcEventHandler</span> {
<span class="type" style="color: rgb(34, 139, 34);">CbcModel</span>* <span class="variable-name" style="color: rgb(160, 82, 45);">original_model_</span>;
<span class="type" style="color: rgb(34, 139, 34);">string</span> <span class="variable-name" style="color: rgb(160, 82, 45);">solution_prefix_</span>;
<span class="type" style="color: rgb(34, 139, 34);">string</span> <span class="variable-name" style="color: rgb(160, 82, 45);">solution_directory_</span>;
<span class="constant" style="color: rgb(0, 139, 139);">std</span>::<span class="type" style="color: rgb(34, 139, 34);">set</span><<span class="type" style="color: rgb(34, 139, 34);">int</span>> <span class="variable-name" style="color: rgb(160, 82, 45);">seen_solutions_</span>;<span class="comment" style="color: rgb(178, 34, 34);">
</span> <span class="type" style="color: rgb(34, 139, 34);">int</span> <span class="variable-name" style="color: rgb(160, 82, 45);">external_solution_id_</span> = 1;
<span class="keyword" style="color: rgb(160, 32, 240);">public</span>:
<span class="keyword" style="color: rgb(160, 32, 240);">virtual</span> <span class="constant" style="color: rgb(0, 139, 139);">CbcEventHandler</span>::<span class="type" style="color: rgb(34, 139, 34);">CbcAction</span> <span class="function-name" style="color: rgb(0, 0, 255);">event</span>(<span class="type" style="color: rgb(34, 139, 34);">CbcEvent</span> <span class="variable-name" style="color: rgb(160, 82, 45);">whichEvent</span>) {
<span class="comment-delimiter" style="color: rgb(178, 34, 34);">// </span><span class="comment" style="color: rgb(178, 34, 34);">If in sub tree carry on
</span> <span class="keyword" style="color: rgb(160, 32, 240);">if</span> (<span class="negation-char">!</span>model_->parentModel()) {
<span class="type" style="color: rgb(34, 139, 34);">int</span> <span class="variable-name" style="color: rgb(160, 82, 45);">solution_id</span> = model_->getSolutionCount();
<span class="keyword" style="color: rgb(160, 32, 240);">if</span> ((whichEvent == solution || whichEvent == heuristicSolution)
&& seen_solutions_.find(solution_id) == seen_solutions_.end()) {
seen_solutions_.insert(solution_id);
<span class="keyword" style="color: rgb(160, 32, 240);">const</span> <span class="type" style="color: rgb(34, 139, 34);">double</span>* <span class="variable-name" style="color: rgb(160, 82, 45);">incumbent_solution</span> = model_->bestSolution();
<span class="keyword" style="color: rgb(160, 32, 240);">auto</span> <span class="type" style="color: rgb(34, 139, 34);">solver</span> = <span class="keyword" style="color: rgb(160, 32, 240);">dynamic_cast</span><OsiClpSolverInterface*> (model_->solver());
<span class="type" style="color: rgb(34, 139, 34);">ClpSimplex</span>* <span class="variable-name" style="color: rgb(160, 82, 45);">current_lp_solver</span> = solver->getModelPtr();
<span class="type" style="color: rgb(34, 139, 34);">ClpSimplex</span> <span class="variable-name" style="color: rgb(160, 82, 45);">lp_solver</span>{*current_lp_solver};
solver->swapModelPtr(&lp_solver);
<span class="type" style="color: rgb(34, 139, 34);">double</span>* <span class="variable-name" style="color: rgb(160, 82, 45);">lp_solver_solution</span> = lp_solver.primalColumnSolution();
<span class="type" style="color: rgb(34, 139, 34);">double</span>* <span class="variable-name" style="color: rgb(160, 82, 45);">lp_solver_lower</span> = lp_solver.columnLower();
<span class="type" style="color: rgb(34, 139, 34);">double</span>* <span class="variable-name" style="color: rgb(160, 82, 45);">lp_solver_upper</span> = lp_solver.columnUpper();
<span class="type" style="color: rgb(34, 139, 34);">int</span> <span class="variable-name" style="color: rgb(160, 82, 45);">lp_solver_number_columns</span> = lp_solver.numberColumns();
memcpy(lp_solver_solution, incumbent_solution,
<span class="type" style="color: rgb(34, 139, 34);">lp_solver_number_columns</span> * <span class="keyword" style="color: rgb(160, 32, 240);">sizeof</span>(<span class="type" style="color: rgb(34, 139, 34);">double</span>));
<span class="keyword" style="color: rgb(160, 32, 240);">for</span> (<span class="type" style="color: rgb(34, 139, 34);">int</span> <span class="variable-name" style="color: rgb(160, 82, 45);">i</span> = 0; i < lp_solver_number_columns; i++) {
<span class="keyword" style="color: rgb(160, 32, 240);">if</span> (solver->isInteger(i)) {
<span class="type" style="color: rgb(34, 139, 34);">double</span> <span class="variable-name" style="color: rgb(160, 82, 45);">x</span> = 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(<span class="constant" style="color: rgb(0, 139, 139);">false</span>);
cbcPreProcessPointer->postProcess(*solver);
<span class="comment-delimiter" style="color: rgb(178, 34, 34);">// </span><span class="comment" style="color: rgb(178, 34, 34);">write solution
</span>
<span class="comment-delimiter" style="color: rgb(178, 34, 34);">// </span><span class="comment" style="color: rgb(178, 34, 34);"><span class="warning" style="color: rgb(255, 0, 0); font-weight: bold;">XXX</span></span><span class="comment" style="color: rgb(178, 34, 34);">: some wishful thinking here: hoping we would see the
</span> <span class="comment-delimiter" style="color: rgb(178, 34, 34);">// </span><span class="comment" style="color: rgb(178, 34, 34);">original number of columns at this point.
</span> lp_solver_number_columns = lp_solver.numberColumns();
<span class="keyword" style="color: rgb(160, 32, 240);">const</span> <span class="type" style="color: rgb(34, 139, 34);">double</span>* <span class="variable-name" style="color: rgb(160, 82, 45);">solution</span> = solver->getColSolution();
<span class="keyword" style="color: rgb(160, 32, 240);">const</span> <span class="type" style="color: rgb(34, 139, 34);">double</span>* <span class="variable-name" style="color: rgb(160, 82, 45);">reduced_costs</span> = solver->getReducedCost();
assert(solution && reduced_costs);
<span class="keyword" style="color: rgb(160, 32, 240);">auto</span> <span class="type" style="color: rgb(34, 139, 34);">column_names</span> = lp_solver.columnNames();
<span class="constant" style="color: rgb(0, 139, 139);">string</span>::<span class="type" style="color: rgb(34, 139, 34);">size_type</span> <span class="variable-name" style="color: rgb(160, 82, 45);">max_name_length</span> = 0;
<span class="keyword" style="color: rgb(160, 32, 240);">for</span> (<span class="keyword" style="color: rgb(160, 32, 240);">auto</span> <span class="keyword" style="color: rgb(160, 32, 240);">const</span>& <span class="variable-name" style="color: rgb(160, 82, 45);">name</span>: *column_names) {
max_name_length = <span class="constant" style="color: rgb(0, 139, 139);">std</span>::max(max_name_length, name.length());
}
<span class="type" style="color: rgb(34, 139, 34);">stringstream</span> <span class="variable-name" style="color: rgb(160, 82, 45);">filename</span>;
filename << solution_directory_
<< solution_prefix_
<< external_solution_id_++
<< <span class="string" style="color: rgb(139, 34, 82);">".txt"</span>;
{
<span class="type" style="color: rgb(34, 139, 34);">ofstream</span> <span class="variable-name" style="color: rgb(160, 82, 45);">out</span>(filename.str());
<span class="keyword" style="color: rgb(160, 32, 240);">if</span> (<span class="negation-char">!</span>out.is_open()) {
<span class="constant" style="color: rgb(0, 139, 139);">std</span>::cout << <span class="string" style="color: rgb(139, 34, 82);">"Couldn't open "</span>
<< filename.str() << <span class="string" style="color: rgb(139, 34, 82);">" for writing "</span> << endl;
abort();
}
<span class="type" style="color: rgb(34, 139, 34);">char</span> <span class="variable-name" style="color: rgb(160, 82, 45);">buf</span>[100];
snprintf(buf, <span class="keyword" style="color: rgb(160, 32, 240);">sizeof</span> buf, <span class="string" style="color: rgb(139, 34, 82);">"Incumbent - objective value %.8f\n"</span>,
lp_solver.getObjValue());
out << buf;
<span class="keyword" style="color: rgb(160, 32, 240);">for</span> (<span class="type" style="color: rgb(34, 139, 34);">int</span> <span class="variable-name" style="color: rgb(160, 82, 45);">i</span> = 0; i < lp_solver_number_columns; i++) {
<span class="keyword" style="color: rgb(160, 32, 240);">if</span> (fabs(solution[i]) > 1.0e-8) {
<span class="keyword" style="color: rgb(160, 32, 240);">auto</span>& <span class="variable-name" style="color: rgb(160, 82, 45);">name</span> = (*column_names)[i];
<span class="type" style="color: rgb(34, 139, 34);">string</span> <span class="variable-name" style="color: rgb(160, 82, 45);">padding</span>(<span class="constant" style="color: rgb(0, 139, 139);">std</span>::max(max_name_length, name.length())
- name.length(), <span class="string" style="color: rgb(139, 34, 82);">' '</span>);
<span class="type" style="color: rgb(34, 139, 34);">char</span> <span class="variable-name" style="color: rgb(160, 82, 45);">buf</span>[100];
snprintf(buf, <span class="keyword" style="color: rgb(160, 32, 240);">sizeof</span> buf,<span class="string" style="color: rgb(139, 34, 82);">"%7d %s%s %15.8g %15.8g\n"</span>,
i,
name.c_str(),
padding.c_str(),
solution[i],
reduced_costs[i]);
out << buf;
}
}
}
<span class="constant" style="color: rgb(0, 139, 139);">std</span>::cout << <span class="string" style="color: rgb(139, 34, 82);">"[SolutionWriter] Solution saved to "</span> << filename.str() << <span class="constant" style="color: rgb(0, 139, 139);">std</span>::endl;
solver->swapModelPtr(current_lp_solver);
}
}
<span class="keyword" style="color: rgb(160, 32, 240);">return</span> noAction; <span class="comment-delimiter" style="color: rgb(178, 34, 34);">// </span><span class="comment" style="color: rgb(178, 34, 34);">carry on
</span> }
<span class="function-name" style="color: rgb(0, 0, 255);">SolutionWriter</span>() = <span class="keyword" style="color: rgb(160, 32, 240);">delete</span>;
<span class="function-name" style="color: rgb(0, 0, 255);">SolutionWriter</span>(<span class="keyword" style="color: rgb(160, 32, 240);">const</span> <span class="type" style="color: rgb(34, 139, 34);">SolutionWriter</span>&) = <span class="keyword" style="color: rgb(160, 32, 240);">default</span>;
<span class="function-name" style="color: rgb(0, 0, 255);">SolutionWriter</span>(<span class="keyword" style="color: rgb(160, 32, 240);">const</span> <span class="type" style="color: rgb(34, 139, 34);">SolutionWriter</span>&&) = <span class="keyword" style="color: rgb(160, 32, 240);">delete</span>;
<span class="function-name" style="color: rgb(0, 0, 255);">SolutionWriter</span>(<span class="type" style="color: rgb(34, 139, 34);">CbcModel</span>* <span class="variable-name" style="color: rgb(160, 82, 45);">model</span>,
<span class="type" style="color: rgb(34, 139, 34);">CbcModel</span>* <span class="variable-name" style="color: rgb(160, 82, 45);">original</span>,
<span class="keyword" style="color: rgb(160, 32, 240);">const</span> <span class="type" style="color: rgb(34, 139, 34);">string</span>& <span class="variable-name" style="color: rgb(160, 82, 45);">solution_prefix</span> = <span class="string" style="color: rgb(139, 34, 82);">"solution"</span>,
<span class="keyword" style="color: rgb(160, 32, 240);">const</span> <span class="type" style="color: rgb(34, 139, 34);">string</span>& <span class="variable-name" style="color: rgb(160, 82, 45);">solution_directory</span> = <span class="string" style="color: rgb(139, 34, 82);">"."</span>)
: CbcEventHandler(model),
original_model_(original),
solution_prefix_(solution_prefix),
solution_directory_(solution_directory) {
<span class="keyword" style="color: rgb(160, 32, 240);">if</span> (solution_directory_.back() != <span class="string" style="color: rgb(139, 34, 82);">'/'</span>) solution_directory_.append(<span class="string" style="color: rgb(139, 34, 82);">"/"</span>);
}
<span class="keyword" style="color: rgb(160, 32, 240);">virtual</span> <span class="type" style="color: rgb(34, 139, 34);">CbcEventHandler</span>* <span class="function-name" style="color: rgb(0, 0, 255);">clone</span>() <span class="keyword" style="color: rgb(160, 32, 240);">const</span> <span class="type" style="color: rgb(34, 139, 34);">override</span> {
<span class="keyword" style="color: rgb(160, 32, 240);">return</span> <span class="keyword" style="color: rgb(160, 32, 240);">new</span> <span class="type" style="color: rgb(34, 139, 34);">SolutionWriter</span>(*<span class="keyword" style="color: rgb(160, 32, 240);">this</span>);
}
};</pre>
<br>
Thanks in advance,<br>
Luís<br>
</body>
</html>