Added 21/07/2025
Energy
electricity_market_competitive
Dimension
{
"x": 25,
"y": 336,
"F": 1,
"G": 72,
"H": 0,
"f": 1,
"g": 511,
"h": 0
}
Solution
{
"optimality": "infeasible",
"x": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
"y": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
"F": 0,
"G": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],
"H": [],
"f": 0,
"g": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-0.83957481,-0.83957481,-0.83957481,-0.83957481,-0.83957481,-0.83957481,-0.83957481,-0.83957481,-0.83957481,-0.83957481,-0.83957481,-0.83957481,-0.83957481,-0.83957481,-0.83957481,-0.83957481,-0.83957481,-0.83957481,-0.83957481,-0.83957481,-0.83957481,-0.83957481,-0.83957481,-0.83957481,-0.12789266,-0.12789266,-0.12789266,-0.12789266,-0.12789266,-0.12789266,-0.12789266,-0.12789266,-0.12789266,-0.12789266,-0.12789266,-0.12789266,-0.12789266,-0.12789266,-0.12789266,-0.12789266,-0.12789266,-0.12789266,-0.12789266,-0.12789266,-0.12789266,-0.12789266,-0.12789266,-0.12789266,-0.05675748,-0.05675748,-0.05675748,-0.05675748,-0.05675748,-0.05675748,-0.05675748,-0.05675748,-0.05675748,-0.05675748,-0.05675748,-0.05675748,-0.05675748,-0.05675748,-0.05675748,-0.05675748,-0.05675748,-0.05675748,-0.05675748,-0.05675748,-0.05675748,-0.05675748,-0.05675748,-0.05675748,-0.56538305,-0.56538305,-0.56538305,-0.56538305,-0.56538305,-0.56538305,-0.56538305,-0.56538305,-0.56538305,-0.56538305,-0.56538305,-0.56538305,-0.56538305,-0.56538305,-0.56538305,-0.56538305,-0.56538305,-0.56538305,-0.56538305,-0.56538305,-0.56538305,-0.56538305,-0.56538305,-0.56538305,-0.21498955,-0.21498955,-0.21498955,-0.21498955,-0.21498955,-0.21498955,-0.21498955,-0.21498955,-0.21498955,-0.21498955,-0.21498955,-0.21498955,-0.21498955,-0.21498955,-0.21498955,-0.21498955,-0.21498955,-0.21498955,-0.21498955,-0.21498955,-0.21498955,-0.21498955,-0.21498955,-0.21498955,-0.31554488,-0.31554488,-0.31554488,-0.31554488,-0.31554488,-0.31554488,-0.31554488,-0.31554488,-0.31554488,-0.31554488,-0.31554488,-0.31554488,-0.31554488,-0.31554488,-0.31554488,-0.31554488,-0.31554488,-0.31554488,-0.31554488,-0.31554488,-0.31554488,-0.31554488,-0.31554488,-0.31554488,-0.70820833,-0.70820833,-0.70820833,-0.70820833,-0.70820833,-0.70820833,-0.70820833,-0.70820833,-0.70820833,-0.70820833,-0.70820833,-0.70820833,-0.70820833,-0.70820833,-0.70820833,-0.70820833,-0.70820833,-0.70820833,-0.70820833,-0.70820833,-0.70820833,-0.70820833,-0.70820833,-0.70820833,0.87536857,0.87329652,0.52418612,0.70880937,0.58396042,0.42134981,0.13151717],
"h": []
}
\subsection{electricity\_market\_competitive}
\label{subsec:electricity_market_competitive}
% Description
We present the extension to the monopolistic model as proposed in \cite{electricity} by introducing a second supplier who is a competitor to the original. Appliances can now be supplied by either the original supplier, its competitor, or both. We model from the perspective of the original supplier, i.e. the competitor's prices $\bar p^h, \, h \in H$ are fixed and the upper-level variable remains as the prices of the original supplier $p^h, \, h \in H$. We introduce a second set of lower-level variables, $\bar x_{n,a}^h$ as the power purchased from the competitor. The bilevel program of the competitive electricity market is then given as
% Equation
\begin{flalign*}
\maximise_{p, \Gamma} \quad
& \sum_{n \in N} \sum_{a \in A_n} \sum_{h \in H} p^h x^h_{n,a} - \kappa \Gamma \\
\subjectto \quad
& \Gamma \geq \sum_{n \in N, a \in A_n} x^h_{n,a} \quad \forall h \in H \\
& 0 \leq p^h \leq p^h_{\text{max}} \quad \forall h \in H \\
& x \in \argmin_{y}
\left\{
\begin{array}{l}
\sum_{n \in N} \sum_{a \in A_n} \sum_{h \in H} \left ( p^h + C_{n,a}(h) \right ) x^h_{n,a} + \\ \quad \quad \sum_{n \in N} \sum_{a \in A_n} \sum_{h \in H} \left ( \bar p^h + C_{n,a}(h) \right ) \bar x^h_{n,a} \\
\text{s.t.} \quad x^h_{n,a} + \bar x^h_{n,a} \leq \beta^{\text{max}}_{n,a}, \quad \forall \, n \in N, a \in A_n, h \in H \\
\sum_{h \in H} x^h_{n,a} + \bar x^h_{n,a} \geq E_{n,a}, \quad \forall \, n \in N, a \in A_n
\end{array}
\right.
\end{flalign*}
classdef electricity_market_competitive
%{
Comming soon
%}
properties(Constant)
name = 'electricity_market_competitive';
category = 'energy';
subcategory = '';
end
end
import numpy as np
import json
import os
"""
Sezin Af¸sar, Luce Brotcorne, Patrice Marcotte, and Gilles Savard.
"Achieving an optimal trade-off between revenue and energy peak within a smart grid environment."
Renewable Energy, 91:293–301, 2016.
"""
# Properties
name: str = "electricity_market_competitive"
category: str = "energy"
subcategory: str = ""
datasets: list = ["electricity_data_toy_ex.json"]
paths: list = [os.path.join("bolib3", "data", "electricity_data_toy_ex.json")]
kappa = 0.1
p_max = np.ones(24)
# Methods
def F(x, y, data):
"""
Upper-level objective function
"""
hours = data["H"]
N = data["N"]
A = data["A"]
p, gamma = x[:hours], x[-1]
pl = []
for n in range(N):
pl.append(y[n*(A[n]*hours): (n + 1)*(A[n]*hours)].reshape(A[n], hours))
return sum([p[h]*pl[n][a, h] for n in range(N) for a in range(A[n]) for h in range(hours)]) - kappa*gamma
def G(x, y, data):
"""
Upper-level inequality constraints
"""
hours = data["H"]
N = data["N"]
A = data["A"]
p, gamma = x[:hours], x[-1]
pl = []
for n in range(N):
pl.append(y[n*(A[n]*hours): (n + 1)*(A[n]*hours)].reshape(A[n], hours))
g_1 = [sum([pl[n][a][h] for n in range(N) for a in range(A[n])]) for h in range(hours)] - gamma
g_2 = -p
g_3 = p - p_max
return np.concatenate((g_1, g_2, g_3))
def H(x, y, data=None):
"""
Upper-level equality constraints
"""
return np.empty(0)
def f(x, y, data):
"""
Lower-level objective function
"""
hours = data["H"]
N = data["N"]
A = data["A"]
p_bar = data["p_bar"]
p, gamma = x[:hours], x[-1]
pl = []
for i in range(len(A)):
pl.append(y[sum(A[:i])*hours: sum(A[:i + 1])*hours].reshape(A[i], hours))
pl_bar = []
for i in range(len(A)):
pl_bar.append(y[sum(A)*hours + sum(A[:i])*hours: sum(A)*hours + sum(A[:i + 1])*hours].reshape(A[i], hours))
return sum(
[(p[h] + C(n, a, h, data))*pl[n][a, h] for n in range(N) for a in range(A[n]) for h in range(hours)]) + sum(
[(p_bar[h] + C(n, a, h, data))*pl_bar[n][a, h] for n in range(N) for a in range(A[n]) for h in range(hours)])
def g(x, y, data):
"""
Lower-level inequality constraints
"""
hours = data["H"]
N = data["N"]
A = data["A"]
E = data["E"]
beta_max = data["beta_max"]
p, gamma = x[:hours], x[-1]
pl = []
for n in range(N):
pl.append(y[n*(A[n]*hours): (n + 1)*(A[n]*hours)].reshape(A[n], hours))
pl_bar = []
for i in range(len(A)):
pl_bar.append(y[sum(A)*hours + sum(A[:i])*hours: sum(A)*hours + sum(A[:i + 1])*hours].reshape(A[i], hours))
g_1 = - y
g_2 = y[:sum(A)*hours] + y[sum(A)*hours:] - np.array(
[[beta_max[n][a]]*hours for n in range(N) for a in range(A[n])]).flatten()
g_3 = np.array(
[E[n][a] - sum([pl[n][a][h] for h in range(hours)]) - sum([pl_bar[n][a][h] for h in range(hours)]) for n in
range(N) for a in range(A[n])])
return np.concatenate((g_1, g_2, g_3))
def h(x, y, data=None):
"""
Lower-level equality constraints
"""
return np.empty(0)
def read_data(filepath=datasets[0]):
"""
If the bilevel program is parameterized by data, this function should
provide code to read data file and return an appropriate python structure.
"""
with open(filepath) as file:
json_str = file.read()
data = json.loads(json_str)
return data
def feasible_point(data=None):
"""
Returns a feasible point (x0, y0) satisfying:
G(x0, y0) >= 0,
H(x0, y0) == 0,
g(x0, y0) >= 0,
h(x0, y0) == 0.
"""
x0 = np.zeros(24 + 1)
y0 = np.zeros(4*24 + 2*24 + 1*24 + 4*24 + 2*24 + 1*24)
return x0, y0
def dimension(key='', data=None):
"""
If the argument 'key' is not specified, then:
- a dictionary mapping variable/function names (str) to the corresponding dimension (int) is returned.
If the first argument 'key' is specified, then:
- a single integer representing the dimension of the variable/function with the name {key} is returned.
"""
hours = data["H"]
N = data["N"]
A = data["A"]
n = {
"x": hours + 1, # Upper-level variables
"y": sum([a*hours for a in A])*2, # Lower-level variables
"F": 1, # Upper-level objective functions
"G": hours*3, # Upper-level inequality constraints
"H": 0, # Upper-level equality constraints
"f": 1, # Lower-level objective functions
"g": sum([a*hours for a in A])*3 + sum(A), # Lower-level inequality constraints
"h": 0, # Lower-level equality constraints
}
if key in n:
return n[key]
return n
# Extra Functions
def C(n, a, h, data):
lam = data["lam"]
E = data["E"]
T = data["T"]
return lam[h]*E[n][a]*((h - T[n][a][0])/(T[n][a][1] - T[n][a][0]))