GitHub

romtools.workflows.parameter_spaces

Model reduction is often focused on parameterized PDEs, where $\boldsymbol \mu$ is the parameter set. The ParameterSpace class encapsulates the notion of the parameter space.

  1#
  2# ************************************************************************
  3#
  4#                         ROM Tools and Workflows
  5# Copyright 2019 National Technology & Engineering Solutions of Sandia,LLC
  6#                              (NTESS)
  7#
  8# Under the terms of Contract DE-NA0003525 with NTESS, the
  9# U.S. Government retains certain rights in this software.
 10#
 11# ROM Tools and Workflows is licensed under BSD-3-Clause terms of use:
 12#
 13# Redistribution and use in source and binary forms, with or without
 14# modification, are permitted provided that the following conditions
 15# are met:
 16#
 17# 1. Redistributions of source code must retain the above copyright
 18# notice, this list of conditions and the following disclaimer.
 19#
 20# 2. Redistributions in binary form must reproduce the above copyright
 21# notice, this list of conditions and the following disclaimer in the
 22# documentation and/or other materials provided with the distribution.
 23#
 24# 3. Neither the name of the copyright holder nor the names of its
 25# contributors may be used to endorse or promote products derived
 26# from this software without specific prior written permission.
 27#
 28# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 29# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 30# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 31# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 32# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 33# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 34# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 35# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 36# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 37# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 38# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 39# POSSIBILITY OF SUCH DAMAGE.
 40#
 41# Questions? Contact Eric Parish (ejparis@sandia.gov)
 42#
 43# ************************************************************************
 44#
 45
 46'''
 47Model reduction is often focused on parameterized PDEs, where
 48$\\boldsymbol \\mu$ is the parameter set.
 49The ParameterSpace class encapsulates the notion of the parameter space.
 50'''
 51import abc
 52from typing import Iterable
 53import numpy as np
 54
 55from romtools.workflows.sampling_methods import Sampler, MonteCarloSampler
 56from romtools.workflows.parameters import Parameter, StringParameter, UniformParameter, GaussianParameter
 57
 58
 59class ParameterSpace(abc.ABC):
 60    '''Abstract implementation'''
 61
 62    @abc.abstractmethod
 63    def get_names(self) -> Iterable[str]:
 64        '''
 65        Returns a list of parameter names
 66        # e.g., ['sigma','beta',...]
 67        '''
 68
 69    @abc.abstractmethod
 70    def get_dimensionality(self) -> int:
 71        '''
 72        Returns an integer for the size
 73        of the parameter domain
 74        '''
 75
 76    @abc.abstractmethod
 77    def generate_samples(self, number_of_samples: int, seed=None) -> np.array:
 78        '''
 79        Generates samples from the parameter space
 80
 81        Returns np.array of shape
 82        (number_of_samples, self.get_dimensionality())
 83        '''
 84
 85
 86##########################################
 87# Concrete ParameterSpace Classes
 88##########################################
 89
 90
 91class HeterogeneousParameterSpace(ParameterSpace):
 92    '''
 93    Heterogeneous parameter space consisting of a list of arbitrary Parameter
 94    objects
 95    '''
 96
 97    def __init__(self, parameter_objs: Iterable[Parameter], sampler: Sampler = MonteCarloSampler):
 98        self._parameters = parameter_objs
 99        self._sampler = sampler
