diff options
Diffstat (limited to 'lib/model.py')
-rw-r--r-- | lib/model.py | 87 |
1 files changed, 23 insertions, 64 deletions
diff --git a/lib/model.py b/lib/model.py index 4c4c226..527a19e 100644 --- a/lib/model.py +++ b/lib/model.py @@ -4,7 +4,7 @@ import logging import numpy as np import os from .automata import PTA, ModelAttribute -from .functions import StaticFunction +from .functions import StaticFunction, SubstateFunction from .parameters import ParallelParamStats from .paramfit import ParallelParamFit from .utils import soft_cast_int, by_name_to_by_param, regression_measures @@ -439,6 +439,7 @@ class PTAModel(AnalyticModel): from .pelt import PELT self.pelt = PELT(**pelt) + # must run before _compute_stats so that _compute_stats produces a "substate_count" model self.find_substates() else: self.pelt = None @@ -448,6 +449,9 @@ class PTAModel(AnalyticModel): self._compute_stats(by_name) if self.pelt is not None: + # cluster_substates uses self.attr_by_name[*]["power"].param_values, which is set by _compute_stats + # cluster_substates relies on fitted "substate_count" models, which are generated by get_fitted. + self.get_fitted() # cluster_substates alters submodel_by_name, so we cannot use its keys() iterator. names_with_submodel = list(self.submodel_by_name.keys()) for name in names_with_submodel: @@ -465,60 +469,6 @@ class PTAModel(AnalyticModel): for key in elem["attributes"]: elem[key] = np.array(elem[key]) - def get_fitted_sub( - self, use_mean=False, safe_functions_enabled=False, state_duration=None - ): - - param_model_getter, param_info_getter = self.get_fitted( - use_mean=use_mean, safe_functions_enabled=safe_functions_enabled - ) - - def model_getter(name, key, **kwargs): - if key != "power": - return param_model_getter(name, key, **kwargs) - - try: - substate_count = round(param_model_getter(name, "substate_count")) - except KeyError: - return param_model_getter(name, key, **kwargs) - if substate_count == 1: - return param_model_getter(name, key, **kwargs) - - cumulative_energy = 0 - total_duration = 0 - substate_model, _ = self.submodel_by_name[name].get_fitted() - substate_sequence = self.substate_sequence_by_nc[(name, substate_count)] - for i, sub_name in enumerate(substate_sequence): - sub_duration = substate_model(sub_name, "duration", **kwargs) - sub_power = substate_model(sub_name, "power", **kwargs) - - if i == substate_count - 1: - if "duration" in kwargs: - sub_duration = kwargs["duration"] - total_duration - elif name in self.states and state_duration is not None: - sub_duration = state_duration - total_duration - - cumulative_energy += sub_power * sub_duration - total_duration += sub_duration - - return cumulative_energy / total_duration - - def info_getter(name, key, **kwargs): - if key != "power": - return None - - try: - substate_count = round(param_model_getter(name, "substate_count")) - except KeyError: - return None - if substate_count == 1: - return None - - # TODO - return True - - return model_getter, info_getter - # This heuristic is very similar to the "function is not much better than # median" checks in get_fitted. So far, doing it here as well is mostly # a performance and not an algorithm quality decision. @@ -669,13 +619,10 @@ class PTAModel(AnalyticModel): # Schwankungen, die beim separaten Fitting zu unterschiedlichen Funktionen führen würden. p_attr = self.attr_by_name[p_name]["power"] p_params = list(set(map(tuple, p_attr.param_values))) - p_param_index = dict() - for i, p_param in enumerate(p_params): - p_param_index[p_param] = i sub_attr_by_function = dict() static = submodel.get_static() lut = submodel.get_param_lut(fallback=True) - values_to_cluster = np.zeros((len(submodel.names), len(p_param_index))) + values_to_cluster = np.zeros((len(submodel.names), len(p_params))) for i, name in enumerate(submodel.names): for j, param in enumerate(p_params): values_to_cluster[i, j] = lut(name, "duration", param=param) @@ -699,7 +646,7 @@ class PTAModel(AnalyticModel): if len(cl_substates) == 1: clusters.append(cl_substates) continue - values_to_cluster = np.zeros((len(cl_substates), len(p_param_index))) + values_to_cluster = np.zeros((len(cl_substates), len(p_params))) for i, name in enumerate(cl_substates): for j, param in enumerate(p_params): values_to_cluster[i, j] = lut(name, "power", param=param) @@ -742,10 +689,22 @@ class PTAModel(AnalyticModel): "power": powers, } self.submodel_by_name[p_name] = PTAModel(by_name, self.parameters, dict()) - for k in self.substate_sequence_by_nc.keys(): - self.substate_sequence_by_nc[k] = list( - map(lambda x: new_subname_by_old[x], self.substate_sequence_by_nc[k]) - ) + sequence_by_count = dict() + for name, count in self.substate_sequence_by_nc.keys(): + if name == p_name: + sequence_by_count[int(count)] = list( + map( + lambda x: new_subname_by_old[x], + self.substate_sequence_by_nc[(name, count)], + ) + ) + + self.attr_by_name[p_name]["power"].model_function = SubstateFunction( + self.attr_by_name[p_name]["power"].get_static(), + sequence_by_count, + self.attr_by_name[p_name]["substate_count"].model_function, + self.submodel_by_name[p_name], + ) # data[0] = [first sub-state, second sub-state, ...] # data[1] = [first sub-state, second sub-state, ...] |