diff --git a/rrompy/parameter/parameter_sampling/__init__.py b/rrompy/parameter/parameter_sampling/__init__.py index 12e89ee..d395bd7 100644 --- a/rrompy/parameter/parameter_sampling/__init__.py +++ b/rrompy/parameter/parameter_sampling/__init__.py @@ -1,35 +1,40 @@ # 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 .generic_sampler import GenericSampler -from .fft_sampler import FFTSampler +from .generic_quadrature_sampler import GenericQuadratureSampler from .manual_sampler import ManualSampler -from .quadrature_sampler import QuadratureSampler -from .quadrature_sampler_total import QuadratureSamplerTotal -from .random_sampler import RandomSampler +from .segment import QuadratureSampler, QuadratureSamplerTotal, RandomSampler +from .shape import (FFTSampler, QuadratureBoxSampler, QuadratureCircleSampler, + RandomBoxSampler, RandomCircleSampler) __all__ = [ 'GenericSampler', - 'FFTSampler', + 'GenericQuadratureSampler', 'ManualSampler', 'QuadratureSampler', 'QuadratureSamplerTotal', - 'RandomSampler' + 'RandomSampler', + 'FFTSampler', + 'QuadratureBoxSampler', + 'QuadratureCircleSampler', + 'RandomBoxSampler', + 'RandomCircleSampler' ] diff --git a/rrompy/parameter/parameter_sampling/random_sampler.py b/rrompy/parameter/parameter_sampling/generic_quadrature_sampler.py similarity index 55% copy from rrompy/parameter/parameter_sampling/random_sampler.py copy to rrompy/parameter/parameter_sampling/generic_quadrature_sampler.py index 835c839..1fa92dc 100644 --- a/rrompy/parameter/parameter_sampling/random_sampler.py +++ b/rrompy/parameter/parameter_sampling/generic_quadrature_sampler.py @@ -1,71 +1,51 @@ # 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_sampler import GenericSampler -from rrompy.utilities.numerical import haltonGenerate, sobolGenerate from rrompy.utilities.base.types import List, paramList from rrompy.utilities.exception_manager import RROMPyException -from rrompy.parameter import checkParameterList -__all__ = ['RandomSampler'] +__all__ = ['GenericQuadratureSampler'] -class RandomSampler(GenericSampler): +class GenericQuadratureSampler(GenericSampler): """Generator of quadrature sample points.""" - allowedKinds = ["UNIFORM", "HALTON", "SOBOL"] - def __init__(self, lims:paramList, kind : str = "UNIFORM", - scalingExp : List[float] = None, seed : int = 42): + scalingExp : List[float] = None): super().__init__(lims = lims, scalingExp = scalingExp) + self._allowedKinds = ["UNIFORM", "CHEBYSHEV", "EXTENDEDCHEBYSHEV", + "GAUSSLEGENDRE", "EXTENDEDGAUSSLEGENDRE"] self.kind = kind - self.seed = seed - + def __str__(self) -> str: return "{}_{}".format(super().__str__(), self.kind) def __repr__(self) -> str: return self.__str__() + " at " + hex(id(self)) @property def kind(self): """Value of kind.""" return self._kind @kind.setter def kind(self, kind): - if kind.upper() not in self.allowedKinds: + kind = kind.upper().strip().replace(" ","") + if kind not in self._allowedKinds: raise RROMPyException("Generator kind not recognized.") - self._kind = kind.upper() - - 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) - for d in range(self.npar): - a = self.lims(0, d) ** self.scalingExp[d] - b = self.lims(1, d) ** self.scalingExp[d] - xmat[:, d] = a + (b - a) * xmat[:, d] - xmat[:, d] **= 1. / self.scalingExp[d] - x = checkParameterList(xmat, self.npar)[0] - return x + self._kind = kind diff --git a/rrompy/parameter/parameter_sampling/manual_sampler.py b/rrompy/parameter/parameter_sampling/manual_sampler.py index b22f7f8..2132633 100644 --- a/rrompy/parameter/parameter_sampling/manual_sampler.py +++ b/rrompy/parameter/parameter_sampling/manual_sampler.py @@ -1,60 +1,60 @@ # 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 copy import deepcopy as copy -from .generic_sampler import GenericSampler +from rrompy.parameter.parameter_sampling.generic_sampler import GenericSampler from rrompy.utilities.base.types import List, paramList from rrompy.parameter import checkParameterList __all__ = ['ManualSampler'] class ManualSampler(GenericSampler): """Manual generator of sample points.""" def __init__(self, lims:paramList, points:paramList, scalingExp : List[float] = None): super().__init__(lims = lims, scalingExp = scalingExp) self.points = points @property def points(self): """Value of points.""" return self._points @points.setter def points(self, points): points = checkParameterList(points, self.npar)[0] self._points = points def __str__(self) -> str: return "{}[{}]".format(self.name(), "_".join(map(str, self.points))) def __repr__(self) -> str: return self.__str__() + " at " + hex(id(self)) def generatePoints(self, n:int, reorder : bool = True) -> paramList: """Array of sample points.""" if n > len(self.points): pts = copy(self.points) for j in range(int(np.ceil(n / len(self.points)))): pts.append(self.points) else: pts = self.points x = checkParameterList(pts[list(range(n))], self.npar)[0] return x diff --git a/rrompy/parameter/parameter_sampling/__init__.py b/rrompy/parameter/parameter_sampling/segment/__init__.py similarity index 83% copy from rrompy/parameter/parameter_sampling/__init__.py copy to rrompy/parameter/parameter_sampling/segment/__init__.py index 12e89ee..66c73f8 100644 --- a/rrompy/parameter/parameter_sampling/__init__.py +++ b/rrompy/parameter/parameter_sampling/segment/__init__.py @@ -1,35 +1,29 @@ # 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 .generic_sampler import GenericSampler -from .fft_sampler import FFTSampler -from .manual_sampler import ManualSampler from .quadrature_sampler import QuadratureSampler from .quadrature_sampler_total import QuadratureSamplerTotal from .random_sampler import RandomSampler __all__ = [ - 'GenericSampler', - 'FFTSampler', - 'ManualSampler', 'QuadratureSampler', 'QuadratureSamplerTotal', 'RandomSampler' ] diff --git a/rrompy/parameter/parameter_sampling/quadrature_sampler.py b/rrompy/parameter/parameter_sampling/segment/quadrature_sampler.py similarity index 50% rename from rrompy/parameter/parameter_sampling/quadrature_sampler.py rename to rrompy/parameter/parameter_sampling/segment/quadrature_sampler.py index fe65111..043ad36 100644 --- a/rrompy/parameter/parameter_sampling/quadrature_sampler.py +++ b/rrompy/parameter/parameter_sampling/segment/quadrature_sampler.py @@ -1,86 +1,52 @@ # 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_sampler import GenericSampler -from rrompy.utilities.base.types import List, paramList -from rrompy.utilities.exception_manager import RROMPyException -from rrompy.utilities.numerical import lowDiscrepancy, kroneckerer +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(GenericSampler): +class QuadratureSampler(GenericQuadratureSampler): """Generator of quadrature sample points.""" - _allowedKinds = ["UNIFORM", "CHEBYSHEV", "EXTENDEDCHEBYSHEV", - "GAUSSLEGENDRE", "EXTENDEDGAUSSLEGENDRE"] - - def __init__(self, lims:paramList, kind : str = "UNIFORM", - scalingExp : List[float] = None): - super().__init__(lims = lims, scalingExp = scalingExp) - self.kind = kind - - def __str__(self) -> str: - return "{}_{}".format(super().__str__(), self.kind) - - def __repr__(self) -> str: - return self.__str__() + " at " + hex(id(self)) - - @property - def kind(self): - """Value of kind.""" - return self._kind - @kind.setter - def kind(self, kind): - if kind.upper() not in self._allowedKinds: - raise RROMPyException("Generator kind not recognized.") - self._kind = kind.upper() - 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) for d in range(self.npar): nright //= n1d a = self.lims(0, d) ** self.scalingExp[d] b = self.lims(1, d) ** self.scalingExp[d] c, r = (a + b) / 2., (a - b) / 2. - if self.kind == "UNIFORM": - xd = np.linspace(a, b, n1d) - elif self.kind in ["CHEBYSHEV", "EXTENDEDCHEBYSHEV"]: - nodes = np.polynomial.chebyshev.chebgauss(n1d)[0] - if n1d > 1 and self.kind == "EXTENDEDCHEBYSHEV": - nodes /= nodes[0] - xd = c + r * nodes - elif self.kind in ["GAUSSLEGENDRE", "EXTENDEDGAUSSLEGENDRE"]: - nodes = np.polynomial.legendre.leggauss(n1d)[0][::-1] - if n1d > 1 and self.kind == "EXTENDEDCHEBYSHEV": - nodes /= nodes[0] - xd = c + r * nodes + xd = c + r * quadraturePointsGenerate(n1d, self.kind) xd **= 1. / self.scalingExp[d] 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, :] x = checkParameterList(xmat, self.npar)[0] return x diff --git a/rrompy/parameter/parameter_sampling/quadrature_sampler_total.py b/rrompy/parameter/parameter_sampling/segment/quadrature_sampler_total.py similarity index 100% rename from rrompy/parameter/parameter_sampling/quadrature_sampler_total.py rename to rrompy/parameter/parameter_sampling/segment/quadrature_sampler_total.py diff --git a/rrompy/parameter/parameter_sampling/random_sampler.py b/rrompy/parameter/parameter_sampling/segment/random_sampler.py similarity index 95% copy from rrompy/parameter/parameter_sampling/random_sampler.py copy to rrompy/parameter/parameter_sampling/segment/random_sampler.py index 835c839..301d852 100644 --- a/rrompy/parameter/parameter_sampling/random_sampler.py +++ b/rrompy/parameter/parameter_sampling/segment/random_sampler.py @@ -1,71 +1,71 @@ # 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_sampler import GenericSampler +from rrompy.parameter.parameter_sampling.generic_sampler import GenericSampler from rrompy.utilities.numerical import haltonGenerate, sobolGenerate from rrompy.utilities.base.types import List, paramList from rrompy.utilities.exception_manager import RROMPyException from rrompy.parameter import checkParameterList __all__ = ['RandomSampler'] class RandomSampler(GenericSampler): - """Generator of quadrature sample points.""" + """Generator of (quasi-)random sample points.""" allowedKinds = ["UNIFORM", "HALTON", "SOBOL"] def __init__(self, lims:paramList, kind : str = "UNIFORM", scalingExp : List[float] = None, seed : int = 42): super().__init__(lims = lims, scalingExp = scalingExp) self.kind = kind self.seed = seed def __str__(self) -> str: return "{}_{}".format(super().__str__(), self.kind) def __repr__(self) -> str: return self.__str__() + " at " + hex(id(self)) @property def kind(self): """Value of kind.""" return self._kind @kind.setter def kind(self, kind): if kind.upper() not in self.allowedKinds: raise RROMPyException("Generator kind not recognized.") self._kind = kind.upper() 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) for d in range(self.npar): a = self.lims(0, d) ** self.scalingExp[d] b = self.lims(1, d) ** self.scalingExp[d] xmat[:, d] = a + (b - a) * xmat[:, d] xmat[:, d] **= 1. / self.scalingExp[d] x = checkParameterList(xmat, self.npar)[0] return x diff --git a/rrompy/parameter/parameter_sampling/__init__.py b/rrompy/parameter/parameter_sampling/shape/__init__.py similarity index 59% copy from rrompy/parameter/parameter_sampling/__init__.py copy to rrompy/parameter/parameter_sampling/shape/__init__.py index 12e89ee..86a8d66 100644 --- a/rrompy/parameter/parameter_sampling/__init__.py +++ b/rrompy/parameter/parameter_sampling/shape/__init__.py @@ -1,35 +1,37 @@ # 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 .generic_sampler import GenericSampler +from .generic_shape_sampler import GenericShapeSampler +from .generic_shape_quadrature_sampler import GenericShapeQuadratureSampler from .fft_sampler import FFTSampler -from .manual_sampler import ManualSampler -from .quadrature_sampler import QuadratureSampler -from .quadrature_sampler_total import QuadratureSamplerTotal -from .random_sampler import RandomSampler +from .quadrature_box_sampler import QuadratureBoxSampler +from .quadrature_circle_sampler import QuadratureCircleSampler +from .random_box_sampler import RandomBoxSampler +from .random_circle_sampler import RandomCircleSampler __all__ = [ - 'GenericSampler', + 'GenericShapeSampler', + 'GenericShapeQuadratureSampler', 'FFTSampler', - 'ManualSampler', - 'QuadratureSampler', - 'QuadratureSamplerTotal', - 'RandomSampler' + 'QuadratureBoxSampler', + 'QuadratureCircleSampler', + 'RandomBoxSampler', + 'RandomCircleSampler' ] diff --git a/rrompy/parameter/parameter_sampling/fft_sampler.py b/rrompy/parameter/parameter_sampling/shape/fft_sampler.py similarity index 85% copy from rrompy/parameter/parameter_sampling/fft_sampler.py copy to rrompy/parameter/parameter_sampling/shape/fft_sampler.py index bd6a9b7..1104159 100644 --- a/rrompy/parameter/parameter_sampling/fft_sampler.py +++ b/rrompy/parameter/parameter_sampling/shape/fft_sampler.py @@ -1,48 +1,51 @@ # 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_sampler import GenericSampler +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(GenericSampler): +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) for d in range(self.npar): nright //= n1d a = self.lims(0, d) ** self.scalingExp[d] b = self.lims(1, d) ** self.scalingExp[d] c, r = (a + b) / 2., (a - b) / 2. - xd = c + r * np.exp(1.j * np.linspace(0, 2 * np.pi, n1d + 1)[:-1]) + 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 xd **= 1. / self.scalingExp[d] if n1d > 1 and reorder: fejerOrdering = [n1d - 1] + lowDiscrepancy(n1d - 1) xd = xd[fejerOrdering] xmat[:, d] = kroneckerer(xd, nleft, nright) nleft *= n1d x = checkParameterList(xmat, self.npar)[0] return x diff --git a/rrompy/parameter/parameter_sampling/shape/generic_shape_quadrature_sampler.py b/rrompy/parameter/parameter_sampling/shape/generic_shape_quadrature_sampler.py new file mode 100644 index 0000000..35e8e6f --- /dev/null +++ b/rrompy/parameter/parameter_sampling/shape/generic_shape_quadrature_sampler.py @@ -0,0 +1,46 @@ +# 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 List, paramList +from rrompy.utilities.exception_manager import RROMPyAssert + +__all__ = ['GenericShapeQuadratureSampler'] + +class GenericShapeQuadratureSampler(GenericQuadratureSampler): + """Generator of quadrature sample points on shapes.""" + + def __init__(self, lims:paramList, kind : str = "UNIFORM", + scalingExp : List[float] = None, + axisRatios : List[float] = None): + super().__init__(lims = lims, kind = kind, scalingExp = scalingExp) + self.axisRatios = axisRatios + + @property + def axisRatios(self): + """Value of axisRatios.""" + return self._axisRatios + @axisRatios.setter + def axisRatios(self, axisRatios): + if axisRatios is None: + axisRatios = [1.] * self.npar + if not hasattr(axisRatios, "__len__"): axisRatios = [axisRatios] + RROMPyAssert(self.npar, len(axisRatios), "Number of axis ratios terms") + self._axisRatios = [np.abs(x) for x in axisRatios] diff --git a/rrompy/parameter/parameter_sampling/shape/generic_shape_sampler.py b/rrompy/parameter/parameter_sampling/shape/generic_shape_sampler.py new file mode 100644 index 0000000..0179cb1 --- /dev/null +++ b/rrompy/parameter/parameter_sampling/shape/generic_shape_sampler.py @@ -0,0 +1,44 @@ +# 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_sampler import GenericSampler +from rrompy.utilities.base.types import List, paramList +from rrompy.utilities.exception_manager import RROMPyAssert + +__all__ = ['GenericShapeSampler'] + +class GenericShapeSampler(GenericSampler): + """Generator of sample points on boxes or ellipses.""" + + def __init__(self, lims:paramList, scalingExp : List[float] = None, + axisRatios : List[float] = None): + super().__init__(lims = lims, scalingExp = scalingExp) + self.axisRatios = axisRatios + + @property + def axisRatios(self): + """Value of axisRatios.""" + return self._axisRatios + @axisRatios.setter + def axisRatios(self, axisRatios): + if axisRatios is None: + axisRatios = [1.] * self.npar + if not hasattr(axisRatios, "__len__"): axisRatios = [axisRatios] + RROMPyAssert(self.npar, len(axisRatios), "Number of axis ratios terms") + self._axisRatios = [np.abs(x) for x in axisRatios] diff --git a/rrompy/parameter/parameter_sampling/fft_sampler.py b/rrompy/parameter/parameter_sampling/shape/quadrature_box_sampler.py similarity index 57% rename from rrompy/parameter/parameter_sampling/fft_sampler.py rename to rrompy/parameter/parameter_sampling/shape/quadrature_box_sampler.py index bd6a9b7..74aa44f 100644 --- a/rrompy/parameter/parameter_sampling/fft_sampler.py +++ b/rrompy/parameter/parameter_sampling/shape/quadrature_box_sampler.py @@ -1,48 +1,58 @@ # 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_sampler import GenericSampler +from .generic_shape_quadrature_sampler import GenericShapeQuadratureSampler from rrompy.utilities.base.types import paramList -from rrompy.utilities.numerical import lowDiscrepancy, kroneckerer +from rrompy.utilities.numerical import (lowDiscrepancy, kroneckerer, + subsampleQuasiuniform, + quadraturePointsGenerate) from rrompy.parameter import checkParameterList -__all__ = ['FFTSampler'] +__all__ = ['QuadratureBoxSampler'] -class FFTSampler(GenericSampler): - """Generator of FFT-type sample points on scaled roots of unity.""" +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))) nleft, nright = 1, n1d ** self.npar xmat = np.empty((nright, self.npar), dtype = np.complex) for d in range(self.npar): nright //= n1d + ax = self.axisRatios[d] a = self.lims(0, d) ** self.scalingExp[d] b = self.lims(1, d) ** self.scalingExp[d] c, r = (a + b) / 2., (a - b) / 2. - xd = c + r * np.exp(1.j * np.linspace(0, 2 * np.pi, n1d + 1)[:-1]) - xd **= 1. / self.scalingExp[d] - if n1d > 1 and reorder: - fejerOrdering = [n1d - 1] + lowDiscrepancy(n1d - 1) - xd = xd[fejerOrdering] + 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 = subsampleQuasiuniform(Xdx.flatten() + 1.j * ax * Xdy.flatten(), + n1d) + xd = (c + r * Z) ** (1. / self.scalingExp[d]) 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, :] x = checkParameterList(xmat, self.npar)[0] return x + diff --git a/rrompy/parameter/parameter_sampling/shape/quadrature_circle_sampler.py b/rrompy/parameter/parameter_sampling/shape/quadrature_circle_sampler.py new file mode 100644 index 0000000..3d7419f --- /dev/null +++ b/rrompy/parameter/parameter_sampling/shape/quadrature_circle_sampler.py @@ -0,0 +1,66 @@ +# 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, + cutOffDistance, subsampleQuasiuniform, + 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))) + nleft, nright = 1, n1d ** self.npar + xmat = np.empty((nright, self.npar), dtype = np.complex) + for d in range(self.npar): + nright //= n1d + ax = self.axisRatios[d] + focus = (1. + 0.j - ax ** 2.) ** .5 + scorebase = cutOffDistance(np.ones(1), [- focus, focus]) + a = self.lims(0, d) ** self.scalingExp[d] + b = self.lims(1, d) ** self.scalingExp[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 = cutOffDistance(Z, [- focus, focus]) + Z = Z[ptscore <= scorebase] + if even: n1dx += 1 + else: n1dy += 1 + Z = subsampleQuasiuniform(Z, n1d) + xd = (c + r * Z) ** (1. / self.scalingExp[d]) + 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, :] + x = checkParameterList(xmat, self.npar)[0] + return x diff --git a/rrompy/parameter/parameter_sampling/random_sampler.py b/rrompy/parameter/parameter_sampling/shape/random_box_sampler.py similarity index 57% copy from rrompy/parameter/parameter_sampling/random_sampler.py copy to rrompy/parameter/parameter_sampling/shape/random_box_sampler.py index 835c839..db5079b 100644 --- a/rrompy/parameter/parameter_sampling/random_sampler.py +++ b/rrompy/parameter/parameter_sampling/shape/random_box_sampler.py @@ -1,71 +1,86 @@ # 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_sampler import GenericSampler +from .generic_shape_sampler import GenericShapeSampler from rrompy.utilities.numerical import haltonGenerate, sobolGenerate from rrompy.utilities.base.types import List, paramList from rrompy.utilities.exception_manager import RROMPyException from rrompy.parameter import checkParameterList -__all__ = ['RandomSampler'] +__all__ = ['RandomBoxSampler'] -class RandomSampler(GenericSampler): - """Generator of quadrature sample points.""" +class RandomBoxSampler(GenericShapeSampler): + """Generator of (quasi-)random sample points on boxes.""" allowedKinds = ["UNIFORM", "HALTON", "SOBOL"] def __init__(self, lims:paramList, kind : str = "UNIFORM", - scalingExp : List[float] = None, seed : int = 42): - super().__init__(lims = lims, scalingExp = scalingExp) + scalingExp : List[float] = None, + axisRatios : List[float] = None, seed : int = 42): + super().__init__(lims = lims, scalingExp = scalingExp, + axisRatios = axisRatios) self.kind = kind self.seed = seed def __str__(self) -> str: return "{}_{}".format(super().__str__(), self.kind) def __repr__(self) -> str: return self.__str__() + " at " + hex(id(self)) @property def kind(self): """Value of kind.""" return self._kind @kind.setter def kind(self, kind): if kind.upper() not in self.allowedKinds: raise RROMPyException("Generator kind not recognized.") self._kind = kind.upper() 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) + 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) for d in range(self.npar): a = self.lims(0, d) ** self.scalingExp[d] b = self.lims(1, d) ** self.scalingExp[d] - xmat[:, d] = a + (b - a) * xmat[:, d] + xmat[:, d] = a + (b - a) * (xmat2[: n, 2 * d] + + 1.j * self.axisRatios[d] * (xmat2[: n, 2 * d + 1] - .5)) xmat[:, d] **= 1. / self.scalingExp[d] x = checkParameterList(xmat, self.npar)[0] return x - diff --git a/rrompy/parameter/parameter_sampling/random_sampler.py b/rrompy/parameter/parameter_sampling/shape/random_circle_sampler.py similarity index 51% rename from rrompy/parameter/parameter_sampling/random_sampler.py rename to rrompy/parameter/parameter_sampling/shape/random_circle_sampler.py index 835c839..f5fdc26 100644 --- a/rrompy/parameter/parameter_sampling/random_sampler.py +++ b/rrompy/parameter/parameter_sampling/shape/random_circle_sampler.py @@ -1,71 +1,89 @@ # 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_sampler import GenericSampler -from rrompy.utilities.numerical import haltonGenerate, sobolGenerate +from .generic_shape_sampler import GenericShapeSampler +from rrompy.utilities.numerical import (haltonGenerate, sobolGenerate, + cutOffDistance) from rrompy.utilities.base.types import List, paramList from rrompy.utilities.exception_manager import RROMPyException from rrompy.parameter import checkParameterList -__all__ = ['RandomSampler'] +__all__ = ['RandomCircleSampler'] -class RandomSampler(GenericSampler): - """Generator of quadrature sample points.""" +class RandomCircleSampler(GenericShapeSampler): + """Generator of (quasi-)random sample points on ellipses.""" allowedKinds = ["UNIFORM", "HALTON", "SOBOL"] def __init__(self, lims:paramList, kind : str = "UNIFORM", - scalingExp : List[float] = None, seed : int = 42): - super().__init__(lims = lims, scalingExp = scalingExp) + scalingExp : List[float] = None, + axisRatios : List[float] = None, seed : int = 42): + super().__init__(lims = lims, scalingExp = scalingExp, + axisRatios = axisRatios) self.kind = kind self.seed = seed def __str__(self) -> str: return "{}_{}".format(super().__str__(), self.kind) def __repr__(self) -> str: return self.__str__() + " at " + hex(id(self)) @property def kind(self): """Value of kind.""" return self._kind @kind.setter def kind(self, kind): if kind.upper() not in self.allowedKinds: raise RROMPyException("Generator kind not recognized.") self._kind = kind.upper() 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) + 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) + for d in range(self.npar): + ax = self.axisRatios[d] + focus = .5 * (1. + 0.j - ax ** 2.) ** .5 + foci = [- focus + .5 + .5j * ax, focus + .5 + .5j * ax] + scorebase = cutOffDistance(.5j * ax * np.ones(1), foci) + if ax > 1.: xmat2[:, 2 * d : 2 * d + 2] *= ax + Z = xmat2[:, 2 * d] + 1.j * ax * xmat2[:, 2 * d + 1] + ptscore = cutOffDistance(Z, foci) + xmat2 = xmat2[ptscore <= scorebase] + nEff += 1 + xmat = np.empty((n, self.npar), dtype = np.complex) for d in range(self.npar): a = self.lims(0, d) ** self.scalingExp[d] b = self.lims(1, d) ** self.scalingExp[d] - xmat[:, d] = a + (b - a) * xmat[:, d] + xmat[:, d] = a + (b - a) * (xmat2[: n, 2 * d] + + 1.j * self.axisRatios[d] * (xmat2[: n, 2 * d + 1] - .5)) xmat[:, d] **= 1. / self.scalingExp[d] x = checkParameterList(xmat, self.npar)[0] return x - diff --git a/rrompy/utilities/numerical/__init__.py b/rrompy/utilities/numerical/__init__.py index 97172ef..1cf0a1f 100644 --- a/rrompy/utilities/numerical/__init__.py +++ b/rrompy/utilities/numerical/__init__.py @@ -1,76 +1,80 @@ # 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 .custom_pinv import customPInv from .degree import (fullDegreeN, totalDegreeN, reduceDegreeN, fullDegreeSet, totalDegreeSet, degreeTotalToFull, fullDegreeMaxMask, totalDegreeMaxMask) from .factorials import multibinom, multifactorial from .halton import haltonGenerate from .hash_derivative import (nextDerivativeIndices, hashDerivativeToIdx, hashIdxToDerivative) from .kroneckerer import kroneckerer from .low_discrepancy import lowDiscrepancy from .marginalize_poly_list import marginalizePolyList from .nonlinear_eigenproblem import (linearizeDense, eigNonlinearDense, eigvalsNonlinearDense) from .number_theory import squareResonances from .point_matching import (pointMatching, cutOffDistance, angleTable, chordalMetricTable, chordalMetricAdjusted) +from .quadrature_points import quadraturePointsGenerate from .rayleigh_quotient_iteration import rayleighQuotientIteration from .sobol import sobolGenerate +from .subsample_quasiuniform import subsampleQuasiuniform from .tensor_la import dot, solve freepar = None __all__ = [ 'freepar', 'customPInv', 'fullDegreeN', 'totalDegreeN', 'reduceDegreeN', 'fullDegreeSet', 'totalDegreeSet', 'degreeTotalToFull', 'fullDegreeMaxMask', 'totalDegreeMaxMask', 'multibinom', 'multifactorial', 'haltonGenerate', 'nextDerivativeIndices', 'hashDerivativeToIdx', 'hashIdxToDerivative', 'kroneckerer', 'lowDiscrepancy', 'marginalizePolyList', 'linearizeDense', 'eigNonlinearDense', 'eigvalsNonlinearDense', 'squareResonances', 'pointMatching', 'cutOffDistance', 'angleTable', 'chordalMetricTable', 'chordalMetricAdjusted', + 'quadraturePointsGenerate', 'rayleighQuotientIteration', 'sobolGenerate', + 'subsampleQuasiuniform', 'dot', 'solve' ] diff --git a/rrompy/parameter/parameter_sampling/__init__.py b/rrompy/utilities/numerical/quadrature_points.py similarity index 50% copy from rrompy/parameter/parameter_sampling/__init__.py copy to rrompy/utilities/numerical/quadrature_points.py index 12e89ee..4ee186b 100644 --- a/rrompy/parameter/parameter_sampling/__init__.py +++ b/rrompy/utilities/numerical/quadrature_points.py @@ -1,35 +1,36 @@ # 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 .generic_sampler import GenericSampler -from .fft_sampler import FFTSampler -from .manual_sampler import ManualSampler -from .quadrature_sampler import QuadratureSampler -from .quadrature_sampler_total import QuadratureSamplerTotal -from .random_sampler import RandomSampler - -__all__ = [ - 'GenericSampler', - 'FFTSampler', - 'ManualSampler', - 'QuadratureSampler', - 'QuadratureSamplerTotal', - 'RandomSampler' - ] +import numpy as np +from rrompy.utilities.base.types import Np1D +from rrompy.utilities.exception_manager import RROMPyException +__all__ = ['quadraturePointsGenerate'] +def quadraturePointsGenerate(n:int, kind:str) -> Np1D: + kind = kind.upper() + if kind == "UNIFORM": x = np.linspace(-1., 1., n) + else: + if kind in ["CHEBYSHEV", "EXTENDEDCHEBYSHEV"]: + x = np.polynomial.chebyshev.chebgauss(n)[0][::-1] + elif kind in ["GAUSSLEGENDRE", "EXTENDEDGAUSSLEGENDRE"]: + x = np.polynomial.legendre.leggauss(n)[0] + else: + raise RROMPyException("Quadrature kind not recognized.") + if n > 1 and kind[: 8] == "EXTENDED": x /= x[-1] + return x diff --git a/rrompy/parameter/parameter_sampling/__init__.py b/rrompy/utilities/numerical/subsample_quasiuniform.py similarity index 52% copy from rrompy/parameter/parameter_sampling/__init__.py copy to rrompy/utilities/numerical/subsample_quasiuniform.py index 12e89ee..dc1ff80 100644 --- a/rrompy/parameter/parameter_sampling/__init__.py +++ b/rrompy/utilities/numerical/subsample_quasiuniform.py @@ -1,35 +1,37 @@ # 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 .generic_sampler import GenericSampler -from .fft_sampler import FFTSampler -from .manual_sampler import ManualSampler -from .quadrature_sampler import QuadratureSampler -from .quadrature_sampler_total import QuadratureSamplerTotal -from .random_sampler import RandomSampler - -__all__ = [ - 'GenericSampler', - 'FFTSampler', - 'ManualSampler', - 'QuadratureSampler', - 'QuadratureSamplerTotal', - 'RandomSampler' - ] +import numpy as np +from .low_discrepancy import lowDiscrepancy +from rrompy.utilities.base.types import Np1D +from rrompy.utilities.exception_manager import RROMPyException +__all__ = ['subsampleQuasiuniform'] +def subsampleQuasiuniform(x:Np1D, n:int) -> Np1D: + N = len(x) + delta = N - n + if delta < 0: raise RROMPyException("Sequence too short.") + if delta == 0: return x + stride = int(np.floor((N + 1) / (delta + 1))) + remove = np.arange(stride - 1, N, stride) + if delta < len(remove): + remove = remove[lowDiscrepancy(len(remove))[: delta]] + keep = np.ones(N, dtype = bool) + keep[remove] = False + return x[keep]