<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>