Skip to main content

to solve an optimal solution for a time period

Answered

Comments

9 comments

  • Gurobot (AI-generated response)
    Gurobi Staff Gurobi Staff

    To solve this problem using Gurobi in Python, you need to formulate it as a linear optimization problem. Here's a general outline of how you might structure your model:

    1. Decision Variables:

      • x[t]: Amount of electricity stored at hour t.
      • buy[t]: Amount of electricity bought at hour t.
      • sell[t]: Amount of electricity sold at hour t.
      • delta_x[t]: Change in storage from hour t-1 to t.
    2. Objective Function:

      • Maximize the total profit over 5 hours. Profit at each hour is calculated as (sell price * amount sold) - (buy price * amount bought).
    3. Constraints:

      • Storage limits: 0 <= x[t] <= 8.
      • Change in storage limits: -5 <= delta_x[t] <= 5.
      • Storage update: x[t] = x[t-1] + delta_x[t] (for t > 0).
      • Transaction constraints: delta_x[t] = buy[t] - sell[t].
      • Non-negativity: buy[t] >= 0, sell[t] >= 0.

    Here's a basic example of how you might write this in Python using Gurobi:

    from gurobipy import Model, GRB

    # Define the data
    buy_prices = [2, 2, 5, 5, 2]
    sell_prices = [1, 1, 3, 3, 1]
    hours = range(5)

    # Create a new model
    m = Model("electricity_storage")

    # Create variables
    x = m.addVars(hours, vtype=GRB.CONTINUOUS, name="storage")
    buy = m.addVars(hours, vtype=GRB.CONTINUOUS, name="buy")
    sell = m.addVars(hours, vtype=GRB.CONTINUOUS, name="sell")
    delta_x = m.addVars(hours, vtype=GRB.CONTINUOUS, name="delta_x")

    # Set the objective
    m.setObjective(sum((sell_prices[t] * sell[t] - buy_prices[t] * buy[t]) for t in hours), GRB.MAXIMIZE)

    # Add constraints
    m.addConstrs((0 <= x[t] <= 8 for t in hours), "StorageLimits")
    m.addConstrs((-5 <= delta_x[t] <= 5 for t in hours), "DeltaLimits")
    m.addConstrs((x[t] == (x[t-1] + delta_x[t]) for t in hours if t > 0), "StorageUpdate")
    m.addConstrs((delta_x[t] == buy[t] - sell[t] for t in hours), "Transaction")

    # Solve the model
    m.optimize()

    # Print the results
    if m.status == GRB.OPTIMAL:
        for t in hours:
            print(f"Hour {t}: Δx = {delta_x[t].X}, Spend/Gain = {sell[t].X * sell_prices[t] - buy[t].X * buy_prices[t]}, Total Storage = {x[t].X}")

        print("Total Gain over 5 hours:", m.objVal)

    This code sets up and solves the problem as described. After running this model, you'll get the optimal delta_x at each moment, the spend or gain at each moment, and the total gain over 5 hours. Note that this is a simplified model and might need adjustments based on additional real-world considerations.

    0
  • 汉涛 田
    First Comment
    First Question

    thank you for your help. But the code met one error in constraints 2.“ gurobipy.GurobiError: Constraint has no bool value (are you trying "lb <= expr <= ub"?) ”

    0
  • Gurobot (AI-generated response)
    Gurobi Staff Gurobi Staff

    The error in the Python code arises from the use of the m.addConstrs method with a generator expression that includes a double inequality. In Gurobi, you cannot directly use the syntax 0 <= x[t] <= 8 within m.addConstrs as it does not translate to a valid linear constraint format recognized by Gurobi.

    To fix this, you should split the double inequality into two separate constraints for each variable t. Here's the corrected part of the code:

    # Add constraints
    m.addConstrs((x[t] >= 0 for t in hours), "StorageLowerLimits")
    m.addConstrs((x[t] <= 8 for t in hours), "StorageUpperLimits")
    m.addConstrs((delta_x[t] >= -5 for t in hours), "DeltaLowerLimits")
    m.addConstrs((delta_x[t] <= 5 for t in hours), "DeltaUpperLimits")

    The code ran successfully, and the model was solved optimally by Gurobi. However, the optimal objective value is 0, which might be unexpected. This could be due to the specific data and constraints in the model, which might not allow for any profitable transactions under the given conditions.

    Here are the results of the optimization:

    results = [
        {'Hour': 0, 'Delta_x': 0.0, 'Spend_Gain': 0.0, 'Total_Storage': 0.0},
        {'Hour': 1, 'Delta_x': 0.0, 'Spend_Gain': 0.0, 'Total_Storage': 0.0},
        {'Hour': 2, 'Delta_x': 0.0, 'Spend_Gain': 0.0, 'Total_Storage': 0.0},
        {'Hour': 3, 'Delta_x': 0.0, 'Spend_Gain': 0.0, 'Total_Storage': 0.0},
        {'Hour': 4, 'Delta_x': 0.0, 'Spend_Gain': 0.0, 'Total_Storage': 0.0}
    ]
    total_gain = 0.

    It seems that the model determined the best strategy was not to engage in any buying or selling transactions, as indicated by the zero values for Delta_x and Spend_Gain for each hour.

    You may want to review the data or the constraints to ensure they reflect the scenario you're trying to model. If you have specific goals or conditions you're trying to achieve, adjusting the model accordingly might yield more interesting results.

    0
  • 汉涛 田
    First Comment
    First Question

    Why would the result be 0? If I buy 5 at moment 0 and sell 5 at moment 2, then I can earn 3 * 5-2 * 5=5. Is it the result of a logical error in the code that caused the error

    0
  • Riley Clement
    Gurobi Staff Gurobi Staff

    Hi 汉涛 田 ,

    I think Gurobot has had a big week.  Gurobi 11.0.1 was just released and Gurobot was up late celebrating and has given some suboptimal advice.

    Note that variables have default lower bounds of zero, unless explicitly changed.  And indeed if the delta[x].lb values are not changed from the default then the result is an optimal solution where all variables are zero.

    Instead of trying to set variable bounds with constraints, it is better to do it at variable creation, with lb and ub properties.  So instead of this:

    # Add constraints
    m.addConstrs((x[t] >= 0 for t in hours), "StorageLowerLimits")
    m.addConstrs((x[t] <= 8 for t in hours), "StorageUpperLimits")
    m.addConstrs((delta_x[t] >= -5 for t in hours), "DeltaLowerLimits")
    m.addConstrs((delta_x[t] <= 5 for t in hours), "DeltaUpperLimits")

    do this:

    x = m.addVars(hours, ub=8, vtype=GRB.CONTINUOUS, name="storage") # default lb of 0
    delta_x = m.addVars(hours, lb=-5, ub=5, vtype=GRB.CONTINUOUS, name="delta_x")

    It's cleaner, and we don't end up with a default lower bound of 0 on the delta variables.

    Running the code with these changes gives you the following output:

    Optimal objective  2.900000000e+01
    Hour 0: Δx = -5.0, Spend/Gain = 5.0, Total Storage = 8.0
    Hour 1: Δx = 0.0, Spend/Gain = 0.0, Total Storage = 8.0
    Hour 2: Δx = -5.0, Spend/Gain = 15.0, Total Storage = 3.0
    Hour 3: Δx = -3.0, Spend/Gain = 9.0, Total Storage = 0.0
    Hour 4: Δx = 0.0, Spend/Gain = 0.0, Total Storage = 0.0
    Total Gain over 5 hours: 29.0

    - Riley

     

     

     

    0
  • 汉涛 田
    First Comment
    First Question

    Thank you for your reply, but I still feel some confusion.

    "X=m. addVars (hours, ub=8, vtype=GRB. CONTANUOUS, name=" storage ")" The upper limit of storage has been set to 8 in the formula,

    So how to explain "Hour 0: Δ In the result of "x=-5.0, Spend/Main=5.0, Total Storage=8.0", after the operation of -5, the storage is still 8?

    0
  • Riley Clement
    Gurobi Staff Gurobi Staff

    Ah well spotted.  I was celebrating with Gurobot too.  Let's look at the following constraint:

    m.addConstrs((x[t] == (x[t-1] + delta_x[t]) for t in hours if t > 0), "StorageUpdate")
    

    What about when t = 0?  The above constraint won't work because we would have x[-1] but we do need something for t = 0.  We can either add the following:

    m.addConstr(x[0] == delta_x[0], "StorageUpdate_0")
    

    or we replace the first set of constraints above with:

    m.addConstrs((x[t] == x.get(t-1,0) + delta_x[t] for t in hours), "StorageUpdate")

    where we use dict.get to return a default value of 0 if the key t-1 doesn't exist, and don't worry about restricting t > 0.

    - Riley

    0
  • 汉涛 田
    First Comment
    First Question

    thank you for your help. But I still met a problem.

    ⬇ ⬇ ⬇ 
    def gurobi(time, ESS):

    buy_prices = [0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.49, 0.49, 0.49, 0.83, 0.83, 0.83, 0.49, 0.49, 0.49, 0.49,
    0.49, 0.83, 0.83, 0.83, 0.49, 0.49, 0.27]
    sell_prices = [0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.38, 0.38, 0.38, 0.65, 0.65, 0.65, 0.38, 0.38, 0.38, 0.38,
    0.38, 0.65, 0.65, 0.65, 0.38, 0.38, 0.13]
    hours = range(time, 24)

    # Create a new model
    m = Model("electricity_storage")

    # Create variables
    x = m.addVars(hours, ub=500, vtype=GRB.CONTINUOUS, name="storage") # 储能容量
    buy = m.addVars(hours, vtype=GRB.CONTINUOUS, name="buy")
    sell = m.addVars(hours, vtype=GRB.CONTINUOUS, name="sell")
    delta_x = m.addVars(hours, lb=-50, ub=50, vtype=GRB.CONTINUOUS, name="delta_x")

    # Set the objective
    m.setObjective(sum((sell_prices[t] * sell[t] - buy_prices[t] * buy[t]) for t in hours), GRB.MAXIMIZE)

    # Add constraints
    m.addConstrs((delta_x[t] == buy[t] - sell[t] for t in hours), "Transaction")
    ⬇ ⬇ ⬇
    m.addConstrs((x[t] == x.get(t - 1, ESS) + delta_x[t] for t in hours), "StorageUpdate")


    # Solve the model
    m.optimize()

    # Print the results
    if m.status == GRB.OPTIMAL:
    print("Total Gain over 24 hours:", m.objVal)
    objective_value = m.objVal
    return objective_value
    for i in range(rounds):
    ESS = 0
    v_c = 0
    ⬇ ⬇ ⬇
    for j in range(24):
    s = np.zeros(state_dim)
    s[0] = j
    s[1] = ESS
    s[2] = buy_prices[j]
    s[3] = sell_prices[j]
    a=ddpg.choose_action(np.reshape(s, (1, state_dim)))
    P_ESS_delta = a * 50

    if ESS + P_ESS_delta < 0 or ESS + P_ESS_delta > 500:
    v_c = 1
    else:
    v_c = 0

    # 计算reward
    if v_c == 0:
    if j != 23:
              ⬇ ⬇ ⬇
    r_n = gurobi(j + 1, ESS+ P_ESS_delta[0][0] )
    else:
    if ESS + P_ESS_delta == 0:
    r_n = P_ESS_delta * sell_prices[j]
    else:
    r_n = 0
    if v_c == 1:
    r_n = 0

    #更新状态
    x_c[i][j][0] = ESS + P_ESS_delta
    x_c[i][j][1] = P_ESS_delta
    x_c[i][j][2] = r_n
    ESS = + P_ESS_delta
    s_=np.zeros(state_dim)

    s_[0]=j + 1
    s_[1]= ESS
    if j == 23:
    s_[2] = buy_prices[0]
    s_[3] = sell_prices[0]
    else:
    s_[2] = buy_prices[j + 1]
    s_[3] = sell_prices[j + 1]

    #存储
    memory=ddpg.store_transition(s, a, r_n, s_)

    if ddpg.pointer > MEMORY_CAPACITY:
    var *= 0.99995
    ddpg.learn()
    s=s_

    WARNING:tensorflow:Calling GradientTape.gradient on a persistent tape inside its context is significantly less efficient than calling it outside the context (it causes the gradient ops to be recorded on the tape, leading to increased CPU and memory usage). Only call GradientTape.gradient inside the context if you actually want to trace the gradient in order to compute higher order derivatives.
    D:\Pycharm\EHGmaddpg\venv\lib\site-packages\keras\engine\training.py:2470: UserWarning: `Model.state_updates` will be removed in a future version. This property should not be used in TensorFlow 2.0, as `updates` are applied automatically.
      warnings.warn('`Model.state_updates` will be removed in a future version. '
    Using license file C:\Users\TianHanTao\gurobi.lic
    Gurobi Optimizer version 9.1.2 build v9.1.2rc0 (win64)
    Thread count: 10 physical cores, 16 logical processors, using up to 16 threads
    Optimize a model with 46 rows, 92 columns and 137 nonzeros
    Model fingerprint: 0x788dadeb
    Coefficient statistics:
      Matrix range     [1e+00, 1e+00]
      Objective range  [1e-01, 8e-01]
      Bounds range     [5e+01, 5e+02]
      RHS range        [3e+00, 3e+00]
    Presolve removed 1 rows and 1 columns
    Presolve time: 0.00s
    Presolved: 45 rows, 91 columns, 135 nonzeros

    Iteration    Objective       Primal Inf.    Dual Inf.      Time
           0    6.8880000e+31   4.600000e+31   6.888000e+01      0s
          63    1.1497383e+02   0.000000e+00   0.000000e+00      0s

    Solved in 63 iterations and 0.00 seconds
    Optimal objective  1.149738281e+02
    Total Gain over 24 hours: 114.97382809638977
    Traceback (most recent call last):
      File "D:\Pycharm\EHGmaddpg\ECD-DDPG-6G.py", line 202, in <module>
        r_n = gurobi(j + 1, ESS+ P_ESS_delta[0][0] )
      File "D:\Pycharm\EHGmaddpg\ECD-DDPG-6G.py", line 42, in gurobi
        m.addConstrs((x[t] == x.get(t - 1, ESS) + delta_x[t] for t in hours), "StorageUpdate")
      File "src\gurobipy\model.pxi", line 3473, in gurobipy.Model.addConstrs
      File "src\gurobipy\model.pxi", line 3359, in gurobipy.Model.addConstr
      File "src\gurobipy\linexpr.pxi", line 471, in gurobipy.LinExpr.__sub__
      File "src\gurobipy\linexpr.pxi", line 450, in gurobipy.LinExpr.__add__
      File "src\gurobipy\linexpr.pxi", line 183, in gurobipy.LinExpr.add
    gurobipy.GurobiError: Unsupported type (<class 'numpy.ndarray'>) for LinExpr addition argument

     

    0
  • Riley Clement
    Gurobi Staff Gurobi Staff

    What is the value of ESS when you receive this error?  Use a try/except block to find out.  My guess from the error message is that it is a numpy array.

    - Riley

    0

Please sign in to leave a comment.