<html>
<head>
<meta content="text/html; charset=windows-1252"
http-equiv="Content-Type">
</head>
<body bgcolor="#FFFFFF" text="#000000">
<div class="moz-cite-prefix">Luis,<br>
<br>
I may put up an example as to how to do this, but I took your code
and fixed it up so that it works on an example - not necessarily
in the most elegant way. In some cases, CbcMain1 does a bit more
work - but I hope the attached works for you.<br>
<br>
John Forrest<br>
On 19/08/16 18:48, Luís Borges de Oliveira wrote:<br>
</div>
<blockquote cite="mid:57B74651.5010707@siscog.pt" type="cite">
<meta http-equiv="Context-Type" content="text/html; charset=utf-8">
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><span class="preprocessor">#include</span> <span class="string"><algorithm></span>
<span class="preprocessor">#include</span> <span class="string"><fstream></span>
<span class="preprocessor">#include</span> <span class="string"><sstream></span>
<span class="preprocessor">#include</span> <span class="string">"CbcModel.hpp"</span>
<span class="preprocessor">#include</span> <span class="string">"OsiClpSolverInterface.hpp"</span>
<span class="preprocessor">#include</span> <span class="string">"CbcSolver.hpp"</span>
<span class="preprocessor">#include</span> <span class="string">"CbcEventHandler.hpp"</span>
<span class="preprocessor">#include</span> <span class="string">"CglPreProcess.hpp"</span>
<span class="keyword">extern</span> <span class="type">CglPreProcess</span>* <span class="variable-name">cbcPreProcessPointer</span>;
<span class="keyword">class</span> <span class="type">SolutionWriter</span> : <span class="keyword">public</span> <span class="type">CbcEventHandler</span> {
<span class="type">CbcModel</span>* <span class="variable-name">original_model_</span>;
<span class="type">string</span> <span class="variable-name">solution_prefix_</span>;
<span class="type">string</span> <span class="variable-name">solution_directory_</span>;
<span class="constant">std</span>::<span class="type">set</span><<span class="type">int</span>> <span class="variable-name">seen_solutions_</span>;<span class="comment">
</span> <span class="type">int</span> <span class="variable-name">external_solution_id_</span> = 1;
<span class="keyword">public</span>:
<span class="keyword">virtual</span> <span class="constant">CbcEventHandler</span>::<span class="type">CbcAction</span> <span class="function-name">event</span>(<span class="type">CbcEvent</span> <span class="variable-name">whichEvent</span>) {
<span class="comment-delimiter">// </span><span class="comment">If in sub tree carry on
</span> <span class="keyword">if</span> (<span class="negation-char">!</span>model_->parentModel()) {
<span class="type">int</span> <span class="variable-name">solution_id</span> = model_->getSolutionCount();
<span class="keyword">if</span> ((whichEvent == solution || whichEvent == heuristicSolution)
&& seen_solutions_.find(solution_id) == seen_solutions_.end()) {
seen_solutions_.insert(solution_id);
<span class="keyword">const</span> <span class="type">double</span>* <span class="variable-name">incumbent_solution</span> = model_->bestSolution();
<span class="keyword">auto</span> <span class="type">solver</span> = <span class="keyword">dynamic_cast</span><OsiClpSolverInterface*> (model_->solver());
<span class="type">ClpSimplex</span>* <span class="variable-name">current_lp_solver</span> = solver->getModelPtr();
<span class="type">ClpSimplex</span> <span class="variable-name">lp_solver</span>{*current_lp_solver};
solver->swapModelPtr(&lp_solver);
<span class="type">double</span>* <span class="variable-name">lp_solver_solution</span> = lp_solver.primalColumnSolution();
<span class="type">double</span>* <span class="variable-name">lp_solver_lower</span> = lp_solver.columnLower();
<span class="type">double</span>* <span class="variable-name">lp_solver_upper</span> = lp_solver.columnUpper();
<span class="type">int</span> <span class="variable-name">lp_solver_number_columns</span> = lp_solver.numberColumns();
memcpy(lp_solver_solution, incumbent_solution,
<span class="type">lp_solver_number_columns</span> * <span class="keyword">sizeof</span>(<span class="type">double</span>));
<span class="keyword">for</span> (<span class="type">int</span> <span class="variable-name">i</span> = 0; i < lp_solver_number_columns; i++) {
<span class="keyword">if</span> (solver->isInteger(i)) {
<span class="type">double</span> <span class="variable-name">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">false</span>);
cbcPreProcessPointer->postProcess(*solver);
<span class="comment-delimiter">// </span><span class="comment">write solution
</span>
<span class="comment-delimiter">// </span><span class="comment"><span class="warning">XXX</span></span><span class="comment">: some wishful thinking here: hoping we would see the
</span> <span class="comment-delimiter">// </span><span class="comment">original number of columns at this point.
</span> lp_solver_number_columns = lp_solver.numberColumns();
<span class="keyword">const</span> <span class="type">double</span>* <span class="variable-name">solution</span> = solver->getColSolution();
<span class="keyword">const</span> <span class="type">double</span>* <span class="variable-name">reduced_costs</span> = solver->getReducedCost();
assert(solution && reduced_costs);
<span class="keyword">auto</span> <span class="type">column_names</span> = lp_solver.columnNames();
<span class="constant">string</span>::<span class="type">size_type</span> <span class="variable-name">max_name_length</span> = 0;
<span class="keyword">for</span> (<span class="keyword">auto</span> <span class="keyword">const</span>& <span class="variable-name">name</span>: *column_names) {
max_name_length = <span class="constant">std</span>::max(max_name_length, name.length());
}
<span class="type">stringstream</span> <span class="variable-name">filename</span>;
filename << solution_directory_
<< solution_prefix_
<< external_solution_id_++
<< <span class="string">".txt"</span>;
{
<span class="type">ofstream</span> <span class="variable-name">out</span>(filename.str());
<span class="keyword">if</span> (<span class="negation-char">!</span>out.is_open()) {
<span class="constant">std</span>::cout << <span class="string">"Couldn't open "</span>
<< filename.str() << <span class="string">" for writing "</span> << endl;
abort();
}
<span class="type">char</span> <span class="variable-name">buf</span>[100];
snprintf(buf, <span class="keyword">sizeof</span> buf, <span class="string">"Incumbent - objective value %.8f\n"</span>,
lp_solver.getObjValue());
out << buf;
<span class="keyword">for</span> (<span class="type">int</span> <span class="variable-name">i</span> = 0; i < lp_solver_number_columns; i++) {
<span class="keyword">if</span> (fabs(solution[i]) > 1.0e-8) {
<span class="keyword">auto</span>& <span class="variable-name">name</span> = (*column_names)[i];
<span class="type">string</span> <span class="variable-name">padding</span>(<span class="constant">std</span>::max(max_name_length, name.length())
- name.length(), <span class="string">' '</span>);
<span class="type">char</span> <span class="variable-name">buf</span>[100];
snprintf(buf, <span class="keyword">sizeof</span> buf,<span class="string">"%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">std</span>::cout << <span class="string">"[SolutionWriter] Solution saved to "</span> << filename.str() << <span class="constant">std</span>::endl;
solver->swapModelPtr(current_lp_solver);
}
}
<span class="keyword">return</span> noAction; <span class="comment-delimiter">// </span><span class="comment">carry on
</span> }
<span class="function-name">SolutionWriter</span>() = <span class="keyword">delete</span>;
<span class="function-name">SolutionWriter</span>(<span class="keyword">const</span> <span class="type">SolutionWriter</span>&) = <span class="keyword">default</span>;
<span class="function-name">SolutionWriter</span>(<span class="keyword">const</span> <span class="type">SolutionWriter</span>&&) = <span class="keyword">delete</span>;
<span class="function-name">SolutionWriter</span>(<span class="type">CbcModel</span>* <span class="variable-name">model</span>,
<span class="type">CbcModel</span>* <span class="variable-name">original</span>,
<span class="keyword">const</span> <span class="type">string</span>& <span class="variable-name">solution_prefix</span> = <span class="string">"solution"</span>,
<span class="keyword">const</span> <span class="type">string</span>& <span class="variable-name">solution_directory</span> = <span class="string">"."</span>)
: CbcEventHandler(model),
original_model_(original),
solution_prefix_(solution_prefix),
solution_directory_(solution_directory) {
<span class="keyword">if</span> (solution_directory_.back() != <span class="string">'/'</span>) solution_directory_.append(<span class="string">"/"</span>);
}
<span class="keyword">virtual</span> <span class="type">CbcEventHandler</span>* <span class="function-name">clone</span>() <span class="keyword">const</span> <span class="type">override</span> {
<span class="keyword">return</span> <span class="keyword">new</span> <span class="type">SolutionWriter</span>(*<span class="keyword">this</span>);
}
};</pre>
<br>
Thanks in advance,<br>
Luís<br>
<br>
<fieldset class="mimeAttachmentHeader"></fieldset>
<br>
<pre wrap="">_______________________________________________
Cbc mailing list
<a class="moz-txt-link-abbreviated" href="mailto:Cbc@list.coin-or.org">Cbc@list.coin-or.org</a>
<a class="moz-txt-link-freetext" href="http://list.coin-or.org/mailman/listinfo/cbc">http://list.coin-or.org/mailman/listinfo/cbc</a>
</pre>
</blockquote>
<p><br>
</p>
</body>
</html>