# Path: imusim/maths/vector_splines.py
# class UnivariateVectorSpline(Spline):
#     """
#     Model of a vector function of a single variable using spline fitting.
# 
#     The implementation uses an independent L{UnivariateSpline} for each
#     component of the vector function.
#     """
#     def __init__(self, x, y, **kwargs):
#         """
#         Construct vector spline.
# 
#         @param x: Length N, monotonically increasing sequence of input values.
#         @param y: MxN L{np.ndarray} of output values.
#         @param kwargs: Additional parameters passed to L{UnivariateSpline}.
#         """
#         self.splines = [UnivariateSpline(x, yi, **kwargs) for yi in y]
# 
#     def __call__(self,x,n=0):
#         """
#         Evaluate the n-th derivative of the function at input value(s) x.
#         """
#         return np.vstack([s(x, n) for s in self.splines])
# 
#     @property
#     def validFrom(self):
#         return max([s.validFrom for s in self.splines])
# 
#     @property
#     def validTo(self):
#         return min([s.validTo for s in self.splines])
# 
# Path: imusim/maths/vector_splines.py
# class PartialInputVectorSpline(PartialInputSpline):
#     """
#     Piecewise vector spline allowing for undefined regions in output domain.
#     """
#     _splineClass = UnivariateVectorSpline
# 
#     def __init__(self, x, y, **kwargs):
#         PartialInputSpline.__init__(self, x, y, **kwargs)
#         self._dims = np.shape(y)[0]
# 
#     def _validity(self, y):
#         return vectors.validity(y)
# 
#     def _output(self, x, conditions, results, undefined):
#         out = np.empty((self._dims, len(np.atleast_1d(x))))
#         for cond, result in izip(conditions, results):
#             out[:,cond] = result
#         out[:,undefined] = np.nan
#         return out


from imusim.maths.splines import Spline
from imusim.maths.vector_splines import UnivariateVectorSpline
from imusim.maths.vector_splines import PartialInputVectorSpline
from imusim.testing.random_data import randomTimeSequence
from imusim.testing.random_data import randomPositionSequence
from imusim.testing.random_data import randomValidity, invalidate
from numpy.testing import assert_almost_equal
import numpy as np
#
# IMUSim 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with IMUSim.  If not, see <http://www.gnu.org/licenses/>.


def checkVectorSpline(splineClass, x, y, order):
    try:
        spline = splineClass(x, y, order=order)
        ys = spline(x)
        splines = spline.splines if isinstance(spline, PartialInputVectorSpline) else [spline]
        valid = np.array(
            np.sum(((x >= spline.validFrom) & (x <= spline.validTo) for spline in splines)),
            dtype=bool)
        assert_almost_equal(y[:,valid], ys[:,valid])
    except Spline.InsufficientPointsError:
        pass

def testVectorSpline():
    for order in (1, 3, 5):
        for i in range(10):
            x = randomTimeSequence()
            y = randomPositionSequence(x)
            yield checkVectorSpline, UnivariateVectorSpline, x, y, order
            validity = randomValidity(x)
            yn = invalidate(y, validity)

# Path: imusim/maths/vector_splines.py
# class UnivariateVectorSpline(Spline):
#     """
#     Model of a vector function of a single variable using spline fitting.
# 
#     The implementation uses an independent L{UnivariateSpline} for each
#     component of the vector function.
#     """
#     def __init__(self, x, y, **kwargs):
#         """
#         Construct vector spline.
# 
#         @param x: Length N, monotonically increasing sequence of input values.
#         @param y: MxN L{np.ndarray} of output values.
#         @param kwargs: Additional parameters passed to L{UnivariateSpline}.
#         """
#         self.splines = [UnivariateSpline(x, yi, **kwargs) for yi in y]
# 
#     def __call__(self,x,n=0):
#         """
#         Evaluate the n-th derivative of the function at input value(s) x.
#         """
#         return np.vstack([s(x, n) for s in self.splines])
# 
#     @property
#     def validFrom(self):
#         return max([s.validFrom for s in self.splines])
# 
#     @property
#     def validTo(self):
#         return min([s.validTo for s in self.splines])
# 
# Path: imusim/maths/vector_splines.py
# class PartialInputVectorSpline(PartialInputSpline):
#     """
#     Piecewise vector spline allowing for undefined regions in output domain.
#     """
#     _splineClass = UnivariateVectorSpline
# 
#     def __init__(self, x, y, **kwargs):
#         PartialInputSpline.__init__(self, x, y, **kwargs)
#         self._dims = np.shape(y)[0]
# 
#     def _validity(self, y):
#         return vectors.validity(y)
# 
#     def _output(self, x, conditions, results, undefined):
#         out = np.empty((self._dims, len(np.atleast_1d(x))))
#         for cond, result in izip(conditions, results):
#             out[:,cond] = result
#         out[:,undefined] = np.nan
#         return out


# Path: imusim/tests/maths/vector_splines_test.py
from imusim.maths.splines import Spline
from imusim.maths.vector_splines import UnivariateVectorSpline
from imusim.maths.vector_splines import PartialInputVectorSpline
from imusim.testing.random_data import randomTimeSequence
from imusim.testing.random_data import randomPositionSequence
from imusim.testing.random_data import randomValidity, invalidate
from numpy.testing import assert_almost_equal
import numpy as np

#
# IMUSim 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with IMUSim.  If not, see <http://www.gnu.org/licenses/>.


def checkVectorSpline(splineClass, x, y, order):
    try:
        spline = splineClass(x, y, order=order)
        ys = spline(x)
        splines = spline.splines if isinstance(spline, PartialInputVectorSpline) else [spline]
        valid = np.array(
            np.sum(((x >= spline.validFrom) & (x <= spline.validTo) for spline in splines)),
            dtype=bool)
        assert_almost_equal(y[:,valid], ys[:,valid])
    except Spline.InsufficientPointsError:
        pass

def testVectorSpline():
    for order in (1, 3, 5):
        for i in range(10):
            x = randomTimeSequence()
            y = randomPositionSequence(x)
            yield checkVectorSpline, UnivariateVectorSpline, x, y, order
            validity = randomValidity(x)
            yn = invalidate(y, validity)

            yield checkVectorSpline, PartialInputVectorSpline, x, yn, order