7.11 Parallel optimization

In this section we demonstrate the method Model.solveBatch which is a parallel optimization mechanism built-in in MOSEK. It has the following features:

  • It allows to fine-tune the balance between the total number of threads in use by the parallel solver and the number of threads used for each individual model.

  • It is very efficient for optimizing a large number of models of similar size, for example models obtained by cloning an initial model and changing some coefficients.

In the example below we demonstrate a very standard application of Model.solveBatch. We create an initial model, clone it a few times, set different parameter values in each clone and then optimize all the cloned models in parallel. When all models complete we access the status for each of them and, if successfully solved, we gather solutions and other information in the standard way, as if each model was optimized separately.

Listing 7.26 Calling the parallel optimizer. Click here to download.
/** Example of how to use Model.solveBatch()
*/
int main(int argc, char ** argv)
{
  // Choose some sample parameters
  int n = 10;                 // Number of models to optimize
  int threadpoolsize = 4;     // Total number of threads available
  int threadspermodel = 1;    // Number of threads per each model

  // Create a toy model for this example
  auto M = makeToyParameterizedModel();

  // Set up n copies of the model with different data
  auto models = std::make_shared<ndarray<Model::t,1>>(shape(n));

  for(int i = 0; i < n ; i++)
  {
    (*models)[i] = M->clone();
    (*models)[i]->getParameter("p")->setValue(i+1);
    // We can set the number of threads individually per model
    (*models)[i]->setSolverParam("numThreads", threadspermodel);
  }

  // Solve all models in parallel
  auto status = Model::solveBatch(false,         // No race
                                  -1.0,          // No time limit
                                  threadpoolsize,
                                  models);       // Array of Models to solve

  // Access the solutions
  for(int i = 0; i < n; i++) 
    if ((*status)[i] == SolverStatus::OK)
      std::cout << "Model "            <<  i << ":  "
                << "  Status "          <<  (*status)[i]
                << "  Solution Status " <<  (*models)[i]->getPrimalSolutionStatus()
                << "  Objective "       <<  (*models)[i]->primalObjValue()
                << "  Time "            <<  (*models)[i]->getSolverDoubleInfo("optimizerTime") << std::endl;
    else
      std::cout << "Model "           <<  i << ": not solved" << std::endl;
}