Decision Optimization

 View Only
  • 1.  Model from milp to lp docplex

    Posted Mon June 07, 2021 04:54 AM
    Edited by System Fri January 20, 2023 04:14 PM
    Hi,

    I want to solve an integer version of my LP model and for that I had to add a binary variable, say A. After the integer solve, I want to reuse again the LP model. I tried removing the variable A but apparently it is not possible. so I tried changing its type to continuous this way
    [Model._set_var_type(i, self.Model.continuous_vartype) for i in A.values()]​

    however, when I try to get the duals of my model, it says that my model is MILP and duals are not accessible for that type. As if the problem type is not updated after this change. I checked the number of integer/binary variables in my model and it is 0, but the problem type is MILP!
    How is possible to inform docplex that the type of the model is actually LP and not MILP? 

    Thank you!
    #DecisionOptimization


  • 2.  RE: Model from milp to lp docplex

    Posted Mon June 07, 2021 05:26 AM
    Hi,

      If you want to solve a linear model, where all discrete variables are fixed to their value sin a previous solve, use solve_fixed.
    If you want to solve a linear relaxation of the MILP model, regardless of previous solve values, use the LinearRelaxer class

    Attached is a sample with solve fixed.

       Regards.

        Philippe Couronne


    ------------------------------
    Philippe Couronne
    ------------------------------



  • 3.  RE: Model from milp to lp docplex

    Posted Mon June 07, 2021 05:46 AM
    thanks for your reply. 
    I tried to use the Linear_relaxer class
    rx=LinearRelaxer()
    Model=rx.linear_relaxation(Model)
    but I get an error:
    RuntimeError: dictionary changed size during iteration 
    I also tried to clone/copy the model before adding the integer variable and I get the same error. 
    I am adding columns as in a column generation and I suppose that that is the reason of the error message. 
    Is there a way to fix this?
    Thanks!


  • 4.  RE: Model from milp to lp docplex

    Posted Mon June 07, 2021 06:11 AM
    Are you using a recent version of DOcplex ( I suggest either 2.20 or 2.21)? If not I suggest first upgrade to one those two.
    I understand you get two issues:one with the relaxer and another with Model.clone() is that so?
    Can you reproduce with a small sample, that would help?

       Regards,

         Philippe

    ------------------------------
    Philippe Couronne
    ------------------------------



  • 5.  RE: Model from milp to lp docplex

    Posted Mon June 07, 2021 06:34 AM
    I was using version 2.20 and I just upgraded it to the latest version, but the error remains.
    Here is an example
    mdl = Model('LP')
    time_periods = [1,2,3]
    initial_routes = [10,20]
    keys = [(route, t) for route in initial_routes for t in time_periods]
    x = mdl.continuous_var_dict(keys, name="x", lb=0, ub=1)
    new_routes_periods = solve_subproblem() # long function basically a labelling algorithm and can assume the output someting like: [(11,2),(13,1)]
    x.update(self.Model.continuous_var_dict(new_routes_periods , name="x", lb=0, ub=1))
    mdl.clone() # does not work 
    A = mdl.integer_var_dict(time_periods, self.T, lb=0, ub=1, name="A")\
    mdl.add_constraints(A[t]==mdl.sum(x[route,t] for route in initial_routes+new_routes)) # new_routes = [11,13]
    mdl.solve()
    rx=LinearRelaxer()
    self.Model=rx.linear_relaxation(self.Model) # doesn't work​
    I can see that the error is thrown because of the update of the x variable because of the error message I get:
    container
    return self.model.get_var_container(self)
    File "C:\Users\Local\Programs\Python\Python37\lib\site-packages\docplex\mp\model.py", line 1312, in get_var_container
    ctn_map = self._ensure_var_to_container_map()
    File "C:\Users\Local\Programs\Python\Python37\lib\site-packages\docplex\mp\model.py", line 1301, in _ensure_var_to_container_map
    for dv in ctn.iter_variables():
    RuntimeError: dictionary changed size during iteration



  • 6.  RE: Model from milp to lp docplex

    Posted Mon June 07, 2021 08:22 AM
    Thanks for the sample. Though is is not self-contained, I was able to reproduce and understand.
    The root cause is the "update" you are performing on the variable dict.
    This is not really necessary but breaks the internal consistency, as internal container objects keep an iterator on the
    dict's values, which your code has modified. Hence this stored iterator crashes when it is executed.
    I agree the documentation should make it explicit that variable dicts (and lists) should not be modified after created.

    The workaround is simple: do not call "update" on an existing variable dict, create a new one.
    With this modification, both `clone` and `relax` work fine:


    from docplex.mp.model import Model
    from docplex.mp.relax_linear import LinearRelaxer
    mdl = Model('LP')
    time_periods = [1,2,3]
    initial_routes = [10,20]
    keys = [(route, t) for route in initial_routes for t in time_periods]
    x = mdl.continuous_var_dict(keys, name="x", lb=0, ub=1)
    #new_routes_periods = solve_subproblem() # long function basically a labelling algorithm and can assume the output someting like: [(11,2),(13,1)]
    #x.update(mdl.continuous_var_dict([4,5] , name="x", lb=0, ub=1))
    x2 = mdl.continuous_var_dict([4,5] , name="x", lb=0, ub=1)


    mdl2 = mdl.clone() # does not work
    mdl2.print_information()

    rx=LinearRelaxer()
    lm = rx.linear_relaxation(mdl) # doesn't work​
    lm.print_information()


    >>>

    Model: Copy of LP
    - number of variables: 8
    - binary=0, integer=0, continuous=8
    - number of constraints: 0
    - linear=0
    - parameters: defaults
    - objective: none
    - problem type is: LP
    Model: lp_LP
    - number of variables: 8
    - binary=0, integer=0, continuous=8
    - number of constraints: 0
    - linear=0
    - parameters: defaults
    - objective: none
    - problem type is: LP


    ------------------------------
    Philippe Couronne
    ------------------------------



  • 7.  RE: Model from milp to lp docplex

    Posted Tue June 08, 2021 02:37 AM
    Thanks for your reply.
    unfortunately, I have already written my code using the dict.update (because I create new variable in each iteration of the column generation which is highly iterative), and I cannot use the workaround suggested as it will take too much time to reimplement it.
    it would be nice to be able to have a feature/method that makes Cplex  re-evaluate whether the model is LP or MILP.


  • 8.  RE: Model from milp to lp docplex

    Posted Tue June 08, 2021 03:38 AM
    What you need is a way to change the CPLEX problem type. To avoid losing consistency between cplex and docplex, I strongly advise to do it temporarily. I have modified the `solvefixed` example code to set the problem type to 0 (LP) instead of 3 (fixedMIP).
    Using a contextmanager ensures the actual type is restored at the end.
    I did only  basic tests, there might be other issues I missed:

    @contextmanager
    def model_solve_as_lp(mdl):
    cpx = mdl._get_cplex(do_raise=True, msgfn=lambda: "model_solvefixed requires CPLEX")
    # save initial problem type, to be restored.
    saved_problem_type = cpx.get_problem_type()
    if saved_problem_type == 0:
    mdl.warning("Model {0} is a LP model, solvefixed does nothing".format(mdl.name))
    return mdl
    try:
    cpx.set_problem_type(0) # 3 is constant fixed_MILP
    yield mdl
    finally:
    cpx.set_problem_type(saved_problem_type)

    ------------------------------
    Philippe Couronne
    ------------------------------



  • 9.  RE: Model from milp to lp docplex

    Posted Wed June 09, 2021 03:51 AM
    thanks for your answer!