> Languages and APIs > ILOG Concert Technology for C++ Users > Example: Optimizing the Diet Problem in C++ > Complete Program

The complete program, ilodiet.cpp, shown here is also provided online, in the standard distribution.

Note


// -------------------------------------------------------------- -*- C++ -*-
// File: examples/src/ilodiet.cpp
// Version 9.0    
// --------------------------------------------------------------------------
//  Copyright (C) 1999-2003 by ILOG.
//  All Rights Reserved.
//  Permission is expressly granted to use this example in the
//  course of developing applications that use ILOG products.
// --------------------------------------------------------------------------
//
// A dietary model.
//
// Input data:
// foodMin[j]      minimum amount of food j to use
// foodMax[j]      maximum amount of food j to use 
// foodCost[j]     cost for one unit of food j
// nutrMin[i]      minimum amount of nutrient i
// nutrMax[i]      maximum amount of nutrient i
// nutrPer[i][j]   nutrition amount of nutrient i in food j
//
// Modeling variables:
// Buy[j]          amount of food j to purchase
//
// Objective:
// minimize sum(j) Buy[j] * foodCost[j]
//
// Constraints:
// forall foods i: nutrMin[i] <= sum(j) Buy[j] * nutrPer[i][j] <= nutrMax[j]
//

#include <ilcplex/ilocplex.h>
ILOSTLBEGIN



void usage(const char* name) {
   cerr << endl;
   cerr << "usage:   " << name << " [options] <file>" << endl;
   cerr << "options: -c  build model by column" << endl;
   cerr << "         -i  use integer variables" << endl;
   cerr << endl;
}


typedef IloArray<IloNumArray> IloNumArray2;


void
buildModelByRow(IloModel           mod,
                IloNumVarArray     Buy,
                const IloNumArray  foodMin,
                const IloNumArray  foodMax,
                const IloNumArray  foodCost, 
                const IloNumArray  nutrMin,
                const IloNumArray  nutrMax,
                const IloNumArray2 nutrPer,
                IloNumVar::Type type) {
   IloEnv env = mod.getEnv();

   Buy.clear();
   IloNumVarArray tmp(env, foodMin, foodMax, type);
   Buy.add(tmp);
   tmp.end();

   IloInt i, j;
   IloInt n = foodCost.getSize();
   IloInt m = nutrMin.getSize();

   mod.add(IloMinimize(env, IloScalProd(Buy,foodCost)));
   for (i = 0; i < m; i++) {
      IloExpr expr(env);
      for (j = 0; j < n; j++) {
         expr += Buy[j] * nutrPer[i][j];
      }
      mod.add(nutrMin[i] <= expr <= nutrMax[i]);
      expr.end();
   }
}


void
buildModelByColumn(IloModel           mod,
                   IloNumVarArray     Buy,
                   const IloNumArray  foodMin,
                   const IloNumArray  foodMax,
                   const IloNumArray  foodCost, 
                   const IloNumArray  nutrMin,
                   const IloNumArray  nutrMax,
                   const IloNumArray2 nutrPer,
                   IloNumVar::Type    type) {
   IloEnv env = mod.getEnv();

   IloInt i, j;
   IloInt n = foodCost.getSize();
   IloInt m = nutrMin.getSize();

   IloRangeArray range (env, nutrMin, nutrMax);
   mod.add(range);
   IloObjective cost = IloAdd(mod, IloMinimize(env));

   for (j = 0; j < n; j++) {
      IloNumColumn col = cost(foodCost[j]);
      for (i = 0; i < m; i++) {
         col += range[i](nutrPer[i][j]);
      }
      Buy.add(IloNumVar(col, foodMin[j], foodMax[j], type));
      col.end();
   }
   range.end();
}


int
main(int argc, char **argv)
{
   IloEnv env;

   try {
      const char*     filename  = "../../../examples/data/diet.dat";
      IloBool         byColumn  = IloFalse;
      IloNumVar::Type varType   = ILOFLOAT;

      IloInt i;

      for (i = 1; i < argc; ++i) {
         if (argv[i][0] == '-') {
            switch (argv[i][1]) {
            case 'c':
               byColumn = IloTrue;
               break;
            case 'i':
               varType = ILOINT;
               break;
            default:
               usage(argv[0]);
               throw (-1);
            }
         }
         else {
            filename = argv[i];
            break;
         }
      }

      ifstream file(filename);
      if ( !file ) {
         cerr << "ERROR: could not open file '" << filename
              << "' for reading" << endl;
         usage(argv[0]);
         throw (-1);
      }

      // model data

      IloNumArray  foodCost(env), foodMin(env), foodMax(env);
      IloNumArray  nutrMin(env), nutrMax(env);
      IloNumArray2 nutrPer(env);

      file >> foodCost >> foodMin >> foodMax;
      file >> nutrMin >> nutrMax;
      file >> nutrPer;

      IloInt nFoods = foodCost.getSize();
      IloInt nNutr  = nutrMin.getSize();

      if ( foodMin.getSize() != nFoods ||
           foodMax.getSize() != nFoods ||
           nutrPer.getSize() != nNutr  ||
           nutrMax.getSize() != nNutr    ) {
         cerr << "ERROR: Data file '" << filename
              << "' contains inconsistent data" << endl;
         throw (-1);
      }

      for (i = 0; i < nNutr; ++i) {
         if (nutrPer[i].getSize() != nFoods) {
            cerr << "ERROR: Data file '" << argv[0]
                 << "' contains inconsistent data" << endl;
            throw (-1);
         }
      }

      // Build model

      IloModel       mod(env);
      IloNumVarArray Buy(env);
      if ( byColumn ) {
         buildModelByColumn(mod, Buy, foodMin, foodMax, foodCost,
                            nutrMin, nutrMax, nutrPer, varType);
      }
      else {
         buildModelByRow(mod, Buy, foodMin, foodMax, foodCost,
                         nutrMin, nutrMax, nutrPer, varType);
      }

      // Solve model

      IloCplex cplex(mod);
      cplex.exportModel("diet.lp");

      cplex.solve();
      cplex.out() << "solution status = " << cplex.getStatus() << endl;

      cplex.out() << endl;
      cplex.out() << "cost   = " << cplex.getObjValue() << endl;
      for (i = 0; i < foodCost.getSize(); i++) {
         cplex.out() << "  Buy" << i << " = " << cplex.getValue(Buy[i]) << 
endl;
      }
   }
   catch (IloException& ex) {
      cerr << "Error: " << ex << endl;
   }
   catch (...) {
      cerr << "Error" << endl;
   }

   env.end();

   return 0;
}