from math import pow
import pandas as pd
import matplotlib.pyplot as plt
from tabulate import tabulate
class Solver:
def __init__(self, alpha, user_at_home, heat_cost, Tout, heat_energy):
# Коэффициент важности дискомфорта пользователя.
self.alpha = alpha
# Массив булевых значений, когда пользователь присутствует дома.
self.b = user_at_home.copy()
# Кусочная функция стоимости отопления от кол-ва энергии.
self.c = heat_cost.copy()
# Массив значений температуры на улице в каждый час.
self.Tout = Tout.copy()
# Кол-во вырабатываемых джоулей в зависимости от режима.
self.u = heat_energy.copy()
self.W_cache = [{} for _ in self.b]
self.dis = 0
def w(self, alpha, is_at_home, current_T, heat_cost):
"""
Возвращает выигрыш: сумму дискомфорта пользователя и стоимость
режима работы.
"""
return is_at_home * alpha * pow(18 - current_T, 2) + (1 - alpha) * heat_cost
def phi(self, heat, current_T, Tout):
"""Возвращает новое состояние: температуру в доме."""
return current_T + 0.5 * (heat - 0.2 * (current_T - Tout))
def W(self, stage, state):
# Если для текущего этапа и состояния была рассчитана ф-ция.
if state in self.W_cache[stage]:
return self.W_cache[stage][state]
best_w = None
best_u = None
best_dis = None
for ui in self.u:
# Если этап последний, то учитываем, какая температура будет после него.
if stage == 11:
final_t = round(self.phi(ui, state, self.Tout[stage]), 1)
wi = round(self.w(self.alpha, self.b[stage], final_t, self.c[ui]), 2)
else:
wi = round(self.w(self.alpha, self.b[stage], state, self.c[ui]) + \
self.W(stage + 1, round(self.phi(ui, state, self.Tout[stage]), 1))[0], 2)
if best_w is None or wi < best_w:
best_w = wi
best_u = ui
# Мемоизация
self.W_cache[stage][state] = (best_w, best_u)
return (best_w, best_u)
def restore_optimal(self):
# Массив режимов работы в каждый час.
control = []
# Массив температуры на начало каждого этапа.
temperature = []
# Начальная температура.
state = 18
for stage in range(len(self.b)):
temperature.append(state)
# Значение не персчитывается, так все они были записаны.
# Лучший режим работы среди сохраненных находим по состоянию.
u = self.W(stage, state)[1]
control.append(u)
state = round(self.phi(u, state, self.Tout[stage]), 1)
return control, temperature, state
def solve(self):
return (self.W(0, 18)[0], *self.restore_optimal())
# Коэффициент важности дсикомфорта пользователя.
alpha = 0.8
# Массив булевых значений, когда пользователь присутствует дома.
bi = [0 if i < 6 else 1 for i in range(12)]
# Кусочная функция стоимости отопления от кол-ва энергии.
c = {0: 0, 2: 12, 4: 25, 6: 43, 8: 62, 10: 83}
# Массив значений температуры на улице в каждый час.
Tout = [-14, -13, -13, -12, -12, -11, -11, -10, -10, -9, -9, -8]
# Кол-во вырабатываемых джоулей в зависимости от режима.
u = [0, 2, 4, 6, 8, 10]
s = Solver(alpha, bi, c, Tout, u)
W, U, T, final_T = s.solve()
# Вывод резульатов.
columns = [bi, T, U]
row_names = ['Присутствие пользователя', 'Температура', 'Режим работы']
columns = [list(i) for i in zip(*columns)]
column_names = [list(range(1, 13))]
data = dict(zip(*column_names, columns))
df = pd.DataFrame(data, index=row_names)
print(tabulate(df, headers='keys', tablefmt='psql'))
cost = sum(map(lambda x: c[x], U))
print(f"Значение alpha: {alpha};")
print(f"Значение целевой функции: {W};")
print(f"Температура в конце 12-го часа: {final_T};")
print(f"Стоимость отопления: {cost} ДЕ.")
# Анализ чувствительности:
alpha = [i/100 for i in range(1, 101)]
costs = []
w = []
for a in alpha:
s = Solver(a, bi, c, Tout, u)
W, U, T, final_T = s.solve()
cost = sum(map(lambda x: c[x], U))
w.append(W)
costs.append(cost)
plt.plot(alpha, costs, 'ro--')
plt.plot(alpha, w, 'go--')
plt.title('Зависимость стоимости и целевой функции от коэффициента значимости', fontsize=20, fontname='Times New Roman')
plt.xlabel('Альфа', fontsize=20)
plt.ylabel('Y', fontsize=20)
plt.show()
Соседние файлы в папке Практическая работа №3