Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 38 additions & 21 deletions src/dial_service/serverside_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,11 @@ def scale_X(self, X: np.ndarray) -> np.ndarray:

return (X - lows) / span

def _extract_y_train_from_dataset(self):
@cached_property
def y_train_raw(self) -> np.ndarray:
"""
Find output y and error values yerr in dataset_y, and save.
Return the raw training target values extracted from the dataset.
"""
if hasattr(self, 'y_train_raw') and hasattr(self, 'yerr_train_raw'):
# only compute this on first invocation
return

y_label = self.statistics_y.loc
if not isinstance(y_label, str):
msg = 'statistics_y.loc must be a Label (str).'
Expand All @@ -78,31 +75,34 @@ def _extract_y_train_from_dataset(self):
# Use the label from self.statistics_y.loc to find the data column with the mean y data
# this may trigger a ValueError, if the label does not exist, but should be handled by dataclass validation
pos_y = self.labels_y.index(y_label)
self.y_train_raw = self.dataset_y[:, pos_y]
return self.dataset_y[:, pos_y]

@cached_property
def yerr_train_raw(self) -> any:
"""
Return the raw training error values extracted from the dataset.
"""
yerr_label = self.statistics_y.scale
if isinstance(yerr_label, float):
self.yerr_train_raw = yerr_label
_yerr_train_raw = yerr_label
else:
# yerr_label is str
# this may trigger a ValueError, but should be handled by dataclass validation
pos_yerr = self.labels_y.index(yerr_label)
self.yerr_train_raw = self.dataset_y[:, pos_yerr]
_yerr_train_raw = self.dataset_y[:, pos_yerr]

if np.any(self.yerr_train_raw < 0):
idxs = np.where(np.yerr_train_raw < 0)
msg = f'yerr values in statistics_y.scale must be non-negative, found {np.yerr_train_raw[idxs[0]]} at {idxs[0]}.'
if np.any(_yerr_train_raw < 0):
idxs = np.where(_yerr_train_raw < 0)
msg = f'yerr values in statistics_y.scale must be non-negative, found {_yerr_train_raw[idxs[0]]} at {idxs[0]}.'
raise ValueError(msg)
return _yerr_train_raw

@cached_property
def Y_train(self) -> np.ndarray:
"""
Find output y and error values yerr in dataset_y, and apply transformation.
Return transformed y value.
"""
# ensure that self.y_train_raw, self.yerr_train_raw are populated
self._extract_y_train_from_dataset()

y, _ = self.transform_Y(self.y_train_raw, self.yerr_train_raw)

# return only y, to conform to interface
Expand All @@ -114,9 +114,6 @@ def Yerr_train(self) -> any:
Find output y and error values in dataset y, and apply transformation.
Return transformed yerr value.
"""
# ensure that self.y_train_raw, self.yerr_train_raw are populated
self._extract_y_train_from_dataset()

# recompute transformation, at some overhead (probably not worth to optimize)
_, yerr = self.transform_Y(self.y_train_raw, self.yerr_train_raw)

Expand All @@ -127,9 +124,6 @@ def _transform_Y_params(self) -> tuple[float, float]:
"""
Return the appropriate mean and scaling of the raw y data for normalization
"""
# ensure that self.y_train_raw, self.yerr_train_raw are populated
self._extract_y_train_from_dataset()

# find y_std from y_train_raw
y_train = self.y_train_raw
if len(y_train) > 0 and self.preprocess_standardize:
Expand Down Expand Up @@ -177,6 +171,29 @@ def inverse_transform_Y(self, y: np.ndarray, yerr: any) -> tuple[np.ndarray, any
def Y_best(self) -> float:
return self.Y_train.max() if self.y_is_good else self.Y_train.min()

def clear_cached_properties(self) -> None:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll have to look at this but I think this function impacts more than it should

# Track attribute names that have already been encountered.
# Classes are inspected in Method Resolution Order (MRO) order,
# starting with the most-derived class
resolved_names = set()

# Walk through the class hierarchy:
# DerivedClass -> BaseClass -> ... -> object
for cls in type(self).__mro__:
# Inspect only attributes defined directly on the current class
for name, attr in cls.__dict__.items():
# Skip names already defined by a more-derived class
if name in resolved_names:
continue

resolved_names.add(name)

# A cached_property descriptor is stored on the class,
# while its computed value is stored in the instance __dict__
if isinstance(attr, cached_property):
# Remove the cached value if it exists
self.__dict__.pop(name, None)


class ServersideInputSingle(ServersideInputBase):
def __init__(
Expand Down
Loading