Jakhon
Jakhon

Reputation: 61

writing C++ programs using CPLEX with Concert Technology

This is my first question in stack overflow website. I was learning concert technology in C++. After I gained some understanding, I have tried to solve the following problem. I have coded the problem but I am getting infeasible solution. Can someone look at it and try to find where I am making mistake? Thank you so much!

Here is the problem:
A pet food company produces feed for dogs, cats, and rabbits. To do this, they mix corn, lime-stone, soybeans, and fish meal. These ingredients contain the following nutrients: vitamins, protein,calcium, and crude fat. The contents of the nutrients in standard units for each kilogram of the ingredients are summarized in the following table.

Ingredient Vitamins Protein Calcium  Crude Fat   Amount Available    Price per kg
Corn         8       10      6         8           9  tons            $0.20
Limestone    6       5       10        6           12 tons            $0.12
Soybeans     10      12      6         6           5  tons            $0.24
Fish meal     4      8       6         9           6  tons            $0.1

The company in contracted to produce 12, 8, and 9 (metric) tons of dog, cat, and rabbit food. However, the company is only able to procure the amount available listed in the above table for each ingredient and the listed price per kilogram. To ensure the integrity of their product, they must adhere to the minimal and maximal units of the various nutrients for a kilogram of the dog, cat, and rabbit food.

Vitamins        Protein     Calcium      Crude      Fat
Product        Min  Max     Min Max     Min Max    Min Max
Dog Food       6    ∞       6   ∞       7    ∞      4  8
Cat Food       6    ∞       6   ∞       6    ∞      4  6
Rabbit Food    4    6       6   ∞       6    ∞      4  5

Formulate this problem as a linear program such that the company minimizes costs.

As you can see I did cout after each block of code to check the content of the arrays. The contents seemed to be fine. And reason why I used 50000 inIloIntVarArray(env, nbIngr, 0, 50000) is that It just a really big upper limit for my decision variable. It could be infinity.

Here is the code:

using namespace std;
#include <ilcplex/ilocplex.h>
#include <iostream>;


typedef IloArray<IloIntVarArray> IloIntVarArray2; // creating two-dimentional array


