メインコンテンツへスキップ

With decision variables in 'for' loop occur:Error code 0: Constraint has no bool value (are you trying "lb <= expr <= ub"?)

回答済み

コメント

14件のコメント

  • Jaromił Najman
    Gurobi Staff Gurobi Staff

    Variable objects don't have a value and thus, cannot be used in \(\texttt{if}\)-clauses or any similar checks. This means that the check \(\texttt{x[f] <= t}\) cannot be evaluated when constructing the model. You have to formulate the conditional statement via additional binary variables and constraints. Please have a look at How do I model conditional statements in Gurobi? for more details.

    Once you have formulated the conditional statements, you can use Gurobi's addGenConstrAnd method to formulate the "and" condition in your first \(\texttt{if}\)-clause.

    You second \(\texttt{if}\)-clause actually reads \(\texttt{if x[f] = t then add constraints}\). Formulating an equality check where \(x\) is a continuous variable is tricky. The stackexchange post In an integer program, how I can force a binary variable to equal 1 if some condition holds? describes a good way to approach this.

    Best regards, 
    Jaromił

    0
  • Jingyue Zhang
    Gurobi-versary
    Collaborator
    Curious

    Thanks a lot! However, there was a typing error for the second if-clause, the code is actually:

     t = 0
            for t in range(288):
                for f in tof.keys():
                    if x[f] <= t and t <= x[f] + 6:
                        m.addConstr(y.sum('*', '*') <= qk, 'c2')
                    else:
                        t += 1
                    if x[f] <= t <= z[f]:
                        for p in fleetType:   
                            m.addConstr(y.sum('*', p) <= xp, 'c8')
                    else:
                        t += 1

    I guess it could be solved using the same method as the first if-clause?

    0
  • Jingyue Zhang
    Gurobi-versary
    Collaborator
    Curious

    Hi again! I revised the code compression like this:

          s  = m.addVar(vtype=GRB.BINARY, name="s")
          h  = m.addVar(vtype=GRB.BINARY, name="h")
          h2  = m.addVar(vtype=GRB.BINARY, name="h2")
          x2  = m.addVar(vtype=GRB.BINARY, name="x2")
          y2  = m.addVar(vtype=GRB.BINARY, name="y2")

      
      

          for t in range(288):
                for f in tof.keys():
                    m.addConstr(t >= x[f] - M * (1-s), 'BigM1-1')
                    m.addConstr(t <= x[f] + M * s, 'BigM1-2')
                   
                    m.addConstr(x[f] + 6 >= t - M * (1-h), 'BigM2-1')
                    m.addConstr(x[f] + 6 <= t + M * h, 'BigM2-2')
                    
                    m.addConstr(z[f] >= t - M * (1-h2), 'BigM3-1')
                    m.addConstr(z[f] <= t + M * h2, 'BigM3-2')
                    
            m.addGenConstrAnd(x2, [s,h], 'andConstr1')
            m.addGenConstrAnd(y2, [s,h2], 'andConstr2')

           
            t = 0
            for t in range(288):
                if x2 == 1:
                    m.addConstr(y.sum('*', '*') <= qk, 'c2')
                else:
                    t += 1
                
                if y2 == 1:
                    for p in fleetType:   
                        m.addConstr(y.sum('*', p) <= xp, 'c8')
                else:
                    t += 1

    However, the error still occurs: 

    Error code 0: Constraint has no bool value (are you trying "lb <= expr <= ub"?)

    Is there anything I didn't get?

    0
  • Jaromił Najman
    Gurobi Staff Gurobi Staff

    I guess it could be solved using the same method as the first if-clause?

    Yes, exactly.

    However, the error still occurs: 

    Error code 0: Constraint has no bool value (are you trying "lb <= expr <= ub"?)

    Is there anything I didn't get?

    As mentioned in my first message, it is not possible to use Var objects for comparisons. Thus, the \(\texttt{if}\)-clause \(\texttt{if x2 == 1}\) and \(\texttt{if y2 == 1}\) result in an error. You have to formulate these \(\texttt{if}\)-statements with the help of binary variables and (in)equality constraints. Luckily, in your case you can use Gurobi's indicator constraints to formulate your \(\texttt{if}\)-statements.

    What I don't understand is, why you loop over \(\texttt{t}\), when you have only exactly one variable \(\texttt{x2}\) and \(\texttt{y2}\).

    Best regards, 
    Jaromił

    0
  • Jingyue Zhang
    Gurobi-versary
    Collaborator
    Curious

    I got it. I need to set the variables differently so that it would go with the loop for t. Thanks for your time help!!!!

    0
  • Jingyue Zhang
    Gurobi-versary
    Collaborator
    Curious

    Hi Jaromił, 

    I've tried again using the code like this:

    try:
            m = Model()

            x = m.addVars(tof.keys(), lb = 0, ub= 287, vtype=GRB.CONTINUOUS, name='x')

            z = m.addVars(tdf.keys(), lb = 0, ub = 287, vtype=GRB.CONTINUOUS, name='z') 
            s  = m.addVars(288, vtype=GRB.BINARY, name="s")
            h  = m.addVars(288, vtype=GRB.BINARY, name="h")
            h2  = m.addVars(288, vtype=GRB.BINARY, name="h2")
            x2  = m.addVars(288, vtype=GRB.BINARY, name="x2")
            y2  = m.addVars(288, vtype=GRB.BINARY, name="y2")

            

            for t in range(288):
                for f in tof.keys():
                    m.addConstr(t >= x[f] - M * (1-s[t]), 'BigM1-1')
                    m.addConstr(t <= x[f] + M * s[t], 'BigM1-2')
                   
                    m.addConstr(x[f] + 6 >= t - M * (1-h[t]), 'BigM2-1')
                    m.addConstr(x[f] + 6 <= t + M * h[t], 'BigM2-2')
                    
                    m.addConstr(z[f] >= t - M * (1-h2[t]), 'BigM3-1')
                    m.addConstr(z[f] <= t + M * h2[t], 'BigM3-2')
           

            for t in range(288):       
                m.addGenConstrAnd(x2[t], [s[t],h[t]], 'andConstr1')
                m.addGenConstrAnd(y2[t], [s[t],h2[t]], 'andConstr2')

            for t in range(288):
                m.addGenConstrIndicator(x2[t], True, y.sum('*', '*') <= qk, 'c2')
                m.addGenConstrIndicator(y2[t], True, y.sum('*', p) <= xp, 'c8')

     

    However, the error: Error code 10003: Additional sense argument provided for general constraint of indicator type occurs.

    Perhaps by using the addGenConstrIndicator the x2[t] and y2[t] cannot be decision variables?

    In that way, I'm wondering how to form the code with the logics states that if the if x2[t] == 1(which is decided by the constraints 'andConstr1' and 'andConstr2') then the constraint must be satisfied.

    Thank you!

    Best regards,

    Jingyue

     

     

     

    0
  • Jaromił Najman
    Gurobi Staff Gurobi Staff

    Hi Jingyue,

    The addGenConstrIndicator method has the arguments \(\texttt{(binvar, binval, lhs, sense=None, rhs=None, name="" )}\). The \(\texttt{lhs}\) argument can be a float, Var, LinExpr, or a TempConstr object. If you provide a TempConstr object for the \(\texttt{lhs}\) argument, you won't provide the \(\texttt{sense}\) and \(\texttt{rhs}\) argument. In this case, you have to explicitly specify that you define the \(\texttt{name}\) argument.

    for t in range(288):
    m.addGenConstrIndicator(x2[t], True, y.sum('*', '*') <= qk, name='c2')
    m.addGenConstrIndicator(y2[t], True, y.sum('*', p) <= xp, name='c8')

    Best regards, 
    Jaromił

     

    0
  • Jingyue Zhang
    Gurobi-versary
    Collaborator
    Curious

    Hi Jaromił, 

    your advice is very helpful. I tried and the error disappears.

    Today I reviewed my code and discovers that the logic might be wrong.

    The logic I'm trying to express is:

    't' stands for discrete time, and there are 288 time windows. For any time t, if the big M constraints about decision variables x[f] and z[f] are satisfied (s,h,h2,x2,y2,z2 are the binary variables for any time t), then the andconstrs occurs, however now my code looks like that t is an integer and it's looping from 0 to 287.

    try:
            m = Model()
            print('building model')

            x = m.addVars(tof.keys(), lb = 0, ub= 287,

    vtype=GRB.CONTINUOUS, name='x')

            z = m.addVars(tdf.keys(), lb = 0, ub = 287, vtype=GRB.CONTINUOUS, name='z')

            s  = m.addVars(288, vtype=GRB.BINARY, name="s")

            h  = m.addVars(288, vtype=GRB.BINARY, name="h")
            h2  = m.addVars(288, vtype=GRB.BINARY, name="h2")

            x2  = m.addVars(288, vtype=GRB.BINARY, name="x2")
            y2  = m.addVars(288, vtype=GRB.BINARY, name="y2")

    for t in range(288):
                for f in tof.keys():
                    m.addConstr(t[f] >= x[f] - M * (1-s[t]), 'BigM1-1')
                    m.addConstr(t[f] <= x[f] + M * s[t], 'BigM1-2')
                   
                    m.addConstr(x[f] + 6 >= t[f] - M * (1-h[t]), 'BigM2-1')
                    m.addConstr(x[f] + 6 <= t[f] + M * h[t], 'BigM2-2')
                    
                    m.addConstr(z[f] >= t[f] - M * (1-h2[t]), 'BigM3-1')
                    m.addConstr(z[f] <= t[f] + M * h2[t], 'BigM3-2')
    for t in range(288):       
        m.addGenConstrAnd(x2[t], [s[t],h[t]], 'andConstr1')
        m.addGenConstrAnd(y2[t], [s[t],h2[t]], 'andConstr2')

    for t in range(288):
        m.addGenConstrIndicator(x2[t], True, y.sum('*', '*'), GRB.LESS_EQUAL, qk, 'c2')
        m.addGenConstrIndicator(y2[t], True, y.sum('*', p), GRB.LESS_EQUAL, xp, 'c8')

    I'm wondering is there any way to express the logic right?

    Thanks again for your help!!!!!

    Yours,

    Jingyue

    0
  • Jaromił Najman
    Gurobi Staff Gurobi Staff

    You would have to model a variable index as an optimization variable. This is possible but quite expensive. It is discussed in the Community post use a decision variable as an index.

    Best regards, 
    Jaromił

    0
  • Jingyue Zhang
    Gurobi-versary
    Collaborator
    Curious

    Hi Jaromił, 

    I think I almost got it from the post you shared. It expresses a way to index x[t] andy[t] for Andconstraints.

    However, I still quite not get how to express the bold part of "For any time t, if the big M constraints about decision variables x[f] and z[f] are satisfied (s,h,h2,x2,y2,z2 are the binary variables for any time t), then the andconstrs occurs".

    Sorry to bother you if my question is silly :)

    0
  • Jaromił Najman
    Gurobi Staff Gurobi Staff

    This is where it gets tricky. You would have to introduce 288 \(\times\) tof.keys() t variables and model the big-M constraints with the particular t[i, f]. Then, you can use t[i, f] as index in your andconstr.

    0
  • Jingyue Zhang
    Gurobi-versary
    Collaborator
    Curious

    Hi Jaromił,

    Thank you for your advice again. It's really helpful!!!!

    I defined the  t[i,f] and tried like this:

     for i in range(288):
            for f in flights:
                tindex[i,f] = 0

     try:
            m = Model()

            x = m.addVars(tof.keys(), lb = 0, ub= 287, vtype=GRB.CONTINUOUS, name='x')
            z = m.addVars(tdf.keys(), lb = 0, ub = 287, vtype=GRB.CONTINUOUS, name='z')  
            s  = m.addVars(288, vtype=GRB.BINARY, name="s")
            h  = m.addVars(288, vtype=GRB.BINARY, name="h")
            h2  = m.addVars(288, vtype=GRB.BINARY, name="h2")
            x2  = m.addVars(288, vtype=GRB.BINARY, name="x2")
            y2  = m.addVars(288, vtype=GRB.BINARY, name="y2")
            ui = m.addVars(288,vtype=GRB.BINARY, name = 'ui')
            t = m.addVars(tindex.keys(), vtype = GRB.BINARY, name = 't')
          

            m.addConstr(ui.sum('*') == 1, 'index2')
      
          
            for i in range(288):
                for f in tof.keys():
                
                    m.addConstr(i* ui[i] == t[i,f], 'index1')
                    
            
                    m.addConstr(t[i,f] >= x[f] - M * (1-s[f]), 'BigM1-1')
                    m.addConstr(t[i,f] <= x[f] + M * s[f], 'BigM1-2')
                   
                    m.addConstr(x[f] + 6 >= t[i,f] - M * (1-h[f]), 'BigM2-1')
                    m.addConstr(x[f] + 6 <= t[i,f] + M * h[f], 'BigM2-2')
                    
                    m.addConstr(z[f] >= t[i,f] - M * (1-h2[f]), 'BigM3-1')
                    m.addConstr(z[f] <= t[i,f] + M * h2[f], 'BigM3-2')
                      
                    m.addGenConstrAnd(x2[f], [s[f],h[f]], 'andConstr1')
                    m.addGenConstrAnd(y2[f], [s[f],h2[f]], 'andConstr2')

            for t in range(288):
                m.addGenConstrIndicator(x2[t], True, y.sum('*', '*'), GRB.LESS_EQUAL, qk, 'c2')
                m.addGenConstrIndicator(y2[t], True, y.sum('*', p), GRB.LESS_EQUAL, xp, 'c8')

    The error occurs:KeyError: '3848669'  

    '3848669' is the a key in tof.keys()

    Also, if I try with this constraint:

    for i in range(288):
                for f in tof.keys():
                    m.addConstr(sum(i* ui[i]) == t,sum('*',f), 'index1')
    "TypeError: 'gurobipy.LinExpr' object is not iterable" occurs.

    I'm confused and wondering where it went wrong.

    0
  • Jaromił Najman
    Gurobi Staff Gurobi Staff

    The error about not iterable object occurs because the \(\texttt{i* ui[i] }\) is a LinExpr object which is not an iterable object such as a list for example. If you want to sum over all indices \(\texttt{i}\), you should try

    for f in tof.keys():
    m.addConstr(quicksum(i* ui[i] for i in range(288)) == t.sum('*',f), 'index1')

    I don't know about the KeyError. It points to an "out-of-array" access. I guess that it is some mismatch between \(\texttt{flights}\) and \(\texttt{tof.keys()}\).

    Note that you defined \(\texttt{t}\) as optimization variables so you definitely should not use it in your \(\texttt{for}\)-loop.

    for i in range(288):
    m.addGenConstrIndicator(x2[i], True, y.sum('*', '*'), GRB.LESS_EQUAL, qk, 'c2')
    m.addGenConstrIndicator(y2[i], True, y.sum('*', p), GRB.LESS_EQUAL, xp, 'c8')

    Hope this helps.

    0
  • Jingyue Zhang
    Gurobi-versary
    Collaborator
    Curious

    Thank you very much!!!!

    I tried and it works!

    0

サインインしてコメントを残してください。