import math
|
import abc
|
|
from .SlidingWindow import SlidingWindow
|
|
|
class Cost(abc.ABC):
|
def __init__(self, temp_min=19.5, temp_max=20.6, params=None):
|
if params is None:
|
params = ('heating', 'heater_on', 'heater_off', 'discomfort')
|
self.params = params
|
|
self.costs = {}
|
for param in params:
|
self.costs[param] = 0.0
|
|
self.temp_min = temp_min
|
self.temp_max = temp_max
|
|
def total(self):
|
return sum(self.costs.values())
|
|
def __lt__(self, other):
|
return self.total() < other.total()
|
|
def __str__(self):
|
result = ''
|
for param in self.params:
|
result += '{}={} '.format(param, self.costs[param])
|
result += 'total={}'.format(self.total())
|
return result
|
|
@abc.abstractmethod
|
def compute_partial_cost(self, window: SlidingWindow) -> dict:
|
pass
|
|
def add_partial_cost(self, window: SlidingWindow) -> dict:
|
partial_cost = self.compute_partial_cost(window)
|
for k, v in partial_cost.items():
|
self.costs[k] += v
|
return partial_cost
|
|
|
class DeviationCost(Cost):
|
def __init__(self, *args, **kwargs):
|
super().__init__(*args, **kwargs, params=('step', 'diff', 'diff_sum', 'mean', 'sq_err'))
|
|
def compute_partial_cost(self, window: SlidingWindow) -> dict:
|
partial_cost = {}
|
|
temp = window.get_current_value('temp_in')
|
temp_calc = window.get_current_orig_value('temp_in')
|
diff = abs(temp - temp_calc)
|
|
partial_cost['diff_sum'] = diff
|
|
partial_cost['mean'] = diff * diff
|
partial_cost['step'] = 1
|
|
return partial_cost
|
|
def add_partial_cost(self, window: SlidingWindow) -> dict:
|
result = super().add_partial_cost(window)
|
self.costs['sq_err'] = self.costs['mean'] / self.costs['step']
|
self.costs['diff'] = max(self.costs['diff'], result['diff_sum'])
|
return result
|
|
|
class NegativeCostBase(Cost):
|
def compute_partial_cost(self, window: SlidingWindow):
|
partial_cost = {}
|
partial_cost['heating'] = window.get_previous_value('mode')
|
|
temperature = window.get_next_value('temp_in')
|
deviation = 0
|
if temperature < self.temp_min:
|
deviation = self.temp_min - temperature
|
elif temperature > self.temp_max:
|
deviation = temperature - self.temp_max
|
if deviation:
|
partial_cost['discomfort'] = pow(deviation * 11, 2)
|
|
return partial_cost
|
|
|
class NegativeCost(Cost):
|
def compute_partial_cost(self, window: SlidingWindow):
|
mode = window.get_previous_value('mode')
|
last_mode = window.get_value('mode', -3)
|
temperature = window.get_current_value('temp_in')
|
|
partial_cost = {}
|
|
if mode:
|
partial_cost['heating'] = 1
|
|
if last_mode is not None:
|
if not last_mode and mode:
|
partial_cost['heater_on'] = 3
|
elif last_mode and not mode:
|
partial_cost['heater_off'] = 4
|
|
deviation = 0
|
if temperature < self.temp_min:
|
deviation = self.temp_min - temperature
|
elif temperature > self.temp_max:
|
deviation = temperature - self.temp_max
|
if deviation:
|
partial_cost['discomfort'] = pow(deviation * 11, 2)
|
|
return partial_cost
|
|
|
class NegativeCostExtendedRange(NegativeCost):
|
def __init__(self):
|
super().__init__(temp_max=20.6)
|