int main() {
    IloEnv env;
    try {
        IloInt i,j,k;
        IloInt nbFood = 3; // Number of food type (Dog food, Cat food, Rabbit food)
        IloInt nbIngr = 4; // Number of ingredient type (Corn, Limestone, Soybeans, Fish meal)
        IloInt nbNut = 4; // Number of nutrient type (Vitamins, Protein, Calcium, Crude fat)

        // Decision variable
        // kgs of ingredient j in food i
        IloIntVarArray2 ingredientInFoodX(env, nbFood);
        for (i = 0; i < nbFood; i++) {
            ingredientInFoodX[i] = IloIntVarArray(env, nbIngr, 0, 50000);          
        }
        for (i = 0; i < nbFood; i++) {
            for (j = 0; j < nbIngr; j++) {
                cout << "content is: " << ingredientInFoodX[i][j] << endl;
            }                 

        }
        cout << typeid(ingredientInFoodX).name() << endl;
        cout << endl;

        // Parametrs
        IloNumArray costIngr(env, nbIngr, 0.2, 0.12, 0.24, 0.12); // cost per kg of ingredient
        for (j = 0; j < nbIngr; j++) {
            cout << "content is: " << costIngr[j] << endl;
        }
        cout << endl;

        IloArray<IloNumArray> nutrientPerIngr(env, nbIngr); // amount of nutrient k for each kg of ingredient j
        nutrientPerIngr[0] = IloNumArray(env, nbNut, 8, 10, 6, 8);
        nutrientPerIngr[1] = IloNumArray(env, nbNut, 6, 5, 10, 6);
        nutrientPerIngr[2] = IloNumArray(env, nbNut, 10, 12, 6, 6);
        nutrientPerIngr[3] = IloNumArray(env, nbNut, 4, 8, 6, 9);
        for (j = 0; j < nbIngr; j++) {
            for (k = 0; k < nbNut; k++) {
                cout << "content is: " << nutrientPerIngr[j][k] << endl;
            }
        }
        cout << endl;
        IloNumArray availableIngr(env, nbIngr, 9000, 12000, 5000, 6000);  // amount available (kg) of ingredient j
        for (j = 0; j < nbIngr; j++) {
            cout << "content is: " << availableIngr[j] << endl;
        }
        cout << endl;
        IloNumArray foodDemand(env, nbFood, 12000, 8000, 9000); // demand for food i
        for (i = 0; i < nbFood; i++) {
            cout << "content is: " << foodDemand[i] << endl;
        }
        cout << endl;

        IloNumArray2 foodMinNutrient(env, nbFood); // minimum nutrient k requirement in food i
        foodMinNutrient[0] = IloNumArray(env, nbNut, 6, 6, 7, 4);
        foodMinNutrient[1] = IloNumArray(env, nbNut, 6, 6, 6, 4);
        foodMinNutrient[2] = IloNumArray(env, nbNut, 4, 6, 6, 4);
        for (i = 0; i < nbFood; i++) {
            for (k = 0; k < nbNut; k++) {
                cout << "content is: " << foodMinNutrient[i][k] << endl;
            }
        }
        cout << endl;
        IloNumArray2 foodMaxNutrient(env, nbFood); // maximum nutrient k requirement in food i
        foodMaxNutrient[0] = IloNumArray(env, nbNut, 10000, 10000, 10000, 8);
        foodMaxNutrient[1] = IloNumArray(env, nbNut, 10000, 10000, 10000, 6);
        foodMaxNutrient[2] = IloNumArray(env, nbNut, 6, 10000, 10000, 5);
        for (i = 0; i < nbFood; i++) {
            for (k = 0; k < nbNut; k++) {
                cout << "content is: " << foodMaxNutrient[i][k] << endl;
            }
        }
        cout << endl;

        IloModel model(env);

        // Objective function (minimize production cost)
        IloExpr objective_func(env);
        for (i = 0; i < nbFood; i++) {
            for (j = 0; j < nbIngr; j++)
                objective_func += costIngr[j] * ingredientInFoodX[i][j];
        }
        model.add(IloMinimize(env, objective_func));
        objective_func.end();

        // Constraints

        //limit amount of available ingredient k
        for (j = 0; j < nbIngr; j++) {
            IloExpr expr(env);
            for (i = 0; i < nbFood; i++) {
                expr += ingredientInFoodX[i][j];
            }
            model.add(expr <= availableIngr[j]);
            expr.end();
        }

        // Ensure demand for food i is satisfied
        for (i = 0; i < nbFood; i++) {
            IloExpr expr(env);
            for (j = 0; j < nbIngr; j++) {
                expr += ingredientInFoodX[i][j];
            }
            model.add(expr >= foodDemand[i]);
            expr.end();
        }

        // Min and Max nutrient requirement in food i
        for (i = 0; i < nbFood; i++) {
            for (k = 0; k < nbNut; k++) {
                IloExpr expr(env);                
                for (j = 0; j < nbIngr; j++) {
                    expr += nutrientPerIngr[j][k] * ingredientInFoodX[i][j];                    
                }
                model.add(foodMinNutrient[i][k] * foodDemand[i] <= expr <= foodMaxNutrient[i][k] * foodDemand[i]);
                expr.end();               
            }
        }
        cout << model << endl;
        IloCplex cplex(model);          
        cplex.solve();
        cplex.setOut(env.getNullStream()); // removes unnecessary information from the output window
        cout << "Solution status is: " << cplex.getStatus() << endl;
        cout << "Objective function value is: " << cplex.getObjValue() << endl;
        cout << ingredientInFoodX[i][j] << endl; 

    }
    catch (IloException & ex) {
        cerr << "Error: " << ex << endl;
    }
    catch (...) {
        cerr << "Error" << endl;
    }
    env.end();   
}

Here is the output:

