Decision Optimization

 View Only
  • 1.  Issue to the naming constraints on docplex

    Posted Mon December 13, 2021 09:37 AM
    Dear community team,

    I am trying to use docplex on google colab to solve an optimization problem in which I need to label the constraints to invoke their dual values. What I am trying to do is:
    mdl.add_constraints(mdl.sum(x[i,j] for j in machines) == 1 for i in tasks, "assign");​
    When I run the model I get this error:
    File "<ipython-input-55-ebac7052607c>", line 46
        mdl.add_constraints(mdl.sum(x[i,j] for j in machines) == 1 for i in tasks, "assign");
                           ^
    SyntaxError: Generator expression must be parenthesized​
    As I have seen some examples that define the labeling as I mentioned and they work fine, I was wondering if, where I am doing wrong? 

    My second question is, how we can invoke the variable's value by relaxing the original problem?
    LP = LinearRelaxer.make_relaxed_model(mdl)
    LP.print_information()
    results= LP.solve(log_output=True)
    print("-------------------------------------")
    LP.report()
    print("-------------------------------------")
    X =LP.solution.get_value_dict(x)
    print(X)​
    The error is:
    DOcplexException                          Traceback (most recent call last)
    <ipython-input-57-da511e6cc21e> in <module>()
         78 LP.report()
         79 print("-------------------------------------")
    ---> 80 X =LP.solution.get_value_dict(x)
         81 print(X)
    
    7 frames
    /usr/local/lib/python3.7/dist-packages/docplex/mp/error_handler.py in fatal(self, msg, args)
        208         resolved_message = resolve_pattern(msg, args)
        209         docplex_error_stop_here()
    --> 210         raise DOcplexException(resolved_message)
        211 
        212     def fatal_limits_exceeded(self, nb_vars, nb_constraints):
    
    DOcplexException: Cannot mix objects from different models in new_binary_constraint. obj1=x_j1_m2, obj2=x_j1_m2​


    Regards



    ------------------------------
    Abbas Omidi
    ------------------------------



  • 2.  RE: Issue to the naming constraints on docplex

    Posted Wed December 15, 2021 10:31 AM
    ```mdl.sum(x[i,j] for j in machines) == 1 for i in tasks​``` is a generator.
    But docplex and Python deals with iterables so you need to put it into a list via ```[ ]```

    So
    mdl.add_constraints([mdl.sum(x[i,j] for j in machines) == 1 for i in tasks], "assign");​​​

    should work.



    ------------------------------
    Vincent Beraudier
    ------------------------------



  • 3.  RE: Issue to the naming constraints on docplex

    Posted Thu December 16, 2021 09:21 AM
    Dear Vincent,

    Many thanks for your comments. It works fine.
    Another issue I have faced is that when I want to invoke the value of the decision variables outside of the defined function I cannot get the correct results. The following notation is shown by the solver:
    x_solution = m2.get_var_value
    print(x_solution)
    
    variables ================================================
    
    <bound method SolveSolution.get_var_value of docplex.mp.solution.SolveSolution(obj=18,values={x_j1_m1:1,x_j2_m1:1,x_j..>​

    Also, I would like to write the LR dual function as follows:

    sum{i in tasks, j in machines} x(i,j)*c(i,j) + sum{i in tasks} u(i)*[1-sum{j in machines} x(i,j)]​

    PS: I have tried to write a minimal working example on colab in this link. Please see that.

    Regards

    ------------------------------
    Abbas Omidi
    ------------------------------



  • 4.  RE: Issue to the naming constraints on docplex

    Posted Fri December 17, 2021 04:46 AM
    ```m2.get_var_value``` is a (undocumented) method.
    You need to use arguments with it, for example like ```m2.get_var_value(x[("j1", "m1")])```
    The documented method is Solution.get_value

    I think your code for the LR expression should be something like:

    u = {}
    for i,t in enumerate(tasks):
        u[t] = m3.get_constraint_by_index(i).dual_value
    
    kpi = mdl.sum( x[(i,j)]*c[(i,j)] for i in tasks for j in machines) + mdl.sum( u[i]*(1- mdl.sum(x[(i,j)] for j in machines )) for i in tasks)
    mdl.add_kpi(kpi, "LR_kpi")
    
    sol = mdl.solve()
    kpi_value = sol.kpi_value_by_name("LR_kpi")
    ​




    ------------------------------
    Vincent Beraudier
    ------------------------------



  • 5.  RE: Issue to the naming constraints on docplex

    Posted Sat December 18, 2021 02:04 AM
    Edited by Abbas Omidi Sat December 18, 2021 02:06 AM
    Dear Vincent,

    Thanks so much for your replying. Before using what you provided in the previous post I would like to know, how we can access the decision variable outside of the function? In my case, I defined a function to call the optimization model and return its attributes. 
    def GAP():
      # Declare variables
      mdl = Model(name='GAP')
      
      idx_x = [(i,j) for i in tasks for j in machines]
      x = mdl.binary_var_dict(idx_x, name="x");
    
      '''
      the model
      '''
    
    if __name__ == '__main__':
      m1 = GAP()​

    In the next step, when I want to invoke this variable outside of the defined function I have some issues:

    x_solution = m2.get_var_value(m2.x[("j1", "m1")])

    In this situation, the x variable cannot be achieved and the solver produces an error as:

    AttributeError: 'SolveSolution' object has no attribute 'x'

    Also, when I write the kpi function in the first definition that you suggested it works fine, but in the second form it produces the following note:

    kpi= mdl.minimize(mdl.sum(x[i,j]*c[i,j] for i in tasks for j in machines));
    mdl.add_kpi(kpi, "MIP_kpi")
    
    ============================================
    DOcplexException: Cannot interpret this as a KPI: None. expecting expression, variable or function

    Regards



    ------------------------------
    Abbas Omidi
    ------------------------------



  • 6.  RE: Issue to the naming constraints on docplex

    Posted Mon December 20, 2021 04:50 AM
    m1 is the model, m2 is the solution. It is not easy to follow with such a naming.
    m and s would be easier ;-)

    * Accessing the x array variables.
    ``` def GAP()``` return the model mdl. You can return the model and the variables like this ``` return mdl, x```
    It will return it as a tuple which can then be accessed via ``` m1, x = GAP() ```

    or you can "attach" the x array on the model itself in the GAP method when you create it with ``` mdl.x = x ``` then you will access it with ```x_solution = m1.get_var_value(m2.x[("j1", "m1")])```

    *About the KPI
    the method Model.minimize is a setter which returns nothing. So kpi is None.

    ------------------------------
    Vincent Beraudier
    ------------------------------



  • 7.  RE: Issue to the naming constraints on docplex

    Posted Mon December 20, 2021 08:13 AM
    Dear Vincent,

    Many thanks for your clarifying and suggestion for naming the model. As the use of the functional form has had some limitations, specifically in colab, I am managing to write the model in the simple form for ease of use, defining the syntax, and having access to its related examples. Please, see this link. In the next step, I will come back to functional form. :)

    Let's say, in this form we can define the original model and its related outputs. It works fine. Then we have tried to achieve the value of the variables by:
    for v in mdl.iter_binary_vars():
      print(v," = ",v.solution_value)
    ​

    It seems the method works. As we need to access the variable's value in the subgradient method, it is so important. Also, I have seen another method to invoke the variable's value that would be convenient to use. It is something like this, but when I run the code the following error is shown:

    for i in range(len(tasks)):
      for j in range(len(machines)):
        print(m.x[i,j].solution_value)
    
    =error===================================
    'SolveSolution' object has no attribute 'x'

    Would you say please, what is the difference between the first and the second method to invoke the variable's value?

    The expression that we will need to write to calculate the Gamma looks like: gamma(i) = 1 - sum{j, x.value(i,j)} and what I have tried is:

    for i in range(len(tasks)):
      gamma[i] = 1- ([j.solution_value] for j in lr.iter_binary_vars())
    
    =error===============================
    TypeError: unsupported operand type(s) for -: 'int' and 'generator'



    About the KPI's, we could define this for the second objective (LR) based on your mentioned function and it works very well, but when I want to define multiple KPI's, for the first objective (original model) and the second one simultaneously, it shows that the multiple KPI's has not been allowed. I was wondering if, how we can define multiple KPI's to store the objective function's values (original and LR in the different values)?

    Regards



    ------------------------------
    Abbas Omidi
    ------------------------------