100
101    def _get_parameter_list(self) -> Iterable[Parameter]:
102        '''
103        Returns a list of Parameter objects
104        '''
105        return self._parameters
106
107    def get_names(self) -> Iterable[str]:
108        return [p.get_name() for p in self._get_parameter_list()]
109
110    def get_dimensionality(self) -> int:
111        return sum(p.get_dimensionality() for p in self._get_parameter_list())
112
113    def generate_samples(self, number_of_samples: int, seed=None) -> np.array:
114        iid_samples = self._sampler(number_of_samples, self.get_dimensionality(), seed)
115        samples = []
116        param_idx = 0
117        for param in self._get_parameter_list():
118            next_param_idx = param_idx + param.get_dimensionality()
119            param_samples = param.scale_samples(iid_samples[:, param_idx:next_param_idx])
120            samples.append(param_samples)
121            param_idx = next_param_idx
122        return np.concatenate(samples, axis=1)
123
124
125class HomogeneousParameterSpace(HeterogeneousParameterSpace):
126    '''
127    Homogenous parameter space in which every parameter is of the same type
128    '''
129
130    def __init__(self, parameter_names: Iterable[str], sampler: Sampler, param_constructor, **kwargs):
131        parameters = []
132        for param_num, param_name in enumerate(parameter_names):
133            args = {key: val[param_num] for key, val in kwargs.items()}
134            parameters.append(param_constructor(parameter_name=param_name, **args))
135        super().__init__(parameters, sampler)
136
137
138class EmptyParameterSpace(ParameterSpace):
139    '''
140    Empty parameter space that is useful for initializations
141    '''
142
143    def get_names(self) -> list:
144        return []
145
146    def get_dimensionality(self) -> int:
147        return 0
148
149    def generate_samples(self, number_of_samples: int, seed=None) -> np.ndarray:
150        return np.empty(shape=(number_of_samples, 0))
151
152
153class UniformParameterSpace(HomogeneousParameterSpace):
154    '''
155    Homogeneous parameter space in which every parameter is a UniformParameter
156    '''
157
158    def __init__(self, parameter_names: Iterable[str], lower_bounds, upper_bounds, sampler: Sampler):
159        super().__init__(parameter_names, sampler=sampler, param_constructor=UniformParameter,
160                         lower_bound=lower_bounds, upper_bound=upper_bounds)
161
162
163class GaussianParameterSpace(HomogeneousParameterSpace):
164    '''
165    Homogeneous parameter space in which every parameter is a GaussianParameter
166    '''
167
168    def __init__(self, parameter_names: Iterable[str], means, stds, sampler: Sampler):
169        super().__init__(parameter_names, sampler=sampler, param_constructor=GaussianParameter, mean=means, std=stds)
170
171
172class ConstParameterSpace(HomogeneousParameterSpace):
173    '''
174    Homogeneous parameter space in which every parameter is a constant
175    StringParameter. All numeric values are converted to str-type.
176
177    Useful if you need to execute workflows in a non-stochastic setting
178    '''
179
180    def __init__(self, parameter_names: Iterable[str], parameter_values):
181        super().__init__(parameter_names, MonteCarloSampler, StringParameter, value=parameter_values)
class ParameterSpace(abc.ABC):
60class ParameterSpace(abc.ABC):
61    '''Abstract implementation'''
62
63    @abc.abstractmethod
64    def get_names(self) -> Iterable[str]:
65        '''
66        Returns a list of parameter names
67        # e.g., ['sigma','beta',...]
68        '''
69
70    @abc.abstractmethod
71    def get_dimensionality(self) -> int:
72        '''
73        Returns an integer for the size
74        of the parameter domain
75        '''
76
77    @abc.abstractmethod
78    def generate_samples(self, number_of_samples: int, seed=None) -> np.array:
79        '''
80        Generates samples from the parameter space
81
82        Returns np.array of shape
83        (number_of_samples, self.get_dimensionality())
84        '''

Abstract implementation

@abc.abstractmethod
def get_names(self) -> Iterable[str]:
63    @abc.abstractmethod
64    def get_names(self) -> Iterable[str]:
65        '''
66        Returns a list of parameter names
67        # e.g., ['sigma','beta',...]
68        '''

Returns a list of parameter names

e.g., ['sigma','beta',...]

@abc.abstractmethod
def get_dimensionality(self) -> int:
70    @abc.abstractmethod
71    def get_dimensionality(self) -> int:
72        '''
73        Returns an integer for the size
74        of the parameter domain
75        '''

Returns an integer for the size of the parameter domain

@abc.abstractmethod
def generate_samples(self, number_of_samples: int, seed=None) -> <built-in function array>:
77    @abc.abstractmethod
78    def generate_samples(self, number_of_samples: int, seed=None) -> np.array:
79        '''
80        Generates samples from the parameter space
81
82        Returns np.array of shape
83        (number_of_samples, self.get_dimensionality())
84        '''

