Skip to content

Commit

Permalink
First version of design compositions
Browse files Browse the repository at this point in the history
  • Loading branch information
ruicoelhopedro committed Mar 29, 2024
1 parent ee80d5e commit 0989d2b
Show file tree
Hide file tree
Showing 3 changed files with 303 additions and 56 deletions.
4 changes: 3 additions & 1 deletion piglot/objective.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
class Composition(ABC):
"""Abstract class for defining composition functionals with gradients"""

@abstractmethod
def composition(self, inner: np.ndarray) -> float:
"""Abstract method for computing the outer function of the composition
Expand All @@ -32,6 +31,9 @@ def composition(self, inner: np.ndarray) -> float:
float
Scalar composition result
"""
inner_torch = torch.from_numpy(inner)
result = self.composition_torch(inner_torch)
return result.numpy(force=True).item()

@abstractmethod
def composition_torch(self, inner: torch.Tensor) -> torch.Tensor:
Expand Down
136 changes: 109 additions & 27 deletions piglot/objectives/compositions.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Module for compositions of objectives."""
from typing import List, Tuple
import numpy as np
import torch
from piglot.objective import Composition
Expand All @@ -7,23 +8,27 @@
class MSEComposition(Composition):
"""Mean squared error outer composite function with gradients."""

def composition(self, inner: np.ndarray) -> float:
"""Compute the MSE outer function of the composition.
def composition_torch(self, inner: torch.Tensor) -> torch.Tensor:
"""Compute the MSE outer function of the composition with gradients.
Parameters
----------
inner : np.ndarray
inner : torch.Tensor
Return value from the inner function.
Returns
-------
float
torch.Tensor
Composition result.
"""
return np.mean(np.square(inner), axis=-1)
return torch.mean(torch.square(inner), dim=-1)


class MAEComposition(Composition):
"""Mean absolute error outer composite function with gradients."""

def composition_torch(self, inner: torch.Tensor) -> torch.Tensor:
"""Compute the MSE outer function of the composition with gradients.
"""Compute the MAE outer function of the composition with gradients.
Parameters
----------
Expand All @@ -35,44 +40,121 @@ def composition_torch(self, inner: torch.Tensor) -> torch.Tensor:
torch.Tensor
Composition result.
"""
return torch.mean(torch.square(inner), dim=-1)
return torch.mean(torch.abs(inner), dim=-1)


class MAEComposition(Composition):
"""Mean absolute error outer composite function with gradients."""
AVAILABLE_COMPOSITIONS = {
'mse': MSEComposition,
'mae': MAEComposition,
}


class UnflattenUtility:
"""Utility for unflattening a set of responses (with gradients)."""

def composition(self, inner: np.ndarray) -> float:
"""Compute the CAE outer function of the composition.
def __init__(self, lengths: List[int]):
self.lengths = lengths
self.indices = np.cumsum([0] + lengths)

def unflatten(self, data: np.ndarray) -> List[np.ndarray]:
"""Unflatten a vector containing a set of responses.
Parameters
----------
inner : np.ndarray
Return value from the inner function.
data : np.ndarray
Flattened data.
Returns
-------
float
Composition result.
List[np.ndarray]
List of unflatten responses.
"""
return np.mean(np.abs(inner), axis=-1)
return [data[..., self.indices[i]:self.indices[i+1]] for i in range(len(self.lengths))]

def composition_torch(self, inner: torch.Tensor) -> torch.Tensor:
"""Compute the CAE outer function of the composition with gradients.
def unflatten_torch(self, data: torch.Tensor) -> List[torch.Tensor]:
"""Unflatten a vector containing a set of responses with gradients.
Parameters
----------
inner : torch.Tensor
Return value from the inner function.
data : torch.Tensor
Flattened data.
Returns
-------
torch.Tensor
Composition result.
List[torch.Tensor]
List of unflatten responses (with gradients).
"""
return torch.mean(torch.abs(inner), dim=-1)
return [data[..., self.indices[i]:self.indices[i+1]] for i in range(len(self.lengths))]


AVAILABLE_COMPOSITIONS = {
'mse': MSEComposition,
'mae': MAEComposition,
}
class FixedLengthTransformer:
"""Utility for transforming a response into a fixed-length format and back."""

def __init__(self, n_points: int):
self.n_points = n_points

def length(self) -> int:
"""Return the length of the fixed-length response.
Returns
-------
int
Length of the fixed-length response.
"""
return self.n_points + 2

def transform(self, time: np.ndarray, data: np.ndarray) -> np.ndarray:
"""Transform a response into a fixed-length format.
Parameters
----------
time : np.ndarray
Time points to transform.
data : np.ndarray
Data points to transform.
Returns
-------
np.ndarray
Fixed-length response.
"""
bounds = np.array([np.min(time), np.max(time)])
grid = np.linspace(bounds[0], bounds[1], self.n_points)
response = np.interp(grid, time, data)
return np.concatenate([response, bounds], axis=-1)

def untransform(self, response: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
"""Untransform a fixed-length response into a response.
Parameters
----------
response : np.ndarray
Fixed-length response.
Returns
-------
Tuple[np.ndarray, np.ndarray]
Time and data points.
"""
grid, data = self.untransform_torch(torch.from_numpy(response))
return grid.numpy(force=True), data.numpy(force=True)

def untransform_torch(self, response: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]:
"""Untransform a fixed-length response into a response (with gradients).
Parameters
----------
response : torch.Tensor
Fixed-length response.
Returns
-------
Tuple[torch.Tensor, torch.Tensor]
Time and data points.
"""
response_gridless = response[..., :-2]
lbounds = response[..., -2].unsqueeze(-1).expand_as(response_gridless)
ubounds = response[..., -1].unsqueeze(-1).expand_as(response_gridless)
reg_grid = torch.linspace(0, 1, self.n_points).expand_as(response_gridless)
grid = lbounds + reg_grid * (ubounds - lbounds)
return grid, response_gridless
Loading

0 comments on commit 0989d2b

Please sign in to comment.