PEG_opti/opti_prod.py

103 lines
3 KiB
Python
Raw Normal View History

2023-12-10 20:40:49 +00:00
import numpy as np
import matplotlib.pyplot as plt
import PyQt5 as qt
2023-12-11 10:20:44 +00:00
# Valeurs des constantes de l'exemple du cours
2023-12-10 20:40:49 +00:00
ptot = 1000 # [MW]
2023-12-10 22:57:18 +00:00
p2max = 400 # [MW]
p23max = 500
t21 = 0.4545
t22 = 0.8182
2023-12-10 20:40:49 +00:00
def C1(x):
return 30*x + 0.01*x**2
def C2(x):
return 20*x + 0.02*x**2
def f(x):
2023-12-11 10:20:44 +00:00
# Lagrangien pour une optimisation simple de la production
2023-12-10 22:57:18 +00:00
return C1(x[0]) + C2(x[1]) + x[2] * (ptot - x[0] - x[1])
def f2(x):
2023-12-11 10:20:44 +00:00
# Lagrangien pour une optimisation avec contrainte de production max
2023-12-10 22:57:18 +00:00
return f(x[0:3]) - abs(x[3]) * (p2max - x[1])
def f3(x):
2023-12-11 10:20:44 +00:00
# Lagrangien pour une optimisation avec contrainte de production et de transport max
2023-12-10 22:57:18 +00:00
return f(x[0:3]) - abs(x[3]) * (p23max - t21 * x[0] - t22 * x[1])
2023-12-10 20:40:49 +00:00
def grad(f, x, h=1e-4):
2023-12-11 10:20:44 +00:00
# Il y a surement des librairies qui font ça mieux, mais c'était plus rapide d'écrire cette fonction que de chercher dans la doc
2023-12-10 20:40:49 +00:00
res = []
for i in range(len(x)):
delta = f(x[:i] + [x[i] + h / 2] + x[i+1:]) - f(x[:i] + [x[i] - h / 2] + x[i+1:])
res += [delta / h]
return res
def norm(x):
2023-12-11 10:20:44 +00:00
# Idem, flemme d'utiliser des arrays et de lire la doc np
2023-12-10 20:40:49 +00:00
n = 0
for d in x:
n += d**2
return np.sqrt(n)
2023-12-11 10:20:44 +00:00
def adaptation_f(f):
# Permet de lancer la descente de gradient sur la norme du gradient du lagrangien
l = lambda x : norm(grad(f, x, h=1e-6)) # Un pas plus faible va créer des divergences
return l
2023-12-10 22:57:18 +00:00
def minimize(f, x0, h=1e-4, step=1e-1, tol=1e-8, N=1e4, echo=False):
2023-12-11 10:20:44 +00:00
# Initialisation
2023-12-10 20:40:49 +00:00
x = x0
g = grad(f, x, h)
n = 0
2023-12-11 10:20:44 +00:00
prev = norm(g) + 2*tol # Très moche mais j'ai pas le temps de faire un truc plus élégant
2023-12-10 22:57:18 +00:00
2023-12-10 20:40:49 +00:00
while abs(norm(g) - prev) > tol:
2023-12-11 10:20:44 +00:00
# Mise à jour de la variable de suivi de convergence
2023-12-10 20:40:49 +00:00
prev = norm(g)
2023-12-11 10:20:44 +00:00
# Calcul
for i in range(len(x)): # Moche mais flemme de rendre ça joli
x[i] -= g[i] * step # Descente de gradient classique
2023-12-10 20:40:49 +00:00
g = grad(f, x, h)
2023-12-10 22:57:18 +00:00
2023-12-11 10:20:44 +00:00
# Print pour debug
2023-12-10 20:40:49 +00:00
if (n % 100 == 0) and echo:
print("Itération ", n)
print("norm(g) = ", norm(g))
print("prev = ", prev)
print("x = ", x)
print("g = ", g)
2023-12-11 10:20:44 +00:00
# Système anti boucle infinie
2023-12-10 20:40:49 +00:00
if n > N:
return x
2023-12-11 10:20:44 +00:00
n += 1
2023-12-10 20:40:49 +00:00
return x
2023-12-11 10:20:44 +00:00
def custom_minimize(f, x0, echo=False):
2023-12-10 22:57:18 +00:00
res_app = minimize(f, x0, step=5e-1)
2023-12-11 10:20:44 +00:00
if echo:
print(res_app)
2023-12-10 22:57:18 +00:00
res_app = minimize(f, res_app, step=1e-3, tol=1e-12, h=1e-5)
2023-12-11 10:20:44 +00:00
if echo:
print(res_app)
2023-12-10 22:57:18 +00:00
res_app = minimize(f, res_app, step=1e-5, tol=1e-14, h=1e-5)
2023-12-11 10:20:44 +00:00
if echo:
print(res_app)
2023-12-10 22:57:18 +00:00
res_app = minimize(f, res_app, step=1e-6, tol=1e-16, h=5e-6)
2023-12-11 10:20:44 +00:00
if echo:
print(res_app)
2023-12-10 22:57:18 +00:00
return res_app
2023-12-11 10:20:44 +00:00
print("Cas sans contraintes")
print(custom_minimize(adaptation_f(f), [0, 0, 0]))
2023-12-10 22:57:18 +00:00
2023-12-11 10:20:44 +00:00
print("Cas avec contrainte de production")
print(custom_minimize(adaptation_f(f2), [0, 0, 0, 0.01]))
2023-12-10 22:57:18 +00:00
2023-12-11 10:20:44 +00:00
print("Cas avec contraintes de production et de transport")
print(custom_minimize(adaptation_f(f3), [0, 0, 0, 0.01]))