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 9f62f2c..f130eec 100644
--- a/rrompy/parameter/parameter_sampling/sparse_grid/sparse_grid_sampler.py
+++ b/rrompy/parameter/parameter_sampling/sparse_grid/sparse_grid_sampler.py
@@ -1,116 +1,112 @@
# 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 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, paramList
from rrompy.utilities.numerical import lowDiscrepancy
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",
scalingExp : List[float] = None):
super().__init__(lims = lims, scalingExp = scalingExp)
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 sparsekinds:
+ if kind.upper() not in [sk.split("_")[2] for sk in sparsekinds]:
raise RROMPyException("Generator kind not recognized.")
self._kind = kind.upper()
def reset(self):
centerEff = .5 * (self.lims[0] ** self.scalingExp
+ self.lims[1] ** self.scalingExp)
self.points = checkParameterList(centerEff ** (1. / self.scalingExp),
self.npar)[0]
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.lims(j) ** self.scalingExp[j] for j in range(self.npar)]
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(
point[jdelta] ** self.scalingExp[jdelta],
limsX[jdelta], self.kind, False)
if dpt[jdelta] == 1:
Centerj = sparseMap(
self.points(0, jdelta) ** self.scalingExp[jdelta],
limsX[jdelta], self.kind, False)
gradj = Pointj - Centerj
if signdelta * gradj > 0:
continue
pointj = copy(point)
Pointj = Pointj + .5 ** (dpt[jdelta] + ddp) * signdelta
pointj[jdelta] = sparseMap(Pointj, limsX[jdelta],
self.kind) ** (1.
/ self.scalingExp[jdelta])
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 : bool = True) -> paramList:
+ 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)
- x = self.points
- if self.npoints > 1 and reorder:
- fejerOrdering = lowDiscrepancy(self.npoints)
- x = checkParameterList(x.data[fejerOrdering, :], self.npar)[0]
- return x
+ return self.points
diff --git a/rrompy/utilities/poly_fitting/piecewise_linear/base.py b/rrompy/utilities/poly_fitting/piecewise_linear/base.py
index fc55c42..112234a 100644
--- a/rrompy/utilities/poly_fitting/piecewise_linear/base.py
+++ b/rrompy/utilities/poly_fitting/piecewise_linear/base.py
@@ -1,41 +1,41 @@
# 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.utilities.base.types import Np1D, Tuple
from rrompy.utilities.exception_manager import RROMPyException
__all__ = ['sparsekinds', 'sparseMap']
-sparsekinds = ["UNIFORM", "LOBATTO"]
+sparsekinds = ["PIECEWISE_LINEAR_" + k for k in ["UNIFORM", "LOBATTO"]]
def sparseMap(x:Np1D, lims:Tuple[np.complex, np.complex], kind:str,
forward : bool = True) -> Np1D:
"""forward: U([-1, 1]) -> lims"""
- kind = kind.upper().strip().replace(" ", "")
+ kind = kind.upper().strip().replace(" ", "").split("_")[-1]
if kind == "UNIFORM":
if forward: return .5 * ((lims[-1] - lims[0]) * x + lims[0] + lims[-1])
return np.real((2. * x - lims[0] - lims[-1]) / (lims[-1] - lims[0]))
elif kind == "LOBATTO":
if forward:
x0 = np.cos(.5 * np.pi * (1. - x))
return sparseMap(x0, lims, "UNIFORM", True)
x0 = sparseMap(x, lims, "UNIFORM", False)
return 1. - 2. / np.pi * np.arccos(np.clip(x0, -1., 1.))
else:
raise RROMPyException("Sparse map kind not recognized.")
diff --git a/rrompy/utilities/poly_fitting/piecewise_linear/kernel.py b/rrompy/utilities/poly_fitting/piecewise_linear/kernel.py
index eb643d8..1942660 100644
--- a/rrompy/utilities/poly_fitting/piecewise_linear/kernel.py
+++ b/rrompy/utilities/poly_fitting/piecewise_linear/kernel.py
@@ -1,63 +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 .base import sparseMap
from rrompy.utilities.base.types import Np1D, Np2D, paramList
from rrompy.utilities.exception_manager import RROMPyException
from rrompy.parameter import checkParameterList
__all__ = ['hatFunction', 'val', 'vander']
def hatFunctionRef(x:Np1D, supp:float, depth:int, kind:str) -> Np1D:
if depth < 0: y = np.zeros_like(x)
elif depth == 0: y = np.ones_like(x)
elif depth == 1:
if not np.isclose(np.abs(supp), 1.):
raise RROMPyException(("Wrong depth. Depth 1 points must be on "
"boundary."))
y = np.array(np.sign(supp) * x)
else:
width = .5 ** (depth - 1.)
if np.abs(supp) + width > 1. + .25 * width:
raise RROMPyException(("Wrong depth or support point. Support "
"point too close to boundary."))
y = np.array(1. - np.abs(x - supp) / width)
return np.clip(y, 0., 1., y)
def hatFunction(x:paramList, supportPoints:paramList, depths:Np2D,
kind:str, lims:paramList) -> Np2D:
x = checkParameterList(x)[0]
supportPoints = checkParameterList(supportPoints, x.shape[1])[0]
lims = checkParameterList(lims, x.shape[1])[0]
res = np.ones((len(supportPoints), len(x)))
for d in range(x.shape[1]):
x0 = sparseMap(x(d), lims(d), kind, False)
for j in range(len(supportPoints)):
supp = sparseMap(supportPoints(j, d), lims(d), kind, False)
res[j] *= hatFunctionRef(x0, supp, depths[j, d], kind)
return res.T
def vander(supportPoints:paramList, depths:Np2D, kind:str,
lims:paramList) -> Np2D:
return hatFunction(supportPoints, supportPoints, depths, kind, lims)
def val(x:paramList, c:Np2D, supportPoints:paramList, depths:Np2D,
kind:str, lims:paramList) -> Np2D:
van = hatFunction(x, supportPoints, depths, kind, lims)
- return np.tensordot(van, c, 1)
+ return np.tensordot(c, van, (0, -1))
diff --git a/rrompy/utilities/poly_fitting/piecewise_linear/piecewise_linear_interpolator.py b/rrompy/utilities/poly_fitting/piecewise_linear/piecewise_linear_interpolator.py
index 25a220c..164b19f 100644
--- a/rrompy/utilities/poly_fitting/piecewise_linear/piecewise_linear_interpolator.py
+++ b/rrompy/utilities/poly_fitting/piecewise_linear/piecewise_linear_interpolator.py
@@ -1,101 +1,101 @@
# 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 rrompy.utilities.base.types import (List, ListAny, DictAny, Np1D, Np2D,
paramList)
from rrompy.utilities.poly_fitting.interpolator import GenericInterpolator
from rrompy.utilities.poly_fitting.custom_fit import customFit
from .kernel import vander, val
from rrompy.utilities.numerical import dot
from rrompy.utilities.exception_manager import RROMPyException, RROMPyAssert
from rrompy.parameter import checkParameterList
__all__ = ['PiecewiseLinearInterpolator']
class PiecewiseLinearInterpolator(GenericInterpolator):
def __init__(self, other = None):
if other is None: return
self.support = other.support
self.lims = other.lims
self.coeffs = other.coeffs
self.depths = other.depths
self.npar = other.npar
self.kind = other.kind
@property
def shape(self):
sh = self.coeffs.shape[1 :] if self.coeffs.ndim > 1 else 1
return sh
def __call__(self, mu:paramList, der : List[int] = None,
scl : Np1D = None):
if der is not None and np.sum(der) > 0:
raise RROMPyException(("Cannot take derivatives of piecewise "
"linear function."))
return val(mu, self.coeffs, self.support, self.depths, self.kind,
self.lims)
def __copy__(self):
- return RadialBasisInterpolator(self)
+ return PiecewiseLinearInterpolator(self)
def __deepcopy__(self, memo):
- other = RadialBasisInterpolator()
+ other = PiecewiseLinearInterpolator()
(other.support, other.lims, other.coeffs, other.depths, other.npar,
other.kind) = copy((self.support, self.lims, self.coeffs, self.depths,
self.npar, self.kind), memo)
return other
def postmultiplyTensorize(self, A:Np2D):
RROMPyAssert(A.shape[0], self.shape[-1], "Shape of output")
self.coeffs = dot(self.coeffs, A)
def pad(self, nleft : List[int] = None, nright : List[int] = None):
if nleft is None: nleft = [0] * len(self.shape)
if nright is None: nright = [0] * len(self.shape)
if not hasattr(nleft, "__len__"): nleft = [nleft]
if not hasattr(nright, "__len__"): nright = [nright]
RROMPyAssert(len(self.shape), len(nleft), "Shape of output")
RROMPyAssert(len(self.shape), len(nright), "Shape of output")
padwidth = [(0, 0)] + [(l, r) for l, r in zip(nleft, nright)]
self.coeffs = np.pad(self.coeffs, padwidth, "constant",
constant_values = (0., 0.))
padwidth = [(0, 0)] * (self.npar - 1) + padwidth
def setupByInterpolation(self, support:paramList, values:ListAny,
lims:paramList, depths:Np2D,
- kind : str = "UNIFORM", verbose : bool = True,
- fitCoeffs : DictAny = {}):
+ kind : str = "PIECEWISE_LINEAR_UNIFORM",
+ verbose : bool = True, fitCoeffs : DictAny = {}):
support = checkParameterList(support)[0]
self.support = copy(support)
self.npar = support.shape[1]
lims = checkParameterList(lims, self.npar)[0]
self.lims = copy(lims)
self.depths = copy(depths)
self.kind = kind
values = values.reshape(values.shape[0], -1)
van = vander(support, depths, kind, lims)
fitOut = customFit(van, values, full = True, **fitCoeffs)
if verbose:
msg = ("Fitting {} samples through piecewise linear "
"interpolator... Conditioning of system: {:.4e}.").format(
len(support), fitOut[1][2][0] / fitOut[1][2][-1])
else: msg = None
self.coeffs = fitOut[0]
return fitOut[1][1] == van.shape[1], msg