content is: IloIntVar(0)[0..50000]
content is: IloIntVar(1)[0..50000]
content is: IloIntVar(2)[0..50000]
content is: IloIntVar(3)[0..50000]
content is: IloIntVar(4)[0..50000]
content is: IloIntVar(5)[0..50000]
content is: IloIntVar(6)[0..50000]
content is: IloIntVar(7)[0..50000]
content is: IloIntVar(8)[0..50000]
content is: IloIntVar(9)[0..50000]
content is: IloIntVar(10)[0..50000]
content is: IloIntVar(11)[0..50000]
class IloArray<class IloIntVarArray>

content is: 0.2
content is: 0.12
content is: 0.24
content is: 0.12

content is: 8
content is: 10
content is: 6
content is: 8
content is: 6
content is: 5
content is: 10
content is: 6
content is: 10
content is: 12
content is: 6
content is: 6
content is: 4
content is: 8
content is: 6
content is: 9

content is: 9000
content is: 12000
content is: 5000
content is: 6000

content is: 12000
content is: 8000
content is: 9000

content is: 6
content is: 6
content is: 7
content is: 4
content is: 6
content is: 6
content is: 6
content is: 4
content is: 4
content is: 6
content is: 6
content is: 4

content is: 10000
content is: 10000
content is: 10000
content is: 8
content is: 10000
content is: 10000
content is: 10000
content is: 6
content is: 6
content is: 10000
content is: 10000
content is: 5

IloModel model12 = {
obj14 = (0.2 * IloIntVar(0)[0..50000]  + 0.12 * IloIntVar(1)[0..50000]  + 0.24 * IloIntVar(2)[0..50000]  + 0.12 * IloIntVar(3)[0..50000]  + 0.2 * IloIntVar(4)[0..50000]  + 0.12 * IloIntVar(5)[0..50000]  + 0.24 * IloIntVar(6)[0..50000]  + 0.12 * IloIntVar(7)[0..50000]  + 0.2 * IloIntVar(8)[0..50000]  + 0.12 * IloIntVar(9)[0..50000]  + 0.24 * IloIntVar(10)[0..50000]  + 0.12 * IloIntVar(11)[0..50000] , IloObjective, Minimize);

IloIntVar(0)[0..50000]  + IloIntVar(4)[0..50000]  + IloIntVar(8)[0..50000]  <= 9000
IloIntVar(1)[0..50000]  + IloIntVar(5)[0..50000]  + IloIntVar(9)[0..50000]  <= 12000
IloIntVar(2)[0..50000]  + IloIntVar(6)[0..50000]  + IloIntVar(10)[0..50000]  <= 5000
IloIntVar(3)[0..50000]  + IloIntVar(7)[0..50000]  + IloIntVar(11)[0..50000]  <= 6000
12000 <= IloIntVar(0)[0..50000]  + IloIntVar(1)[0..50000]  + IloIntVar(2)[0..50000]  + IloIntVar(3)[0..50000]
8000 <= IloIntVar(4)[0..50000]  + IloIntVar(5)[0..50000]  + IloIntVar(6)[0..50000]  + IloIntVar(7)[0..50000]
9000 <= IloIntVar(8)[0..50000]  + IloIntVar(9)[0..50000]  + IloIntVar(10)[0..50000]  + IloIntVar(11)[0..50000]
72000 <= 8 * IloIntVar(0)[0..50000]  + 6 * IloIntVar(1)[0..50000]  + 10 * IloIntVar(2)[0..50000]  + 4 * IloIntVar(3)[0..50000]  <= 1.2e+08
72000 <= 10 * IloIntVar(0)[0..50000]  + 5 * IloIntVar(1)[0..50000]  + 12 * IloIntVar(2)[0..50000]  + 8 * IloIntVar(3)[0..50000]  <= 1.2e+08
84000 <= 6 * IloIntVar(0)[0..50000]  + 10 * IloIntVar(1)[0..50000]  + 6 * IloIntVar(2)[0..50000]  + 6 * IloIntVar(3)[0..50000]  <= 1.2e+08
48000 <= 8 * IloIntVar(0)[0..50000]  + 6 * IloIntVar(1)[0..50000]  + 6 * IloIntVar(2)[0..50000]  + 9 * IloIntVar(3)[0..50000]  <= 96000
48000 <= 8 * IloIntVar(4)[0..50000]  + 6 * IloIntVar(5)[0..50000]  + 10 * IloIntVar(6)[0..50000]  + 4 * IloIntVar(7)[0..50000]  <= 8e+07
48000 <= 10 * IloIntVar(4)[0..50000]  + 5 * IloIntVar(5)[0..50000]  + 12 * IloIntVar(6)[0..50000]  + 8 * IloIntVar(7)[0..50000]  <= 8e+07
48000 <= 6 * IloIntVar(4)[0..50000]  + 10 * IloIntVar(5)[0..50000]  + 6 * IloIntVar(6)[0..50000]  + 6 * IloIntVar(7)[0..50000]  <= 8e+07
32000 <= 8 * IloIntVar(4)[0..50000]  + 6 * IloIntVar(5)[0..50000]  + 6 * IloIntVar(6)[0..50000]  + 9 * IloIntVar(7)[0..50000]  <= 48000
36000 <= 8 * IloIntVar(8)[0..50000]  + 6 * IloIntVar(9)[0..50000]  + 10 * IloIntVar(10)[0..50000]  + 4 * IloIntVar(11)[0..50000]  <= 54000
54000 <= 10 * IloIntVar(8)[0..50000]  + 5 * IloIntVar(9)[0..50000]  + 12 * IloIntVar(10)[0..50000]  + 8 * IloIntVar(11)[0..50000]  <= 9e+07
54000 <= 6 * IloIntVar(8)[0..50000]  + 10 * IloIntVar(9)[0..50000]  + 6 * IloIntVar(10)[0..50000]  + 6 * IloIntVar(11)[0..50000]  <= 9e+07
36000 <= 8 * IloIntVar(8)[0..50000]  + 6 * IloIntVar(9)[0..50000]  + 6 * IloIntVar(10)[0..50000]  + 9 * IloIntVar(11)[0..50000]  <= 45000
}


