Skip to main content

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

Answered

Comments

15 comments

  • Official comment
    Simranjit Kaur
    • Gurobi Staff
    This post is more than three years old. Some information may not be up to date. For current information, please check the Gurobi Documentation or Knowledge Base. If you need more help, please create a new post in the community forum, or try Gurobot, our chatbot interface offering instant, expert-level support.
  • Jaromił Najman
    • 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

    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

    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

    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

    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

    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

Post is closed for comments.