Decision Optimization

Decision Optimization

Delivers prescriptive analytics capabilities and decision intelligence to improve decision-making.

 View Only
  • 1.  Custom diet.py and diet.dat - "Exception: data file error" trouble.

    Posted Tue January 19, 2016 06:41 AM

    Originally posted by: ModulM


    Here the code of my custom diet.py C:\Program Files\IBM\ILOG\CPLEX_Studio_Community1263\cplex\examples\src\python
    #!/usr/bin/python
    # ---------------------------------------------------------------------------
    # File: diet.py
    # Version 12.6.3
    # ---------------------------------------------------------------------------
    # Licensed Materials - Property of IBM
    # 5725-A06 5725-A29 5724-Y48 5724-Y49 5724-Y54 5724-Y55 5655-Y21
    # Copyright IBM Corporation 2009, 2015. All Rights Reserved.
    #
    # US Government Users Restricted Rights - Use, duplication or
    # disclosure restricted by GSA ADP Schedule Contract with
    # IBM Corp.
    # ---------------------------------------------------------------------------
    #
    # diet.py -- A diet problem
    #
    # Problem Description
    # -------------------
    #
    # Mimimize the cost of a diet subject to nutritional constraints.
    #
    # To run from the command line, use
    #
    #    python diet.py
    
    from __future__ import print_function
    
    import sys
    import os
    import cplex
    from cplex.exceptions import CplexError
    from inputdata import read_dat_file
    
    # a class to store problem data
    
    
    class ProbData:
    
        def __init__(self, filename):
    
            # read the data in diet.dat
            (self.foodCost, self.foodMin, self.foodMax, self.nutrMin,
             self.nutrMax, self.nutrPer) = read_dat_file("../../data/diet.dat")
    
            # check data consistency
            if (len(self.foodCost) != len(self.foodMin) or
                    len(self.foodCost) != len(self.foodMax) or
                    len(self.nutrMin) != len(self.nutrMax) or
                    len(self.nutrMin) != len(self.nutrPer)):
                print("ERROR: Data file '%s' contains inconsistent data\n" %
                      filename)
                raise Exception("data file error")
    
            for np in self.nutrPer:
                if len(self.foodCost) != len(np):
                    print("ERROR: Data file '%s' contains inconsistent data\n" %
                          filename)
                    raise Exception("data file error")
    
    
    def populatebyrow(prob, data):
    
        nFoods = len(data.foodCost)
        nNutrients = len(data.nutrMin)
    
        # we want to minimize costs
        prob.objective.set_sense(prob.objective.sense.minimize)
    
        # add variables to decide how much of each type of food to buy
        varnames = ["x" + str(j) for j in range(nFoods)]
        prob.variables.add(obj=data.foodCost,
                           lb=data.foodMin,
                           ub=data.foodMax,
                           names=varnames)
    
        # add constraints to specify limits for each of the nutrients
        for n in range(nNutrients):
            prob.linear_constraints.add(
                lin_expr=[[varnames, data.nutrPer[n]]],
                senses=["R"],
                rhs=[data.nutrMin[n]],
                range_values=[data.nutrMax[n] - data.nutrMin[n]])
    
    
    def populatebycolumn(prob, data):
        nFoods = len(data.foodCost)
        nNutrients = len(data.nutrMin)
    
        # we want to minimize costs
        prob.objective.set_sense(prob.objective.sense.minimize)
    
        # create empty constraints to be filled later
        rownames = ["r" + str(n) for n in range(nNutrients)]
        prob.linear_constraints.add(senses=["R" * nNutrients],
                                    rhs=data.nutrMin,
                                    range_values=[data.nutrMax[n] - data.nutrMin[n]
                                                  for n in range(nNutrients)],
                                    names=rownames)
    
        # create columns
        for j in range(nFoods):
            prob.variables.add(obj=[data.foodCost[j]],
                               lb=[data.foodMin[j]],
                               ub=[data.foodMax[j]],
                               columns=[[rownames, [data.nutrPer[n][j]
                                                    for n in range(nNutrients)]]])
    
    
    def diet(pop_method):
        try:
            # read the data in diet.dat
            data = ProbData("../../data/diet.dat")
    
            # create CPLEX object
            my_prob = cplex.Cplex()
    
            # sys.stdout is the default output stream for log and results
            # so these lines may be omitted
            my_prob.set_results_stream(sys.stdout)
            my_prob.set_log_stream(sys.stdout)
    
            # populate problem
            if pop_method == "r":
                handle = populatebyrow(my_prob, data)
            elif pop_method == "c":
                handle = populatebycolumn(my_prob, data)
            else:
                raise ValueError('pop_method must be one of "r" or "c"')
    
            # solve problem
            my_prob.solve()
    
        except CplexError as exc:
            print(exc)
            return
    
        numrows = my_prob.linear_constraints.get_num()
        numcols = my_prob.variables.get_num()
    
        solution = my_prob.solution
    
        # solution.get_status() returns an integer code
        print("Solution status = ", solution.get_status(), ":", end=' ')
        # the following line prints the corresponding string
        print(solution.status[solution.get_status()])
        print("Objective value = ", solution.get_objective_value())
    
        x = solution.get_values(0, my_prob.variables.get_num() - 1)
        for j in range(my_prob.variables.get_num()):
            print("Buy %d = %17.10g" % (j, x[j]))
    
        my_prob.write("dietresults.lp")
        solution.write("dietsolution.lp")
        
    if __name__ == "__main__":
        if len(sys.argv) != 2 or sys.argv[1] not in ["-r", "-c"]:
            print("Usage: diet.py -X")
            print("   where X is one of the following options:")
            print("      r          generate problem by row")
            print("      c          generate problem by column")
            print(" Exiting...")
            sys.exit(-1)
        diet(sys.argv[1][1])
    

    Here the values of normal diet.dat

    [1.84, 2.19, 1.84, 1.44, 2.29, 0.77, 1.29, 0.6, 0.72]
    [0, 0, 0, 0, 0, 0, 0, 0, 0]
    [10, 10, 10, 10, 10, 10, 10, 10, 10]
    [2000, 350, 55, 100, 100, 100, 100]
    [9999, 375, 9999, 9999, 9999, 9999, 9999]
    [[510, 370, 500, 370, 400, 220, 345, 110, 80],
     [34, 35, 42, 38, 42, 26, 27, 12, 20],
     [28, 24, 25, 14, 31, 3,  15, 9,  1],
     [15, 15, 6,  2,  8 , 0,  4 , 10, 2],
     [6,  10, 2,  0,  15, 15, 0 , 4,  120],
     [30, 20, 25, 15, 15, 0,  20, 30, 2],
     [20, 20, 20, 10, 8 , 2,  15, 0,  2]]

    I replace i with my custom diet.dat with other number of nutrients and food values, as shown below.

    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    [10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
    [3330, 0.594, 90, 34.2, 720, 5.4, 297, 522, 4230, 1350, 8.46, 0.63, 2.07, 40.5, 67.5, 0.9, 0.99, 10.8, 4.5, 0.99, 288, 495, 1.8, 562.5, 10.8, 9]
    [4070, 0.726, 110, 41.8, 880, 6.6, 363, 638, 5170, 1650, 10.34, 0.77, 2.53, 49.5, 82.5, 1.1, 1.21, 13.2, 5.5, 1.21, 352, 605, 2.2, 687.5, 13.2, 11]
    [[85.56, 0.26, 13.81, 2.4, 6, 0.12, 5, 11, 107, 1, 0.04, 0.027, 0.035, 0, 4.6, 0.017, 0.026, 0.091, 0.061, 0.041, 3, 3.4, 0, 3, 0.18, 0],
    [86.35, 1.4, 11.12, 2, 13, 0.39, 10, 23, 259, 1, 0.2, 0.078, 0.077, 0.1, 10, 0.03, 0.04, 0.6, 0.24, 0.054, 9, 2.8, 0, 96, 0.89, 0],
    [74.91, 1.09, 22.84, 2.6, 5, 0.26, 27, 22, 358, 1, 0.15, 0.078, 0.27, 1, 8.7, 0.031, 0.073, 0.665, 0.334, 0.367, 20, 9.8, 0, 3, 0.1, 0],
    [88.15, 1.39, 9.61, 5.3, 29, 0.62, 20, 22, 162, 1, 0.53, 0.165, 0.646, 0.4, 21, 0.02, 0.026, 0.646, 0.276, 0.03, 25, 8.5, 0, 11, 1.17, 0],
    [86.75, 0.94, 11.75, 2.4, 40, 0.1, 10, 14, 181, 0, 0.07, 0.045, 0.025, 0.5, 53.2, 0.087, 0.04, 0.282, 0.25, 0.06, 30, 8.4, 0, 11, 0.18, 0],
    [90.95, 0.67, 7.68, 2, 16, 0.41, 13, 24, 153, 1, 0.14, 0.048, 0.386, 0.4, 58.8, 0.024, 0.022, 0.386, 0.125, 0.047, 24, 5.7, 0, 1, 0.29, 0],
    [45.52, 21.58, 0.12, 0, 298, 1.62, 29, 375, 158, 415, 0.66, 0.564, 0.093, 3.8, 0, 0.072, 0.676, 1.148, 0.19, 0.06, 2, 15.4, 0.22, 407, 0.26, 0.5],
    [15.87, 0.85, 0.06, 0, 24, 0.02, 2, 24, 24, 643, 0.09, 0, 0, 1, 0, 0.005, 0.034, 0.042, 0.11, 0.003, 3, 18.8, 0.17, 684, 2.32, 0],
    [43.85, 5.33, 40.01, 9.3, 133, 0.48, 65, 143, 213, 113, 1.06, 0.36, 0.677, 3.9, 0, 0.182, 0.2, 3.528, 0.297, 0.093, 17, 14.5, 0.07, 26, 0.7, 0.2],
    [7.74, 5.55, 74.72, 8.3, 444, 2.7, 82, 244, 333, 375, 1.15, 0.187, 1.748, 14.8, 39.1, 0.411, 0.1, 0.478, 0.588, 0.073, 20, 22.5, 0, 0, 0.98, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.2, 0, 0, 0, 0, 0, 0, 0, 79.8, 0, 0, 2.7, 0.7],
    [84.05, 1.82, 8.52, 0.4, 23, 0.64, 3, 31, 138, 669, 0.7, 0.1, 0.3, 1.9, 2.2, 0.043, 0.062, 0.62, 0.11, 0.01, 19, 13, 0.04, 26, 0.49, 0],
    [2.12, 13.14, 74.24, 29.3, 389, 17.6, 362, 1150, 1020, 258, 12.4, 1.04, 7.41, 9.4, 20, 2.27, 2.71, 14.8, 1.06, 12, 1310, 49.4, 18.8, 522, 1.19, 4.3],
    [28.28, 10.06, 0.32, 0, 36, 0.82, 12, 160, 214, 125, 1.13, 0.045, 0.007, 15.1, 0, 0.246, 0.139, 3.93, 0.513, 0.234, 0, 46, 1.4, 0, 0.24, 1.5],
    [92.82, 3.99, 2.1, 1.9, 32, 0.96, 27, 70, 79, 6, 0.92, 0.157, 0.188, 0.6, 8.2, 0.076, 0.126, 0.481, 0.563, 0.034, 36, 14.4, 0, 8, 0.02, 0],
    [62.11, 28.15, 0, 0, 14, 3.14, 23, 224, 390, 87, 9.82, 0.126, 0.016, 31.4, 0, 0.09, 0.313, 4.34, 1.025, 0.404, 7, 105.3, 5.18, 2, 0.14, 0.1],
    [91.96, 0.46, 3.55, 0, 4, 0.02, 6, 14, 27, 4, 0.01, 0.005, 0.008, 0.6, 0, 0.005, 0.025, 0.513, 0.041, 0.046, 6, 10.1, 0.02, 0, 0, 0]]

    Then i got this error, when I try to solve it. Can you help me with fixing it? Does not see a trouble in the strings in traceback. Thank you very much for your attention!

    C:\Program Files\IBM\ILOG\CPLEX_Studio_Community1263\cplex\examples\src\python>python diet.py -r

    ERROR: Data file '../../data/diet.dat' contains inconsistent data

    Traceback (most recent call last):
      File "diet.py", line 163, in <module>
        diet(sys.argv[1][1])
      File "diet.py", line 112, in diet
        data = ProbData("../../data/diet.dat")
      File "diet.py", line 52, in __init__
        raise Exception("data file error")
    Exception: data file error


    #CPLEXOptimizers
    #DecisionOptimization


  • 2.  Re: Custom diet.py and diet.dat - "Exception: data file error" trouble.

    Posted Tue January 19, 2016 08:00 AM

    If you look at line 52 in diet.py (the point that raises the exception) then you will find that it is this check that fails:

            if (len(self.foodCost) != len(self.foodMin) or
                    len(self.foodCost) != len(self.foodMax) or
                    len(self.nutrMin) != len(self.nutrMax) or
                    len(self.nutrMin) != len(self.nutrPer)):
                print("ERROR: Data file '%s' contains inconsistent data\n" %
                      filename)
                raise Exception("data file error")

    And indeed, the length of arrays nutrMin and nutrMax is 26, while the length of nutrPer is only 17. You have to fix up that array in the .dat file.


    #CPLEXOptimizers
    #DecisionOptimization


  • 3.  Re: Custom diet.py and diet.dat - "Exception: data file error" trouble.

    Posted Tue January 19, 2016 10:12 AM

    Originally posted by: ModulM


    Thank you for answer. I modified diet.dat, as shown below, but return the same error. Tried to fix as I unterstand your message. For example, nutrMin (water) = 3330, nutrMax (water) = 4070, and this row below represent a water per food name(85.56 = water in food1, 86.35 = water in food2, etc. Water = [[85.56, 86.35, 74.91, 88.15, 86.75, 90.95, 45.52, 15.87, 43.85, 7.74, 0, 84.05, 2.12, 28.28, 92.82, 62.11, 91.96], next rows represent other nutrients. P.S. In the topic starter post i thought that I must wrote in a row as in nutrMin row: water in food 1, sodium in food 1. etc.
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    [10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
    [3330, 0.594, 90, 34.2, 720, 5.4, 297, 522, 4230, 1350, 8.46, 0.63, 2.07, 40.5, 67.5, 0.9, 0.99, 10.8, 4.5, 0.99, 288, 495, 1.8, 562.5, 10.8, 9]
    [4070, 0.726, 110, 41.8, 880, 6.6, 363, 638, 5170, 1650, 10.34, 0.77, 2.53, 49.5, 82.5, 1.1, 1.21, 13.2, 5.5, 1.21, 352, 605, 2.2, 687.5, 13.2, 11]
    [[85.56, 86.35, 74.91, 88.15, 86.75, 90.95, 45.52, 15.87, 43.85, 7.74, 0, 84.05, 2.12, 28.28, 92.82, 62.11, 91.96],
    [0.26, 1.4, 1.09, 1.39, 0.94, 0.67, 21.58, 0.85, 5.33, 5.55, 0, 1.82, 13.14, 10.06, 3.99, 28.15, 0.46],
    [13.81, 11.12, 22.84, 9.61, 11.75, 7.68, 0.12, 0.06, 40.01, 74.72, 0, 8.52, 74.24, 0.32, 2.1, 0, 3.55],
    [2.4, 2, 2.6, 5.3, 2.4, 2, 0, 0, 9.3, 8.3, 0, 0.4, 29.3, 0, 1.9, 0, 0],
    [6, 13, 5, 29, 40, 16, 298, 24, 133, 444, 0, 23, 389, 36, 32, 14, 4],
    [0.12, 0.39, 0.26, 0.62, 0.1, 0.41, 1.62, 0.02, 0.48, 2.7, 0, 0.64, 17.6, 0.82, 0.96, 3.14, 0.02],
    [5, 10, 27, 20, 10, 13, 29, 2, 65, 82, 0, 3, 362, 12, 27, 23, 6],
    [11, 23, 22, 22, 14, 24, 375, 24, 143, 244, 0, 31, 1150, 160, 70, 224, 14],
    [107, 259, 358, 162, 181, 153, 158, 24, 213, 333, 0, 138, 1020, 214, 79, 390, 27],
    [1, 1, 1, 1, 0, 1, 415, 643, 113, 375, 0, 669, 258, 125, 6, 87, 4],
    [0.04, 0.2, 0.15, 0.53, 0.07, 0.14, 0.66, 0.09, 1.06, 1.15, 0, 0.7, 12.4, 1.13, 0.92, 9.82, 0.01],
    [0.027, 0.078, 0.078, 0.165, 0.045, 0.048, 0.564, 0, 0.36, 0.187, 0, 0.1, 1.04, 0.045, 0.157, 0.126, 0.005],
    [0.035, 0.077, 0.27, 0.646, 0.025, 0.386, 0.093, 0, 0.677, 1.748, 0, 0.3, 7.41, 0.007, 0.188, 0.016, 0.008],
    [0, 0.1, 1, 0.4, 0.5, 0.4, 3.8, 1, 3.9, 14.8, 0.2, 1.9, 9.4, 15.1, 0.6, 31.4, 0.6],
    [4.6, 10, 8.7, 21, 53.2, 58.8, 0, 0, 0, 39.1, 0, 2.2, 20, 0, 8.2, 0, 0],
    [0.017, 0.03, 0.031, 0.02, 0.087, 0.024, 0.072, 0.005, 0.182, 0.411, 0, 0.043, 2.27, 0.246, 0.076, 0.09, 0.005],
    [0.026, 0.04, 0.073, 0.026, 0.04, 0.022, 0.676, 0.034, 0.2, 0.1, 0, 0.062, 2.71, 0.139, 0.126, 0.313, 0.025],
    [0.091, 0.6, 0.665, 0.646, 0.282, 0.386, 1.148, 0.042, 3.528, 0.478, 0, 0.62, 14.8, 3.93, 0.481, 4.34, 0.513],
    [0.061, 0.24, 0.334, 0.276, 0.25, 0.125, 0.19, 0.11, 0.297, 0.588, 0, 0.11, 1.06, 0.513, 0.563, 1.025, 0.041],
    [0.041, 0.054, 0.367, 0.03, 0.06, 0.047, 0.06, 0.003, 0.093, 0.073, 0, 0.01, 12, 0.234, 0.034, 0.404, 0.046],
    [3, 9, 20, 25, 30, 24, 2, 3, 17, 20, 0, 19, 1310, 0, 36, 7, 6],
    [3.4, 2.8, 9.8, 8.5, 8.4, 5.7, 15.4, 18.8, 14.5, 22.5, 79.8, 13, 49.4, 46, 14.4, 105.3, 10.1],
    [0, 0, 0, 0, 0, 0, 0.22, 0.17, 0.07, 0, 0, 0.04, 18.8, 1.4, 0, 5.18, 0.02],
    [3, 96, 3, 11, 11, 1, 407, 684, 26, 0, 0, 26, 522, 0, 8, 2, 0],
    [0.18, 0.89, 0.1, 1.17, 0.18, 0.29, 0.26, 2.32, 0.7, 0.98, 2.7, 0.49, 1.19, 0.24, 0.02, 0.14, 0],
    [0, 0, 0, 0, 0, 0, 0.5, 0, 0.2, 0, 0.7, 0, 4.3, 1.5, 0, 0.1, 0]]


    #CPLEXOptimizers
    #DecisionOptimization


  • 4.  Re: Custom diet.py and diet.dat - "Exception: data file error" trouble.

    Posted Thu January 21, 2016 09:28 AM

    As you can see in line 42 of diet.py, the program reads 6 arrays from the diet.dat file:

    # read the data in diet.dat
    (self.foodCost, self.foodMin, self.foodMax, self.nutrMin,
     self.nutrMax, self.nutrPer) = read_dat_file("diet.dat")
    

    The subsequent checks in diet.py verify the following:

    • foodCost, foodMin, foodMax must all have the same length
    • nutrMin, nutrMax, nutrPer must all have the same length
    • nutrPer is actually an array of arrays, each array in nutrPer must have the same length as foodCost

    The last check is the one that fails for your updated diet.dat. The arrays in nutrPer only have 17 elements while they should have 26 (the length of foodCost). Note that nutrPer[n][f] gives the amount of nutrient n in one unit of food f. Hence it should be clear that each element in nutrPer must be an array with as many elements as there are foods.

    BTW, it should be very easy to track down your errors in a .dat file with a debugger. Please try this first before posting further problems about incorrect .dat files.


    #CPLEXOptimizers
    #DecisionOptimization