Generates samples from the parameter space

Returns np.array of shape (number_of_samples, self.get_dimensionality())

class HeterogeneousParameterSpace(ParameterSpace):
 92class HeterogeneousParameterSpace(ParameterSpace):
 93    '''
 94    Heterogeneous parameter space consisting of a list of arbitrary Parameter
 95    objects
 96    '''
 97
 98    def __init__(self, parameter_objs: Iterable[Parameter], sampler: Sampler = MonteCarloSampler):
 99        self._parameters = parameter_objs
100        self._sampler = sampler
101
102    def _get_parameter_list(self) -> Iterable[Parameter]:
103        '''
104        Returns a list of Parameter objects
105        '''
106        return self._parameters
107
108    def get_names(self) -> Iterable[str]:
109        return [p.get_name() for p in self._get_parameter_list()]
110
111    def get_dimensionality(self) -> int:
112        return sum(p.get_dimensionality() for p in self._get_parameter_list())
113
114    def generate_samples(self, number_of_samples: int, seed=None) -> np.array:
115        iid_samples = self._sampler(number_of_samples, self.get_dimensionality(), seed)
116        samples = []
117        param_idx = 0
118        for param in self._get_parameter_list():
119            next_param_idx = param_idx + param.get_dimensionality()
120            param_samples = param.scale_samples(iid_samples[:, param_idx:next_param_idx])
121            samples.append(param_samples)
122            param_idx = next_param_idx
123        return np.concatenate(samples, axis=1)

Heterogeneous parameter space consisting of a list of arbitrary Parameter objects

HeterogeneousParameterSpace( parameter_objs: Iterable[romtools.workflows.parameters.Parameter], sampler: romtools.workflows.sampling_methods.Sampler = <function MonteCarloSampler>)
 98    def __init__(self, parameter_objs: Iterable[Parameter], sampler: Sampler = MonteCarloSampler):
 99        self._parameters = parameter_objs
100        self._sampler = sampler
def get_names(self) -> Iterable[str]:
108    def get_names(self) -> Iterable[str]:
109        return [p.get_name() for p in self._get_parameter_list()]

Returns a list of parameter names

e.g., ['sigma','beta',...]

def get_dimensionality(self) -> int:
111    def get_dimensionality(self) -> int:
112        return sum(p.get_dimensionality() for p in self._get_parameter_list())

Returns an integer for the size of the parameter domain

def generate_samples(self, number_of_samples: int, seed=None) -> <built-in function array>:
114    def generate_samples(self, number_of_samples: int, seed=None) -> np.array:
115        iid_samples = self._sampler(number_of_samples, self.get_dimensionality(), seed)
116        samples = []
117        param_idx = 0
118        for param in self._get_parameter_list():
119            next_param_idx = param_idx + param.get_dimensionality()
120            param_samples = param.scale_samples(iid_samples[:, param_idx:next_param_idx])
121            samples.append(param_samples)
122            param_idx = next_param_idx
123        return np.concatenate(samples, axis=1)

Generates samples from the parameter space

Returns np.array of shape (number_of_samples, self.get_dimensionality())

class HomogeneousParameterSpace(HeterogeneousParameterSpace):
126class HomogeneousParameterSpace(HeterogeneousParameterSpace):
127    '''
128    Homogenous parameter space in which every parameter is of the same type
129    '''
130
131    def __init__(self, parameter_names: Iterable[str], sampler: Sampler, param_constructor, **kwargs):
132        parameters = []
133        for param_num, param_name in enumerate(parameter_names):
134            args = {key: val[param_num] for key, val in kwargs.items()}
135            parameters.append(param_constructor(parameter_name=param_name, **args))
136        super().__init__(parameters, sampler)

Homogenous parameter space in which every parameter is of the same type

