batchmode_c++.cpp#

/* Copyright 2024, Gurobi Optimization, LLC */

// This example reads a MIP model from a file, solves it in batch mode,
// and prints the JSON solution string.
//
// You will need a Compute Server license for this example to work.

#include <ctime>
#if defined (WIN32) || defined (WIN64) || defined(_WIN32) || defined (_WIN64)
#include <Windows.h>
#define sleep(n) Sleep(1000*n)
#else
#include <unistd.h>
#endif
#include "gurobi_c++.h"
using namespace std;

// Set-up the environment for batch mode optimization.
//
// The function configures and start an environment to be used for batch
// optimization.
void
setupbatchenv(GRBEnv* env)
{
  env->set(GRB_StringParam_LogFile,        "batchmode.log");
  env->set(GRB_StringParam_CSManager,      "http://localhost:61080");
  env->set(GRB_StringParam_UserName,       "gurobi");
  env->set(GRB_StringParam_ServerPassword, "pass");
  env->set(GRB_IntParam_CSBatchMode, 1);

  // No network communication happened up to this point. This will happen
  // now that we call the start() method.
  env->start();
}

// Print batch job error information, if any
void
printbatcherrorinfo(GRBBatch &batch)
{
  if (batch.get(GRB_IntAttr_BatchErrorCode) == 0)
    return;

  cerr << "Batch ID " << batch.get(GRB_StringAttr_BatchID)
       << ": Error code " << batch.get(GRB_IntAttr_BatchErrorCode)
       << " (" << batch.get(GRB_StringAttr_BatchErrorMessage)
       << ")" << endl;
}

// Create a batch request for given problem file
string
newbatchrequest(char* filename)
{
  GRBEnv*   env   = NULL;
  GRBModel* model = NULL;
  GRBVar*   v     = NULL;
  string batchID;

  try {
    // Start environment, create Model object from file
    env = new GRBEnv(true);
    setupbatchenv(env);
    model = new GRBModel(*env, filename);

    // Set some parameters; switch on detailed JSON information
    model->set(GRB_DoubleParam_MIPGap, 0.01);
    model->set(GRB_IntParam_JSONSolDetail, 1);

    // Define tags for some variables in order to access their values later
    int numvars = model->get(GRB_IntAttr_NumVars);
    v = model->getVars();
    if (numvars > 10) numvars = 10;
    for (int j = 0; j < numvars; j++) {
      char vtag[64];
      sprintf(vtag, "Variable %d", j);
      v[j].set(GRB_StringAttr_VTag, string(vtag));
    }

    // submit batch request
    batchID = model->optimizeBatch();

  } catch (...) {
    // Free local resources
    delete[] v;
    delete model;
    delete env;
    // Let the exception propagate
    throw;
  }

  // Free local resources
  delete[] v;
  delete model;
  delete env;

  return batchID;
}

// Wait for the final status of the batch.
// Initially the status of a batch is "submitted"; the status will change
// once the batch has been processed (by a compute server).
void
waitforfinalstatus(string batchID)
{
  // Wait no longer than one hour
  time_t maxwaittime = 3600;
  GRBEnv*   env   = NULL;
  GRBBatch* batch = NULL;


  try {
    // Setup and start environment, create local Batch handle object
    env = new GRBEnv(true);
    setupbatchenv(env);
    batch = new GRBBatch(*env, batchID);
    time_t starttime = time(NULL);
    int BatchStatus = batch->get(GRB_IntAttr_BatchStatus);

    while (BatchStatus == GRB_BATCH_SUBMITTED) {

      // Abort this batch if it is taking too long
      time_t curtime = time(NULL);
      if (curtime - starttime > maxwaittime) {
        batch->abort();
        break;
      }

      // Wait for two seconds
      sleep(2);

      // Update the resident attribute cache of the Batch object with the
      // latest values from the cluster manager.
      batch->update();
      BatchStatus = batch->get(GRB_IntAttr_BatchStatus);

      // If the batch failed, we try again
      if (BatchStatus == GRB_BATCH_FAILED)
        batch->retry();
    }
  } catch (...) {
    // Print information about error status of the job that
    // processed the batch
    printbatcherrorinfo(*batch);
    // Free local resources
    delete batch;
    delete env;
    // let the exception propagate
    throw;
  }

  // Free local resources
  delete batch;
  delete env;
}

void
printfinalreport(string batchID)
{
  GRBEnv*   env   = NULL;
  GRBBatch* batch = NULL;

  try {
    // Setup and starts environment, create local Batch handle object
    env = new GRBEnv(true);
    setupbatchenv(env);
    batch = new GRBBatch(*env, batchID);

    int BatchStatus = batch->get(GRB_IntAttr_BatchStatus);
    if (BatchStatus == GRB_BATCH_CREATED)
      cout << "Batch status is 'CREATED'" << endl;
    else if (BatchStatus == GRB_BATCH_SUBMITTED)
      cout << "Batch is 'SUBMITTED" << endl;
    else if (BatchStatus == GRB_BATCH_ABORTED)
      cout << "Batch is 'ABORTED'" << endl;
    else if (BatchStatus == GRB_BATCH_FAILED)
      cout << "Batch is 'FAILED'" << endl;
    else if (BatchStatus == GRB_BATCH_COMPLETED) {
      cout << "Batch is 'COMPLETED'" << endl;
      // Pretty printing the general solution information
      cout << "JSON solution:" << batch->getJSONSolution() << endl;

      // Write the full JSON solution string to a file
      batch->writeJSONSolution("batch-sol.json.gz");
    } else {
      // Should not happen
      cout << "Batch has unknown BatchStatus" << endl;
    }
  } catch (...) {
    // Free local resources
    delete batch;
    delete env;
    // let the exception propagate
    throw;
  }

  // Free local resources
  delete batch;
  delete env;
}

// Instruct cluster manager to remove all data relating to this BatchID
void
batchdiscard(string batchID)
{
  GRBEnv*   env   = NULL;
  GRBBatch* batch = NULL;

  try {
    // Setup and start environment, create local Batch handle object
    env = new GRBEnv(true);
    setupbatchenv(env);
    batch = new GRBBatch(*env, batchID);

    // Remove batch request from manager
    batch->discard();
  } catch (...) {
    // Free local resources even
    delete batch;
    delete env;
    // let the exception propagate
    throw;
  }

  // Free local resources
  delete batch;
  delete env;
}

// Solve a given model using batch optimization
int
main(int   argc,
    char** argv)
{
  // Ensure we have an input file
  if (argc != 2) {
    cout << "Usage: " << argv[0] << " filename" << endl;
    return 0;
  }

  try {
    // Submit new batch request
    string batchID = newbatchrequest(argv[1]);

    // Wait for final status
    waitforfinalstatus(batchID);

    // Report final status info
    printfinalreport(batchID);

    // Remove batch request from manager
    batchdiscard(batchID);

    cout << "Batch optimization OK" << endl;
  } catch (GRBException e) {
    cout << "Error code = " << e.getErrorCode() << endl;
    cout << e.getMessage() << endl;
  } catch (...) {
    cout << "Exception during optimization" << endl;
  }
  return 0;
}