diff --git a/rrompy/parameter/parameter_map.py b/rrompy/parameter/parameter_map.py index 9e6a162..1daaaa0 100644 --- a/rrompy/parameter/parameter_map.py +++ b/rrompy/parameter/parameter_map.py @@ -1,48 +1,54 @@ # Copyright (C) 2018 by the RROMPy authors # # This file is part of RROMPy. # # RROMPy is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # RROMPy is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with RROMPy. If not, see . # import numpy as np from numbers import Number from rrompy.utilities.base.types import DictAny from rrompy.utilities.exception_manager import RROMPyException, RROMPyAssert __all__ = ['parameterMap'] def parameterMap(pMap = 1., npar : int = None) -> DictAny: if isinstance(pMap, (Number,)): if npar is None: npar = 1 pMap = [pMap] * npar if isinstance(pMap, (tuple,)): pMap = list(pMap) if isinstance(pMap, (dict,)): if (("F" not in pMap.keys() and "f" not in pMap.keys()) or ("B" not in pMap.keys() and "b" not in pMap.keys())): raise RROMPyException("Keys missing from parameter map dict.") parameterMap = {} parameterMap["F"] = pMap["F"] if "F" in pMap.keys() else pMap["f"] parameterMap["B"] = pMap["B"] if "B" in pMap.keys() else pMap["b"] return parameterMap if isinstance(pMap, (list,)): if npar is not None: RROMPyAssert(len(pMap), npar, "Length of parameter map scaling exponent.") - if np.all(np.isclose(pMap, 1.)): return {"F": ['x'], "B": ['x']} - return {"F": ['x', '**', pMap], - "B": ['x', '**', list(1. / np.array(pMap))]} + parameterMap = {"F":[], "B":[]} + for e in pMap: + if np.isclose(e, 1.): + parameterMap["F"] += [['x']] + parameterMap["B"] += [['x']] + else: + parameterMap["F"] += [['x', '**', e]] + parameterMap["B"] += [['x', '**', 1. / e]] + return parameterMap raise RROMPyException(("Parameter map not recognized. Only dict with keys " "'F' and 'B', or list of scaling exponents are " "allowed.")) diff --git a/rrompy/parameter/parameter_sampling/generic_sampler.py b/rrompy/parameter/parameter_sampling/generic_sampler.py index 4d557ac..5009683 100644 --- a/rrompy/parameter/parameter_sampling/generic_sampler.py +++ b/rrompy/parameter/parameter_sampling/generic_sampler.py @@ -1,91 +1,94 @@ # Copyright (C) 2018 by the RROMPy authors # # This file is part of RROMPy. # # RROMPy is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # RROMPy is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with RROMPy. If not, see . # import numpy as np from abc import abstractmethod from numbers import Number -from rrompy.utilities.base.types import Tuple, DictAny, paramList +from rrompy.utilities.base.types import Tuple, List, DictAny, paramList from rrompy.utilities.expression import expressionEvaluator from rrompy.utilities.exception_manager import RROMPyException, RROMPyAssert from rrompy.parameter import checkParameterList, parameterMap as pMap __all__ = ['GenericSampler'] class GenericSampler: """ABSTRACT. Generic generator of sample points.""" def __init__(self, lims:paramList, parameterMap : DictAny = 1.): self.lims = lims self.parameterMap = pMap(parameterMap, self.npar) def name(self) -> str: return self.__class__.__name__ def __str__(self) -> str: return "{}[{}_{}]".format(self.name(), self.lims[0], self.lims[1]) def __repr__(self) -> str: return self.__str__() + " at " + hex(id(self)) def __eq__(self, other) -> bool: if (not hasattr(other, "__dict__") or self.__dict__.keys() != other.__dict__.keys()): return False for key in self.__dict__: val = self.__dict__[key] if isinstance(val, (np.ndarray,)): if not np.allclose(val, other.__dict__[key]): return False else: if val != other.__dict__[key]: return False return True @property def npar(self): """Number of parameters.""" return self._lims.shape[1] def normalFoci(self, d : int = 0): return [-1., 1.] def groundPotential(self, d : int = 0): fp = self.normalFoci(d)[1] fpa = np.abs(fp) if np.isclose(fpa, 0.) or np.isclose(fpa, 1.): return 1. return (1. + np.abs(1. - fp ** 2.) ** .5) / fpa @property def lims(self): """Value of lims.""" return self._lims @lims.setter def lims(self, lims): lims = checkParameterList(lims)[0] if len(lims) != 2: raise RROMPyException("2 limits must be specified.") self._lims = lims - def mapParameterList(self, mu:paramList, - direct : str = "F") -> Tuple[paramList, bool]: - muMapped = expressionEvaluator(self.parameterMap[direct], - checkParameterList(mu, self.npar)[0]) - return checkParameterList(muMapped, self.npar) + def mapParameterList(self, mu:paramList, direct : str = "F", + idx : List[int] = None) -> paramList: + if idx is None: idx = np.arange(self.npar) + muMapped = checkParameterList(mu, len(idx))[0] + for j, d in enumerate(idx): + muMapped.data[:, j] = expressionEvaluator( + self.parameterMap[direct][d], muMapped(j))(0) + return muMapped @abstractmethod def generatePoints(self, n:int, reorder : bool = True) -> paramList: """Array of points.""" pass diff --git a/rrompy/parameter/parameter_sampling/segment/quadrature_sampler.py b/rrompy/parameter/parameter_sampling/segment/quadrature_sampler.py index 6807917..c167860 100644 --- a/rrompy/parameter/parameter_sampling/segment/quadrature_sampler.py +++ b/rrompy/parameter/parameter_sampling/segment/quadrature_sampler.py @@ -1,49 +1,48 @@ # Copyright (C) 2018 by the RROMPy authors # # This file is part of RROMPy. # # RROMPy is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # RROMPy is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with RROMPy. If not, see . # import numpy as np from rrompy.parameter.parameter_sampling.generic_quadrature_sampler import ( GenericQuadratureSampler) from rrompy.utilities.base.types import paramList from rrompy.utilities.numerical import (lowDiscrepancy, kroneckerer, quadraturePointsGenerate) -from rrompy.parameter import checkParameterList __all__ = ['QuadratureSampler'] class QuadratureSampler(GenericQuadratureSampler): """Generator of quadrature sample points.""" def generatePoints(self, n:int, reorder : bool = True) -> paramList: """Array of sample points.""" n1d = int(np.ceil(n ** (1. / self.npar))) nleft, nright = 1, n1d ** self.npar xmat = np.empty((nright, self.npar), dtype = self.lims.dtype) - limsE = self.mapParameterList(self.lims)[0] + limsE = self.mapParameterList(self.lims) for d in range(self.npar): nright //= n1d a, b = limsE(d) c, r = (a + b) / 2., (a - b) / 2. xd = c + r * quadraturePointsGenerate(n1d, self.kind) xmat[:, d] = kroneckerer(xd, nleft, nright) nleft *= n1d nright = n1d ** self.npar if nright > 1 and reorder: fejerOrdering = [nright - 1] + lowDiscrepancy(nright - 1) xmat = xmat[fejerOrdering, :] - return self.mapParameterList(xmat, "B")[0] + return self.mapParameterList(xmat, "B") diff --git a/rrompy/parameter/parameter_sampling/segment/random_sampler.py b/rrompy/parameter/parameter_sampling/segment/random_sampler.py index cb986e8..3e0c8fb 100644 --- a/rrompy/parameter/parameter_sampling/segment/random_sampler.py +++ b/rrompy/parameter/parameter_sampling/segment/random_sampler.py @@ -1,44 +1,43 @@ # Copyright (C) 2018 by the RROMPy authors # # This file is part of RROMPy. # # RROMPy is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # RROMPy is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with RROMPy. If not, see . # import numpy as np from rrompy.parameter.parameter_sampling.generic_random_sampler import ( GenericRandomSampler) from rrompy.utilities.numerical import haltonGenerate, sobolGenerate from rrompy.utilities.base.types import paramList -from rrompy.parameter import checkParameterList __all__ = ['RandomSampler'] class RandomSampler(GenericRandomSampler): """Generator of (quasi-)random sample points.""" def generatePoints(self, n:int, reorder : bool = True) -> paramList: """Array of quadrature points.""" if self.kind == "UNIFORM": np.random.seed(self.seed) xmat = np.random.uniform(size = (n, self.npar)) elif self.kind == "HALTON": xmat = haltonGenerate(self.npar, n, self.seed) else: xmat = sobolGenerate(self.npar, n, self.seed) - limsE = self.mapParameterList(self.lims)[0] + limsE = self.mapParameterList(self.lims) for d in range(self.npar): a, b = limsE(d) xmat[:, d] = a + (b - a) * xmat[:, d] - return self.mapParameterList(xmat, "B")[0] + return self.mapParameterList(xmat, "B") diff --git a/rrompy/parameter/parameter_sampling/shape/fft_sampler.py b/rrompy/parameter/parameter_sampling/shape/fft_sampler.py index 844cef0..e9fb583 100644 --- a/rrompy/parameter/parameter_sampling/shape/fft_sampler.py +++ b/rrompy/parameter/parameter_sampling/shape/fft_sampler.py @@ -1,49 +1,48 @@ # Copyright (C) 2018 by the RROMPy authors # # This file is part of RROMPy. # # RROMPy is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # RROMPy is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with RROMPy. If not, see . # import numpy as np from .generic_shape_sampler import GenericShapeSampler from rrompy.utilities.base.types import paramList from rrompy.utilities.numerical import lowDiscrepancy, kroneckerer -from rrompy.parameter import checkParameterList __all__ = ['FFTSampler'] class FFTSampler(GenericShapeSampler): """Generator of FFT-type sample points on scaled roots of unity.""" def generatePoints(self, n:int, reorder : bool = True) -> paramList: """Array of sample points.""" n1d = int(np.ceil(n ** (1. / self.npar))) nleft, nright = 1, n1d ** self.npar xmat = np.empty((nright, self.npar), dtype = np.complex) - limsE = self.mapParameterList(self.lims)[0] + limsE = self.mapParameterList(self.lims) for d in range(self.npar): nright //= n1d a, b = limsE(d) c, r = (a + b) / 2., (a - b) / 2. unitpts = np.exp(1.j * np.linspace(0, 2 * np.pi, n1d + 1)[:-1]) unitpts = (np.real(unitpts) + 1.j * self.axisRatios[d] * np.imag(unitpts)) xd = c + r * unitpts if n1d > 1 and reorder: fejerOrdering = [n1d - 1] + lowDiscrepancy(n1d - 1) xd = xd[fejerOrdering] xmat[:, d] = kroneckerer(xd, nleft, nright) nleft *= n1d - return self.mapParameterList(xmat, "B")[0] + return self.mapParameterList(xmat, "B") diff --git a/rrompy/parameter/parameter_sampling/shape/quadrature_box_sampler.py b/rrompy/parameter/parameter_sampling/shape/quadrature_box_sampler.py index 13b6bc3..f61d64b 100644 --- a/rrompy/parameter/parameter_sampling/shape/quadrature_box_sampler.py +++ b/rrompy/parameter/parameter_sampling/shape/quadrature_box_sampler.py @@ -1,56 +1,55 @@ # Copyright (C) 2018 by the RROMPy authors # # This file is part of RROMPy. # # RROMPy is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # RROMPy is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with RROMPy. If not, see . # import numpy as np from .generic_shape_quadrature_sampler import GenericShapeQuadratureSampler from rrompy.utilities.base.types import paramList from rrompy.utilities.numerical import (lowDiscrepancy, kroneckerer, quadraturePointsGenerate) -from rrompy.parameter import checkParameterList __all__ = ['QuadratureBoxSampler'] class QuadratureBoxSampler(GenericShapeQuadratureSampler): """Generator of quadrature sample points on boxes.""" def generatePoints(self, n:int, reorder : bool = True) -> paramList: """Array of sample points.""" n1d = int(np.ceil(n ** (1. / self.npar))) xds, nds = [None] * self.npar, [None] * self.npar - limsE = self.mapParameterList(self.lims)[0] + limsE = self.mapParameterList(self.lims) for d in range(self.npar): ax = self.axisRatios[d] a, b = limsE(d) c, r = (a + b) / 2., (a - b) / 2. n1dx = int(np.ceil((n1d / ax) ** .5)) n1dy = int(np.ceil(n1d / n1dx)) Xdx, Xdy = np.meshgrid(quadraturePointsGenerate(n1dx, self.kind), quadraturePointsGenerate(n1dy, self.kind)) Z = Xdx.flatten() + 1.j * ax * Xdy.flatten() xds[d] = c + r * Z nds[d] = len(Z) nleft, nright = 1, np.prod(nds) xmat = np.empty((nright, self.npar), dtype = np.complex) for d in range(self.npar): nright //= nds[d] xmat[:, d] = kroneckerer(xds[d], nleft, nright) nleft *= nds[d] if len(xmat) > 1 and reorder: fejerOrdering = [len(xmat) - 1] + lowDiscrepancy(len(xmat) - 1) xmat = xmat[fejerOrdering, :] - return self.mapParameterList(xmat, "B")[0] + return self.mapParameterList(xmat, "B") diff --git a/rrompy/parameter/parameter_sampling/shape/quadrature_circle_sampler.py b/rrompy/parameter/parameter_sampling/shape/quadrature_circle_sampler.py index fc2f624..eabc845 100644 --- a/rrompy/parameter/parameter_sampling/shape/quadrature_circle_sampler.py +++ b/rrompy/parameter/parameter_sampling/shape/quadrature_circle_sampler.py @@ -1,64 +1,63 @@ # Copyright (C) 2018 by the RROMPy authors # # This file is part of RROMPy. # # RROMPy is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # RROMPy is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with RROMPy. If not, see . # import numpy as np from .generic_shape_quadrature_sampler import GenericShapeQuadratureSampler from rrompy.utilities.base.types import paramList from rrompy.utilities.numerical import (lowDiscrepancy, kroneckerer, potential, quadraturePointsGenerate) -from rrompy.parameter import checkParameterList __all__ = ['QuadratureCircleSampler'] class QuadratureCircleSampler(GenericShapeQuadratureSampler): """Generator of quadrature sample points on ellipses.""" def generatePoints(self, n:int, reorder : bool = True) -> paramList: """Array of sample points.""" n1d = int(np.ceil(n ** (1. / self.npar))) xds, nds = [None] * self.npar, [None] * self.npar - limsE = self.mapParameterList(self.lims)[0] + limsE = self.mapParameterList(self.lims) for d in range(self.npar): ax = self.axisRatios[d] scorebase = self.groundPotential(d) a, b = limsE(d) c, r = (a + b) / 2., (a - b) / 2. n1dx = int(np.ceil((n1d * 4. / np.pi / ax) ** .5)) n1dy = int(np.ceil(n1d * 4. / np.pi / n1dx)) even, Z = True, [] while len(Z) < n1d: Xdx, Xdy = np.meshgrid( quadraturePointsGenerate(n1dx, self.kind), quadraturePointsGenerate(n1dy, self.kind)) Z = Xdx.flatten() + 1.j * ax * Xdy.flatten() ptscore = potential(Z, self.normalFoci(d)) Z = Z[ptscore <= scorebase] if even: n1dx += 1 else: n1dy += 1 xds[d] = c + r * Z nds[d] = len(Z) nleft, nright = 1, np.prod(nds) xmat = np.empty((nright, self.npar), dtype = np.complex) for d in range(self.npar): nright //= nds[d] xmat[:, d] = kroneckerer(xds[d], nleft, nright) nleft *= nds[d] if len(xmat) > 1 and reorder: fejerOrdering = [len(xmat) - 1] + lowDiscrepancy(len(xmat) - 1) xmat = xmat[fejerOrdering, :] - return self.mapParameterList(xmat, "B")[0] + return self.mapParameterList(xmat, "B") diff --git a/rrompy/parameter/parameter_sampling/shape/random_box_sampler.py b/rrompy/parameter/parameter_sampling/shape/random_box_sampler.py index 87bfe81..cc48aea 100644 --- a/rrompy/parameter/parameter_sampling/shape/random_box_sampler.py +++ b/rrompy/parameter/parameter_sampling/shape/random_box_sampler.py @@ -1,57 +1,56 @@ # Copyright (C) 2018 by the RROMPy authors # # This file is part of RROMPy. # # RROMPy is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # RROMPy is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with RROMPy. If not, see . # import numpy as np from .generic_shape_random_sampler import GenericShapeRandomSampler from rrompy.utilities.numerical import haltonGenerate, sobolGenerate from rrompy.utilities.base.types import paramList -from rrompy.parameter import checkParameterList __all__ = ['RandomBoxSampler'] class RandomBoxSampler(GenericShapeRandomSampler): """Generator of (quasi-)random sample points on boxes.""" def generatePoints(self, n:int, reorder : bool = True) -> paramList: """Array of quadrature points.""" nEff = int(np.ceil(n * np.prod( [max(x, 1. / x) for x in self.axisRatios]))) xmat2 = [] while len(xmat2) < n: if self.kind == "UNIFORM": np.random.seed(self.seed) xmat2 = np.random.uniform(size = (nEff, 2 * self.npar)) elif self.kind == "HALTON": xmat2 = haltonGenerate(2 * self.npar, nEff, self.seed) else: xmat2 = sobolGenerate(2 * self.npar, nEff, self.seed) for d in range(self.npar): ax = self.axisRatios[d] if ax <= 1.: xmat2 = xmat2[xmat2[:, 2 * d + 1] <= ax] else: xmat2 = xmat2[xmat2[:, 2 * d] <= 1. / ax] xmat2[:, 2 * d : 2 * d + 2] *= ax nEff += 1 xmat = np.empty((n, self.npar), dtype = np.complex) - limsE = self.mapParameterList(self.lims)[0] + limsE = self.mapParameterList(self.lims) for d in range(self.npar): a, b = limsE(d) xmat[:, d] = a + (b - a) * (xmat2[: n, 2 * d] + 1.j * self.axisRatios[d] * (xmat2[: n, 2 * d + 1] - .5)) - return self.mapParameterList(xmat, "B")[0] + return self.mapParameterList(xmat, "B") diff --git a/rrompy/parameter/parameter_sampling/shape/random_circle_sampler.py b/rrompy/parameter/parameter_sampling/shape/random_circle_sampler.py index b6ba444..1c237b2 100644 --- a/rrompy/parameter/parameter_sampling/shape/random_circle_sampler.py +++ b/rrompy/parameter/parameter_sampling/shape/random_circle_sampler.py @@ -1,60 +1,59 @@ # Copyright (C) 2018 by the RROMPy authors # # This file is part of RROMPy. # # RROMPy is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # RROMPy is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with RROMPy. If not, see . # import numpy as np from .generic_shape_random_sampler import GenericShapeRandomSampler from rrompy.utilities.numerical import (haltonGenerate, sobolGenerate, potential) from rrompy.utilities.base.types import paramList -from rrompy.parameter import checkParameterList __all__ = ['RandomCircleSampler'] class RandomCircleSampler(GenericShapeRandomSampler): """Generator of (quasi-)random sample points on ellipses.""" def generatePoints(self, n:int, reorder : bool = True) -> paramList: """Array of quadrature points.""" nEff = int(np.ceil(n * (4. / np.pi) ** self.npar * np.prod( [max(x, 1. / x) for x in self.axisRatios]))) xmat2 = [] while len(xmat2) < n: if self.kind == "UNIFORM": np.random.seed(self.seed) xmat2 = np.random.uniform(size = (nEff, 2 * self.npar)) elif self.kind == "HALTON": xmat2 = haltonGenerate(2 * self.npar, nEff, self.seed) else: xmat2 = sobolGenerate(2 * self.npar, nEff, self.seed) xmat2 = xmat2 * 2. - 1. for d in range(self.npar): ax = self.axisRatios[d] if ax > 1.: xmat2[:, 2 * d : 2 * d + 2] *= ax Z = xmat2[:, 2 * d] + 1.j * ax * xmat2[:, 2 * d + 1] ptscore = potential(Z, self.normalFoci(d)) xmat2 = xmat2[ptscore <= self.groundPotential(d)] nEff += 1 xmat = np.empty((n, self.npar), dtype = np.complex) - limsE = self.mapParameterList(self.lims)[0] + limsE = self.mapParameterList(self.lims) for d in range(self.npar): ax = self.axisRatios[d] a, b = limsE(d) c, r = (a + b) / 2., (a - b) / 2. xmat[:, d] = c + r * (xmat2[: n, 2 * d] + 1.j * ax * xmat2[: n, 2 * d + 1]) - return self.mapParameterList(xmat, "B")[0] + return self.mapParameterList(xmat, "B") diff --git a/rrompy/parameter/parameter_sampling/sparse_grid/sparse_grid_sampler.py b/rrompy/parameter/parameter_sampling/sparse_grid/sparse_grid_sampler.py index 1d72cb5..7c5a803 100644 --- a/rrompy/parameter/parameter_sampling/sparse_grid/sparse_grid_sampler.py +++ b/rrompy/parameter/parameter_sampling/sparse_grid/sparse_grid_sampler.py @@ -1,117 +1,115 @@ # Copyright (C) 2018 by the RROMPy authors # # This file is part of RROMPy. # # RROMPy is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # RROMPy is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with RROMPy. If not, see . # from copy import deepcopy as copy from itertools import product import numpy as np -from rrompy.parameter import checkParameterList from rrompy.parameter.parameter_sampling.generic_sampler import GenericSampler from rrompy.utilities.poly_fitting.piecewise_linear import (sparsekinds, sparseMap) from rrompy.utilities.base.types import List, DictAny, paramList from rrompy.utilities.exception_manager import RROMPyException __all__ = ['SparseGridSampler'] class SparseGridSampler(GenericSampler): """Generator of sparse grid sample points.""" def __init__(self, lims:paramList, kind : str = "UNIFORM", parameterMap : DictAny = 1.): super().__init__(lims = lims, parameterMap = parameterMap) self.kind = kind self.reset() def __str__(self) -> str: return "{}[{}_{}]_{}".format(self.name(), self.lims[0], self.lims[1], self.kind) @property def npoints(self): """Number of points.""" return len(self.points) @property def kind(self): """Value of kind.""" return self._kind @kind.setter def kind(self, kind): if kind.upper() not in [sk.split("_")[2] + extra for sk, extra in product(sparsekinds, ["", "-NOBOUNDARY"])]: raise RROMPyException("Generator kind not recognized.") self._kind = kind.upper() self._noBoundary = "NOBOUNDARY" in self._kind def reset(self): - limsE = self.mapParameterList(self.lims)[0] + limsE = self.mapParameterList(self.lims) centerEff = .5 * (limsE[0] + limsE[1]) - self.points = self.mapParameterList(centerEff, "B")[0] + self.points = self.mapParameterList(centerEff, "B") self.depth = np.zeros((1, self.npar), dtype = int) self.deltadepth = np.zeros(1, dtype = int) def refine(self, active : List[int] = None) -> List[int]: if active is None: active = np.arange(self.npoints) - limsX = self.mapParameterList(self.lims)[0].data.T + limsX = self.mapParameterList(self.lims).data.T newIdxs = [] for act in active: point, dpt = self.points[act], self.depth[act] exhausted = False while not exhausted: ddp = self.deltadepth[act] for jdelta in range(self.npar): for signdelta in [-1., 1.]: Pointj = sparseMap( - self.mapParameterList(point)[0](0, jdelta), - limsX[jdelta], self.kind, False) + self.mapParameterList(point[jdelta], + idx = [jdelta])(0, 0), + limsX[jdelta], self.kind, False) if not self._noBoundary and dpt[jdelta] == 1: Centerj = sparseMap( - self.mapParameterList(self.points[0])[0](0, jdelta), - limsX[jdelta], self.kind, False) + self.mapParameterList(self.points[0][jdelta], + idx = [jdelta])(0, 0), + limsX[jdelta], self.kind, False) gradj = Pointj - Centerj if signdelta * gradj > 0: continue pointj = copy(point) Pointj = Pointj + .5 ** (dpt[jdelta] + ddp + self._noBoundary) * signdelta - pointjE = np.empty(self.npar, dtype = point.dtype) - pointjE[:] = np.nan - pointjE[jdelta] = sparseMap(Pointj, limsX[jdelta], - self.kind) - pointj[jdelta] = self.mapParameterList(pointjE, - "B")[0](0, jdelta) + pointj[jdelta] = self.mapParameterList( + sparseMap(Pointj, limsX[jdelta], self.kind), + "B", [jdelta])(0, 0) dist = np.sum(np.abs(self.points.data - pointj.reshape(1, -1)), axis = 1) samePt = np.where(np.isclose(dist, 0.))[0] if len(samePt) > 0: if samePt[0] in newIdxs: exhausted = True continue newIdxs += [self.npoints] self.points.append(pointj) self.depth = np.append(self.depth, [dpt], 0) self.depth[-1, jdelta] += 1 + ddp self.deltadepth = np.append(self.deltadepth, [0]) exhausted = True self.deltadepth[act] += 1 return newIdxs def generatePoints(self, n:int, reorder = None) -> paramList: if self.npoints > n: self.reset() idx = np.arange(self.npoints) while self.npoints < n: idx = self.refine(idx) return self.points