HomogeneousParameterSpace( parameter_names: Iterable[str], sampler: romtools.workflows.sampling_methods.Sampler, param_constructor, **kwargs)
131    def __init__(self, parameter_names: Iterable[str], sampler: Sampler, param_constructor, **kwargs):
132        parameters = []
133        for param_num, param_name in enumerate(parameter_names):
134            args = {key: val[param_num] for key, val in kwargs.items()}
135            parameters.append(param_constructor(parameter_name=param_name, **args))
136        super().__init__(parameters, sampler)
class EmptyParameterSpace(ParameterSpace):
139class EmptyParameterSpace(ParameterSpace):
140    '''
141    Empty parameter space that is useful for initializations
142    '''
143
144    def get_names(self) -> list:
145        return []
146
147    def get_dimensionality(self) -> int:
148        return 0
149
150    def generate_samples(self, number_of_samples: int, seed=None) -> np.ndarray:
151        return np.empty(shape=(number_of_samples, 0))

Empty parameter space that is useful for initializations

def get_names(self) -> list:
144    def get_names(self) -> list:
145        return []

Returns a list of parameter names

e.g., ['sigma','beta',...]

def get_dimensionality(self) -> int:
147    def get_dimensionality(self) -> int:
148        return 0

Returns an integer for the size of the parameter domain

def generate_samples(self, number_of_samples: int, seed=None) -> numpy.ndarray:
150    def generate_samples(self, number_of_samples: int, seed=None) -> np.ndarray:
151        return np.empty(shape=(number_of_samples, 0))

Generates samples from the parameter space

Returns np.array of shape (number_of_samples, self.get_dimensionality())

class UniformParameterSpace(HomogeneousParameterSpace):
154class UniformParameterSpace(HomogeneousParameterSpace):
155    '''
156    Homogeneous parameter space in which every parameter is a UniformParameter
157    '''
158
159    def __init__(self, parameter_names: Iterable[str], lower_bounds, upper_bounds, sampler: Sampler):
160        super().__init__(parameter_names, sampler=sampler, param_constructor=UniformParameter,
161                         lower_bound=lower_bounds, upper_bound=upper_bounds)

Homogeneous parameter space in which every parameter is a UniformParameter

UniformParameterSpace( parameter_names: Iterable[str], lower_bounds, upper_bounds, sampler: romtools.workflows.sampling_methods.Sampler)
159    def __init__(self, parameter_names: Iterable[str], lower_bounds, upper_bounds, sampler: Sampler):
160        super().__init__(parameter_names, sampler=sampler, param_constructor=UniformParameter,
161                         lower_bound=lower_bounds, upper_bound=upper_bounds)
class GaussianParameterSpace(HomogeneousParameterSpace):
164class GaussianParameterSpace(HomogeneousParameterSpace):
165    '''
166    Homogeneous parameter space in which every parameter is a GaussianParameter
167    '''
168
169    def __init__(self, parameter_names: Iterable[str], means, stds, sampler: Sampler):
170        super().__init__(parameter_names, sampler=sampler, param_constructor=GaussianParameter, mean=means, std=stds)

Homogeneous parameter space in which every parameter is a GaussianParameter

GaussianParameterSpace( parameter_names: Iterable[str], means, stds, sampler: romtools.workflows.sampling_methods.Sampler)
169    def __init__(self, parameter_names: Iterable[str], means, stds, sampler: Sampler):
170        super().__init__(parameter_names, sampler=sampler, param_constructor=GaussianParameter, mean=means, std=stds)
class ConstParameterSpace(HomogeneousParameterSpace):
173class ConstParameterSpace(HomogeneousParameterSpace):
174    '''
175    Homogeneous parameter space in which every parameter is a constant
176    StringParameter. All numeric values are converted to str-type.
177
178    Useful if you need to execute workflows in a non-stochastic setting
179    '''
180
181    def __init__(self, parameter_names: Iterable[str], parameter_values):
182        super().__init__(parameter_names, MonteCarloSampler, StringParameter, value=parameter_values)

Homogeneous parameter space in which every parameter is a constant StringParameter. All numeric values are converted to str-type.

Useful if you need to execute workflows in a non-stochastic setting

ConstParameterSpace(parameter_names: Iterable[str], parameter_values)
181    def __init__(self, parameter_names: Iterable[str], parameter_values):
182        super().__init__(parameter_names, MonteCarloSampler, StringParameter, value=parameter_values)