Solution status is: Infeasible
Error: CPLEX Error  1217: No solution exists.

Upvotes: 0

Views: 235

Answers (1)

Daniel Junglas
Daniel Junglas

Reputation: 5940

You can use the conflict refiner to analyze infeasibility. This can be done by calling cplex.refineConflict(). For small problems it is however simpler to export the model and analyze the conflict in the interactive optimizer. To this end, call cplex.exportModel("food.lp") before calling cplex.solve(). Then in the console invoke the interactive optimizer (cplex.exe on Windows and cplex for other operating systems) and do the following at the prompt:

CPLEX> read food.lp
CPLEX> tools conflict
CPLEX> display conflict all

This will find a minimal set of conflicting constraints and display them. In your case, the conflict is:

Subject To
 c7:  x9 + x10 + x11 + x12 >= 9000
 c19: 8 x9 + 6 x10 + 6 x11 + 9 x12 - Rgc19  = 36000
\Sum of equality rows in the conflict:
\ sum_eq: 8 x9 + 6 x10 + 6 x11 + 9 x12 - Rgc19  = 36000
Bounds
      x9 >= 0
      x10 Free
      x11 Free
      x12 >= 0
 -Inf <= Rgc19 <= 9000
Generals
 x9  x10  x11  x12

You can make this more readable if you assign names to your variables and constraints in your program.

In any case, you can see that c7 requires the four variables to sum to 9000 or more. That means that in the second constraint the sum 8 x9 + 6 x10 + 6 x11 + 9 x12 will be at least 6 * 9000 = 54000. Given that the upper bound on Rgct19 is 9000 it is clear that this constraint can never be satisfied since 54000 - 9000 <= 36000 can never be true. It seems there is something wrong with your data.

Upvotes: 2

Related Questions