Skip to main content

Using a for loop for a single or specific value in variable list in constraint formulation

Answered

Comments

209 comments

  • Margi Shah
    Gurobi-versary
    Thought Leader
    Curious

    Hi Jaromil,

    I have two questions:

    1.

    x={}
    for t in time1:
        x[t]=price_energy[t-1]*EnergyResource[174,t].X 

    I have tried to store the value of x as a list. This is Obj value at different time steps? Am I correctly understanding?

    2.

    y={}
    for t in time1:
        y[t]=EnergyResource[174,t].X 

    y is the values of Energy Resource variable at different time steps ? Is it correct?

     

    Can I have both these parameters (Model Attribute) & ( Variable attribute) stored as a list?

     

     

    0
  • Jaromił Najman
    Gurobi Staff Gurobi Staff

    Hi Margi,

    1.

    x={}
    for t in time1:
        x[t]=price_energy[t-1]*EnergyResource[174,t].X 

    I have tried to store the value of x as a list. This is Obj value at different time steps? Am I correctly understanding?

    Your objective is defined as \(sum_t^{\text{time1}} \sum_{res}^{\text{reslist1}} \text{priceenergy}_{t-1} \cdot \text{EnergyResouce}_{res,t}\) so the \(x\) you compute is only a part of your objective function, namely \(sum_t^{\text{time1}} \text{priceenergy}_{t-1} \cdot \text{EnergyResource}_{174,t}\). So you sum all time steps over \(res=174\). If this is what you want and understand by "Obj value at different time steps" then yes, you understand correctly.

    2.

    y={}
    for t in time1:
        y[t]=EnergyResource[174,t].X 

    y is the values of Energy Resource variable at different time steps ? Is it correct?

    \(y\) holds values of the EnergyResource variable for \(res=174\) at different time steps.

    Can I have both these parameters (Model Attribute) & ( Variable attribute) stored as a list?

    Which parameters do you mean? The \(x,y\) you construct? You can just use a list instead of a dictionary

    x=[]
    for t in time1:
      x.append(price_energy[t-1]*EnergyResource[174,t].X)
    y=[]
    for t in time1:
      y.append(EnergyResource[174,t].X)

    But note that lists start with index \(0\) and your time1 list starts with \(1\) so I would think that using dictionaries might be more convenient here.

    If you mean to get all X attribute values as a list, then yes, this is possible via the Model.getAttr() method. However, you will have to provide the variables as a list to get a list out of this method, which would require an additional step in your current implementation. So it may be better to stick to your current approach.

    0
  • Margi Shah
    Gurobi-versary
    Thought Leader
    Curious

    Hi Jaromił Najman,

    Many thanks for replying to the question. I think I have understood what model attributes are.

    Firstly, I am as of now not putting any query, but this post is for the appreciation for the employees like you who are dedicated.

    For people like me, who used Gurobi for the very first time, you helped a lot to make this start smooth. I know its lot and lot to learn further but you made sure it was smooth start.

    Thanks a lot, Jaromil. I really appreciate it.

    Looking forward to more learning.

     

     

    0
  • Margi Shah
    Gurobi-versary
    Thought Leader
    Curious

    Hi Jaromił Najman,

    Is there a way to access the number of binary and continuous variables present in the model? I am aware of how I can access the constraints, like below:

    x=steel.NumConstrs

    I am not sure how to retrieve the binary and continuous variables. 

     

    Regards,

    Margi

     

    0
  • Jaromił Najman
    Gurobi Staff Gurobi Staff

    Hi Margi,

    For the total number of variables, you can access the NumVars attribute of the model object. There are also attributes for the number of binary variables (NumBinVars) and the number of integer variables (NumIntVars). To get the number of continuous variables, you can simply subtract the number of binary and integer variables from the number of all variables.

    numbinvars  = steel.NumBinVars # number of binary vars
    numintvars = steel.NumIntVars # number of integer vars
    numcontvars = steel.NumVars - numbinvars - numintvars # number of continuous vars

    Best regards, 
    Jaromił

    0
  • Margi Shah
    Gurobi-versary
    Thought Leader
    Curious

    Thanks Jaromił Najman :)

    0
  • Margi Shah
    Gurobi-versary
    Thought Leader
    Curious

    Hi Jaromił Najman,

    As per your last comment,

    I tried to check the number of constraints and variables:

    numconstraints = steel.NumConstrs # number of constraints
    print(numconstraints)
    numbinvars = steel.NumBinVars # number of binary vars
    print(numbinvars)
    numintvars = steel.NumIntVars # number of integer vars
    print(numintvars)
    numcontvars = steel.NumVars - numbinvars - numintvars # number of continuous vars
    print(numcontvars)

    Output seems to be:

    16800
    11520
    23451
    -11232

    How does number of continous varibales has negative sign?


    Thanks in advance.

    0
  • Jaromił Najman
    Gurobi Staff Gurobi Staff

    Hi Margi,

    I just noticed that the parameter for number of integer variables (NumIntVars) counts both binaries and integers. Thus the correct call should be

    numintvars = steel.NumIntVars  # number of integer and binary vars
    print(numintvars)
    numcontvars = steel.NumVars - numintvars  # number of continuous vars
    print(numcontvars)

    Sorry for the confusion.

    Best regards, 
    Jaromił

    0
  • Margi Shah
    Gurobi-versary
    Thought Leader
    Curious

    Hi Jaromił Najman,

    Thanks for your comment.

    I was solving a MILP problem and I see the message below.Does that interpret there is a error in the model?


    Set parameter Username
    Academic license - for non-commercial use only - expires 2025-01-09
    Gurobi Optimizer version 11.0.0 build v11.0.0rc2 (win64 - Windows 11.0 (22621.2))

    CPU model: 12th Gen Intel(R) Core(TM) i7-12700, instruction set [SSE2|AVX|AVX2]
    Thread count: 12 physical cores, 20 logical processors, using up to 20 threads

    Optimize a model with 98592 rows, 140211 columns and 779575 nonzeros
    Model fingerprint: 0x9f0c9bc7
    Model has 288 general constraints
    Variable types: 864 continuous, 139347 integer (69120 binary)
    Coefficient statistics:
      Matrix range     [2e-01, 7e+00]
      Objective range  [3e+01, 9e+01]
      Bounds range     [1e+00, 2e+00]
      RHS range        [1e+00, 5e+01]
    Presolve removed 71679 rows and 74765 columns
    Presolve time: 2.07s
    Presolved: 26913 rows, 65446 columns, 510584 nonzeros
    Variable types: 0 continuous, 65446 integer (38980 binary)
    Deterministic concurrent LP optimizer: primal simplex, dual simplex, and barrier
    Showing barrier log only...

    Root barrier log...

    Ordering time: 0.19s

    Barrier statistics:
     AA' NZ     : 6.963e+05
     Factor NZ  : 2.780e+06 (roughly 60 MB of memory)
     Factor Ops : 8.332e+08 (less than 1 second per iteration)
     Threads    : 9

                      Objective                Residual
    Iter       Primal          Dual         Primal    Dual     Compl     Time
       0   1.60606716e+09 -8.85134680e+08  5.90e+05 0.00e+00  8.56e+05     3s
       1   4.83313425e+08 -5.08655091e+08  1.76e+05 1.48e+02  2.59e+05     3s
       2   3.47612326e+07 -1.84927426e+08  1.17e+04 6.54e-11  1.84e+04     3s
       3   9.72483914e+06 -8.58172782e+07  2.86e+03 5.97e-11  4.68e+03     3s
       4   9.00611709e+06 -7.77744736e+07  2.60e+03 6.63e-11  4.21e+03     3s
       5   7.36512578e+06 -6.69103310e+07  2.02e+03 1.25e-10  3.31e+03     3s
       6   1.95451399e+06 -4.26878556e+07  4.05e+02 8.25e-11  8.48e+02     3s
       7   6.94822602e+05 -8.91461349e+06  1.27e+02 7.12e-11  2.07e+02     3s
       8   2.53059121e+05 -4.37385742e+06  3.37e+01 7.60e-11  6.81e+01     3s
       9   1.58572834e+05 -2.44412900e+06  1.34e+01 6.35e-11  3.16e+01     3s
      10   1.52436112e+05 -1.62277799e+06  1.18e+01 8.21e-11  2.27e+01     3s
      11   1.30677778e+05 -1.18385144e+06  7.06e+00 9.08e-11  1.51e+01     3s
      12   1.15300570e+05 -6.12351449e+05  3.59e+00 7.54e-11  7.61e+00     3s
      13   1.05989192e+05 -4.14634307e+05  1.92e+00 5.50e-11  4.93e+00     3s
      14   9.96725987e+04 -2.48795783e+05  9.64e-01 6.44e-11  3.06e+00     3s
      15   9.84988138e+04 -1.79386295e+05  7.93e-01 7.10e-11  2.40e+00     3s
      16   9.66247872e+04 -1.28162154e+05  6.39e-01 7.40e-11  1.92e+00     3s
      17   9.39721606e+04 -6.15255350e+04  3.34e-01 6.24e-11  1.27e+00     3s
      18   9.20959060e+04 -4.43444144e+04  1.82e-01 5.38e-11  1.08e+00     3s
      19   8.98493310e+04 -2.29414822e+03  1.10e-01 5.94e-11  7.22e-01     3s
      20   8.87635839e+04  1.95183360e+04  7.93e-02 5.29e-11  5.39e-01     3s
      21   8.84540516e+04  2.39727220e+04  7.05e-02 5.26e-11  5.01e-01     3s
      22   8.78120292e+04  4.53174903e+04  5.56e-02 4.53e-11  3.30e-01     3s
      23   8.75156453e+04  5.68868708e+04  4.77e-02 3.37e-11  2.38e-01     3s
      24   8.69889024e+04  6.25361992e+04  3.75e-02 4.61e-11  1.89e-01     3s
      25   8.66943307e+04  6.99545536e+04  3.16e-02 4.44e-11  1.30e-01     4s
      26   8.62448626e+04  7.39449906e+04  2.05e-02 2.87e-11  9.48e-02     4s
      27   8.58815436e+04  7.57373976e+04  1.32e-02 3.12e-11  7.80e-02     4s
      28   8.57064836e+04  7.97025751e+04  1.02e-02 3.01e-11  4.62e-02     4s
      29   8.55075443e+04  8.15352363e+04  7.77e-03 3.55e-11  3.06e-02     4s
      30   8.53856830e+04  8.21181821e+04  6.52e-03 4.04e-11  2.51e-02     4s
      31   8.52500771e+04  8.29536725e+04  5.15e-03 3.97e-11  1.77e-02     4s
      32   8.51119472e+04  8.33196743e+04  3.75e-03 2.84e-11  1.38e-02     4s
      33   8.50243785e+04  8.35818785e+04  2.95e-03 3.32e-11  1.11e-02     4s
      34   8.49431437e+04  8.37695504e+04  2.28e-03 4.23e-11  9.02e-03     4s
      35   8.49002525e+04  8.39717067e+04  1.91e-03 4.39e-11  7.14e-03     4s
      36   8.48346445e+04  8.41384990e+04  1.42e-03 4.50e-11  5.35e-03     4s
      37   8.48016230e+04  8.41903466e+04  1.19e-03 4.64e-11  4.70e-03     4s
      38   8.47792862e+04  8.42126092e+04  1.03e-03 5.97e-11  4.35e-03     4s
      39   8.47418146e+04  8.43274396e+04  7.75e-04 5.23e-11  3.18e-03     4s
      40   8.47264439e+04  8.43616733e+04  6.79e-04 6.03e-11  2.80e-03     4s
      41   8.46929448e+04  8.44339802e+04  4.75e-04 4.18e-11  1.99e-03     4s
      42   8.46724001e+04  8.44743653e+04  3.65e-04 5.06e-11  1.52e-03     4s
      43   8.46620288e+04  8.45018676e+04  3.10e-04 5.42e-11  1.23e-03     4s
      44   8.46538245e+04  8.45187973e+04  2.69e-04 6.00e-11  1.04e-03     4s
      45   8.46336794e+04  8.45375778e+04  1.67e-04 5.18e-11  7.38e-04     4s
      46   8.46295046e+04  8.45486523e+04  1.48e-04 5.33e-11  6.21e-04     4s
      47   8.46190101e+04  8.45601962e+04  1.03e-04 5.18e-11  4.52e-04     4s
      48   8.46096688e+04  8.45689460e+04  6.47e-05 5.31e-11  3.13e-04     4s
      49   8.46040765e+04  8.45760993e+04  4.24e-05 4.72e-11  2.15e-04     4s
      50   8.46002605e+04  8.45820584e+04  2.79e-05 4.94e-11  1.40e-04     4s
      51   8.45977328e+04  8.45860607e+04  1.86e-05 4.79e-11  8.97e-05     4s
      52   8.45961081e+04  8.45874891e+04  1.29e-05 4.50e-11  6.62e-05     4s
      53   8.45952727e+04  8.45885442e+04  9.98e-06 5.13e-11  5.17e-05     4s
      54   8.45943504e+04  8.45894339e+04  6.80e-06 5.45e-11  3.78e-05     4s
      55   8.45936911e+04  8.45902599e+04  4.58e-06 8.70e-11  2.63e-05     4s
      56   8.45931330e+04  8.45909608e+04  2.74e-06 8.21e-11  1.67e-05     5s
      57   8.45929633e+04  8.45915183e+04  2.19e-06 9.69e-11  1.11e-05     5s
      58   8.45926389e+04  8.45917617e+04  1.20e-06 1.14e-10  6.74e-06     5s
      59   8.45925912e+04  8.45918048e+04  1.06e-06 1.22e-10  6.04e-06     5s
      60   8.45924333e+04  8.45919327e+04  5.87e-07 8.39e-11  3.84e-06     5s
      61   8.45923244e+04  8.45920622e+04  2.77e-07 9.04e-11  2.01e-06     5s
      62   8.45922846e+04  8.45921580e+04  1.73e-07 6.01e-11  9.74e-07     5s
      63   8.45922578e+04  8.45921825e+04  1.02e-07 7.30e-11  5.80e-07     5s
      64   8.45922307e+04  8.45921903e+04  2.85e-08 8.42e-11  3.09e-07     5s
      65   8.45922227e+04  8.45922089e+04  8.83e-09 5.97e-11  1.06e-07     5s
      66   8.45922196e+04  8.45922166e+04  2.69e-09 5.73e-11  2.33e-08     5s
      67   8.45922189e+04  8.45922173e+04  1.47e-09 7.64e-11  1.26e-08     5s
      68   8.45922186e+04  8.45922177e+04  1.79e-09 8.47e-11  6.99e-09     5s
      69   8.45922151e+04  8.45922181e+04  5.24e-08 6.55e-11  2.45e-09     5s

    Barrier solved model in 69 iterations and 4.91 seconds (9.10 work units)
    Optimal objective 8.45922151e+04


    Root crossover log...

           0 DPushes remaining with DInf 0.0000000e+00                 5s

        5483 PPushes remaining with PInf 1.3603881e-03                 5s
           0 PPushes remaining with PInf 0.0000000e+00                 5s

      Push phase complete: Pinf 0.0000000e+00, Dinf 5.2146768e-02      5s


    Root simplex log...

    Iteration    Objective       Primal Inf.    Dual Inf.      Time
       24179    8.4592218e+04   0.000000e+00   5.214676e-02      5s
       24185    8.4592218e+04   0.000000e+00   0.000000e+00      5s
    Concurrent spin time: 0.00s

    Solved with barrier
       24185    8.4592218e+04   0.000000e+00   0.000000e+00      5s

    Root relaxation: objective 8.459222e+04, 24185 iterations, 3.12 seconds (4.90 work units)
    Total elapsed time = 12.11s (DegenMoves)
    Total elapsed time = 16.96s (DegenMoves)

        Nodes    |    Current Node    |     Objective Bounds      |     Work
     Expl Unexpl |  Obj  Depth IntInf | Incumbent    BestBd   Gap | It/Node Time

       0     0 84592.2184    0 3879          - 84592.2184      -     -   20s...........
    .
    .
    .
    .
    .
    . .......continues

    I haven't seen such a message previously. 

    Regards,
    Margi

     

    0
  • Jaromił Najman
    Gurobi Staff Gurobi Staff

    Hi Margi,

    I haven't seen such a message previously.

    Could you please explain which message exactly did you not see previously?

    What you currently posted is the normal output for models with discrete variables, see MIP Logging.

    Best regards, 
    Jaromił

    0
  • Margi Shah
    Gurobi-versary
    Thought Leader
    Curious

    Hi Jaromił Najman,

    I am trying to reformulate the optimisation problem. 

    Objective function:

    for res in res_list4:
        for t in time1:
             # add constr aux = EnergyResouce - E
          steel.addConstr(aux[res,t] == EnergyResource[res,t] + BatteryPower - E_Wind[t-1],name="aux_constr_%s_%d"%(res,t))
            # add constr maxaux = max(0, aux)
            steel.addGenConstrMax(maxaux[res,t],[aux[res,t]],0.0,name="maxconstr_%s_%d"%(res,t))        

    obj=gp.quicksum(price_energy[t-1]*maxaux[res,t] for res in res_list4 for t in time1)

    My question is how do I write the below constraint and define variable:

    Constraint:

    SoC calculation:

    if t == 1:
    SoC = initial_SoC(at t=0) + (BatteryPower * ch_eff) / e_b_cap
    else:
       SoC = SoC + (BatteryPower * ch_eff) / e_b_cap

    The variable BatteryPower can be any number between [-3,-2,-1,0,1,2,3].

    My question is, how do I write the variable and the constraint with regards to SoC calculation?

    Regards,
    Margi


     

    0
  • Jaromił Najman
    Gurobi Staff Gurobi Staff

    Hi Margi,

    You will need to introduce a bounded continuous \(\texttt{SoC_t}\) variable.

    # introduce variable SoC for every timestep t
    SoC = steel.addVars(time1, lb= SoC_MIN, ub = SoC_MAX, name="SoC")

    Next, you can add linear constraints by looping over the time index

    for t in time1:
    if t == 1:
    steel.addConstr(SoC[t] == inital_SoC(0) + (BatteryPower * ch_eff) / e_b_cap
    else:
       steel.addConstr(SoC[t] == (BatteryPower * ch_eff) / e_b_cap

    In the above I assumed that \(\texttt{intial_SoC}\) is some constant value that you can calculate.

    Best regards, 
    Jaromił

    0
  • Margi Shah
    Gurobi-versary
    Thought Leader
    Curious

    Hi Jaromił Najman,

    Actually the variable is the BatteryPower and SoC is calculated from it. 

    SoC calculation:

    if t == 1:
        SoC = initial_SoC(at t=0) + (BatteryPower * ch_eff) / e_b_cap
    else:
        SoC = SoC(t-1) + (BatteryPower * ch_eff) / e_b_cap
    0
  • Jaromił Najman
    Gurobi Staff Gurobi Staff

    Hi Margi,

    Actually the variable is the BatteryPower and SoC is calculated from it. 

    This is correct, but if you want to compute SoC being dependent on an optimization variable, then SoC has to become an optimization variable itself. Otherwise, it cannot be modeled.

    Best regards, 
    Jaromił

    0
  • Margi Shah
    Gurobi-versary
    Thought Leader
    Curious

    Hi Jaromił Najman,

    Thats correct. I understand but then how it is possible to calculate BatteryPower necessary for the objective function?

     

    Regards,
    Margi

    0
  • Jaromił Najman
    Gurobi Staff Gurobi Staff

    Thats correct. I understand but then how it is possible to calculate BatteryPower necessary for the objective function?

    BatteryPower is an optimization variable itself. This means that you can use it in the objective function and the solver will compute an optimal value for it.

    0
  • Margi Shah
    Gurobi-versary
    Thought Leader
    Curious

    Hi Jaromił Najman,

    Does that mean If I define SoC as a variable, I don't require to define BatteryPower as a variable?

    0
  • Jaromił Najman
    Gurobi Staff Gurobi Staff

    Hi Margi,

    Does that mean If I define SoC as a variable, I don't require to define BatteryPower as a variable?

    No, you still need to keep BatteryPower as a variable, because as you said it can take different values that need to be determined by the solver.

    0
  • Margi Shah
    Gurobi-versary
    Thought Leader
    Curious

    Hi Jaromił Najman,

    Alright, That means I will need to define batterypower like below:

    # introduce variable BatteryPower for every timestep t
    BatteryPower = steel.addVars(time1, lb= -3, ub = 3, name="BatteryPower")

    But how to make sure that it will take discrete values like -3,-2,-1,0,1,2,3?

    Regards,
    Margi

    0
  • Margi Shah
    Gurobi-versary
    Thought Leader
    Curious

    Hi Jaromił Najman,

    Also I am not sure why I am getting this error:

    initial_SoC = 0.5 


    Regards,
    Margi

    0
  • Jaromił Najman
    Gurobi Staff Gurobi Staff

    How do you define the optimization variable BatteryPower? Is it only one variable?

    0
  • Margi Shah
    Gurobi-versary
    Thought Leader
    Curious

    Hi Jaromił Najman,

    This is how I define BatteryPower:

    What do you mean by 'is it only one variable?'

    # introduce variable BatteryPower for every timestep t
    BatteryPower = steel.addVars(time1, lb= -3, ub = 3, name="BatteryPower")
    0
  • Jaromił Najman
    Gurobi Staff Gurobi Staff

    You define BatterPower via the addVars method. This means that the object BatterPower does not hold a single variable, but a tupledict of variables. Did you mean to access \(\texttt{BatteryPower[t]}\)?

    0
  • Margi Shah
    Gurobi-versary
    Thought Leader
    Curious

    Hi Jaromił Najman,

    Yes correct, I want to access BatteryPower[t].

    It can take any discrete value from [-3,-2,-1,0,1,2,3].
    How do I write it as variable?

    0
  • Jaromił Najman
    Gurobi Staff Gurobi Staff

    How do I write it as variable?

    You already added it as a tupledict of variables by the code

    BatteryPower = steel.addVars(time1, lb= -3, ub = 3, name="BatteryPower")

    You now just have to access it via \(\texttt{BatteryPower[t]}\) just as you do with SoC and other variables in your model.

    0
  • Margi Shah
    Gurobi-versary
    Thought Leader
    Curious
    Hi Jaromił Najman,

    Thank you for the response.

    I ran the optimisation model and when I saw the Battery power, I can see that it is continous variable rather than a discrete variable. 
    Why so ?



    BatteryPower[88] -2.7939182097697230e+00
    BatteryPower[89] -6.5532541123029220e-01
    BatteryPower[90] 1.0434642353333383e+00
    BatteryPower[91] 7.6636275700000844e-01
    BatteryPower[92] 1.2850982193333333e+00
    BatteryPower[93] 2.475373096



    I have defined BatteryPower as:
    BatteryPower = steel.addVars(time1, lb= -3, ub = 3, name="BatteryPower")

     

     

    0
  • Jaromił Najman
    Gurobi Staff Gurobi Staff

    You have to set the variable's vtype to be integer, see the documentation of addVars.

    BatteryPower = steel.addVars(time1, lb= -3, ub = 3, vtype=gp.GRB.INTEGER, name="BatteryPower")
    0
  • Margi Shah
    Gurobi-versary
    Thought Leader
    Curious

    Hi Jaromił Najman Najman,When I am trying to replace '<=' sign in the below constraint to '<', it shows me this error, why gurobi don't accept '<' sign?

    res = res_cat2idx['SP'][0]
    Spinningusage = {}

    for ti in time1:
        sumexpression = gp.LinExpr(0)
        for task_cat, task_list1 in tasks.items():
            if task_cat == 'EAF':
                if 'TR' in task_cat:  # transportation has no energy consumption
                    continue
                for task in task_list1:
                    duration = task_duration[task]
                    for theta in range(0, min(duration, ti)):
                        sumexpression.add(rtn_profile[res][task][theta] * Tasks[task, ti - theta])
              Spinningusage[res, ti] = steel.addConstr(SpinningResource[res, ti] <= sumexpression,name="Spinningusage[%s,%d]" % (res, ti))


    Error:

    0
  • Jaromił Najman
    Gurobi Staff Gurobi Staff

    Hi Margi and Happy New Year,

    This issue is explained in the Knowledge Base article Why doesn't Gurobi support strict inequality constraints like x < a?

    Best regards, 
    Jaromił

     

    0

Please sign in to leave a comment.