Ejemplo n.º 1
0
def test_lambdify():
    # Test lambdify with implemented functions
    # first test basic (sympy) lambdify
    f = sympy.cos
    yield assert_equal(lambdify(x, f(x))(0), 1)
    yield assert_equal(lambdify(x, 1 + f(x))(0), 2)
    yield assert_equal(lambdify((x, y), y + f(x))(0, 1), 2)
    # make an implemented function and test
    f = implemented_function("f", lambda x : x+100)
    yield assert_equal(lambdify(x, f(x))(0), 100)
    yield assert_equal(lambdify(x, 1 + f(x))(0), 101)
    yield assert_equal(lambdify((x, y), y + f(x))(0, 1), 101)
    # Error for functions with same name and different implementation
    f2 = implemented_function("f", lambda x : x+101)
    yield assert_raises(ValueError, lambdify, x, f(f2(x)))
    # our lambdify, like sympy's lambdify, can also handle tuples,
    # lists, dicts as expressions
    lam = lambdify(x, (f(x), x))
    yield assert_equal(lam(3), (103, 3))
    lam = lambdify(x, [f(x), x])
    yield assert_equal(lam(3), [103, 3])
    lam = lambdify(x, [f(x), (f(x), x)])
    yield assert_equal(lam(3), [103, (103, 3)])
    lam = lambdify(x, {f(x): x})
    yield assert_equal(lam(3), {103: 3})
    lam = lambdify(x, {f(x): x})
    yield assert_equal(lam(3), {103: 3})
    lam = lambdify(x, {x: f(x)})
    yield assert_equal(lam(3), {3: 103})
Ejemplo n.º 2
0
def test_lambdify():
    # Test lambdify with implemented functions
    # first test basic (sympy) lambdify
    f = sympy.cos
    assert_equal(lambdify(x, f(x))(0), 1)
    assert_equal(lambdify(x, 1 + f(x))(0), 2)
    assert_equal(lambdify((x, y), y + f(x))(0, 1), 2)
    # make an implemented function and test
    f = implemented_function("f", lambda x: x + 100)
    assert_equal(lambdify(x, f(x))(0), 100)
    assert_equal(lambdify(x, 1 + f(x))(0), 101)
    assert_equal(lambdify((x, y), y + f(x))(0, 1), 101)
    # Error for functions with same name and different implementation
    f2 = implemented_function("f", lambda x: x + 101)
    assert_raises(ValueError, lambdify, x, f(f2(x)))
    # our lambdify, like sympy's lambdify, can also handle tuples,
    # lists, dicts as expressions
    lam = lambdify(x, (f(x), x))
    assert_equal(lam(3), (103, 3))
    lam = lambdify(x, [f(x), x])
    assert_equal(lam(3), [103, 3])
    lam = lambdify(x, [f(x), (f(x), x)])
    assert_equal(lam(3), [103, (103, 3)])
    lam = lambdify(x, {f(x): x})
    assert_equal(lam(3), {103: 3})
    lam = lambdify(x, {f(x): x})
    assert_equal(lam(3), {103: 3})
    lam = lambdify(x, {x: f(x)})
    assert_equal(lam(3), {3: 103})
Ejemplo n.º 3
0
def test_2d():
    B1, B2 = [gen_BrownianMotion() for _ in range(2)]
    B1s = implemented_function("B1", B1)
    B2s = implemented_function("B2", B2)
    s, t = sympy.symbols('s', 't')
    e = B1s(s)+B2s(t)
    ee = lambdify((s,t), e)
    yield assert_almost_equal(ee(B1.x, B2.x), B1.y + B2.y)
Ejemplo n.º 4
0
def test_alias():
    x = F.Term('x')
    f = implemented_function('f', lambda x: 2*x)
    g = implemented_function('g', lambda x: np.sqrt(x))
    ff = F.Formula([f(x), g(x)**2])
    n = F.make_recarray([2,4,5], 'x')
    assert_almost_equal(ff.design(n)['f(x)'], n['x']*2)
    assert_almost_equal(ff.design(n)['g(x)**2'], n['x'])
Ejemplo n.º 5
0
def test_alias():
    x = F.Term('x')
    f = implemented_function('f', lambda x: 2*x)
    g = implemented_function('g', lambda x: np.sqrt(x))
    ff = F.Formula([f(x), g(x)**2])
    n = F.make_recarray([2,4,5], 'x')
    assert_almost_equal(ff.design(n)['f(x)'], n['x']*2)
    assert_almost_equal(ff.design(n)['g(x)**2'], n['x'])
Ejemplo n.º 6
0
def test_2d():
    B1, B2 = [gen_BrownianMotion() for _ in range(2)]
    B1s = implemented_function("B1", B1)
    B2s = implemented_function("B2", B2)
    s, t = sympy.symbols(('s', 't'))
    e = B1s(s) + B2s(t)
    ee = lambdify((s, t), e)
    assert_almost_equal(ee(B1.x, B2.x), B1.y + B2.y)
Ejemplo n.º 7
0
def natural_spline(t, knots=None, order=3, intercept=False):
    """ Return a Formula containing a natural spline

    Spline for a Term with specified `knots` and `order`.

    Parameters
    ----------
    t : ``Term``
    knots : None or sequence, optional
       Sequence of float.  Default None (same as empty list)
    order : int, optional
       Order of the spline. Defaults to a cubic (==3)
    intercept : bool, optional
       If True, include a constant function in the natural
       spline. Default is False

    Returns
    -------
    formula : Formula
         A Formula with (len(knots) + order) Terms (if intercept=False,
         otherwise includes one more Term), made up of the natural spline
         functions.

    Examples
    --------
    >>> x = Term('x')
    >>> n = natural_spline(x, knots=[1,3,4], order=3)
    >>> xval = np.array([3,5,7.]).view(np.dtype([('x', np.float)]))
    >>> n.design(xval, return_float=True)
    array([[   3.,    9.,   27.,    8.,    0.,   -0.],
           [   5.,   25.,  125.,   64.,    8.,    1.],
           [   7.,   49.,  343.,  216.,   64.,   27.]])
    >>> d = n.design(xval)
    >>> print d.dtype.descr
    [('ns_1(x)', '<f8'), ('ns_2(x)', '<f8'), ('ns_3(x)', '<f8'), ('ns_4(x)', '<f8'), ('ns_5(x)', '<f8'), ('ns_6(x)', '<f8')]
    """
    if knots is None:
        knots = {}
    fns = []
    for i in range(order+1):
        n = 'ns_%d' % i
        def f(x, i=i):
            return x**i
        s = implemented_function(n, f)
        fns.append(s(t))

    for j, k in enumerate(knots):
        n = 'ns_%d' % (j+i+1,)
        def f(x, k=k, order=order):
            return (x-k)**order * np.greater(x, k)
        s = implemented_function(n, f)
        fns.append(s(t))

    if not intercept:
        fns.pop(0)

    ff = Formula(fns)
    return ff
Ejemplo n.º 8
0
def test_implemented_function():
    # Here we check if the default returned functions are anonymous - in
    # the sense that we can have more than one function with the same name
    f = implemented_function('f', lambda x: 2 * x)
    g = implemented_function('f', lambda x: np.sqrt(x))
    l1 = lambdify(x, f(x))
    l2 = lambdify(x, g(x))
    assert_equal(str(f(x)), str(g(x)))
    assert_equal(l1(3), 6)
    assert_equal(l2(3), np.sqrt(3))
    # check that we can pass in a sympy function as input
    func = sympy.Function('myfunc')
    assert_false(hasattr(func, '_imp_'))
    f = implemented_function(func, lambda x: 2 * x)
    assert_true(hasattr(func, '_imp_'))
Ejemplo n.º 9
0
def test_implemented_function():
    # Here we check if the default returned functions are anonymous - in
    # the sense that we can have more than one function with the same name
    f = implemented_function('f', lambda x: 2*x)
    g = implemented_function('f', lambda x: np.sqrt(x))
    l1 = lambdify(x, f(x))
    l2 = lambdify(x, g(x))
    yield assert_equal(str(f(x)), str(g(x)))
    yield assert_equal(l1(3), 6)
    yield assert_equal(l2(3), np.sqrt(3))
    # check that we can pass in a sympy function as input
    func = sympy.Function('myfunc')
    yield assert_false(hasattr(func, 'alias'))
    f = implemented_function(func, lambda x: 2*x)
    yield assert_true(hasattr(func, 'alias'))
Ejemplo n.º 10
0
def interp(times, values, fill=0, name=None, **kw):
    """ Generic interpolation function of t given `times` and `values`

    Imterpolator such that:

    f(times[i]) = values[i]

    if t < times[0] or t > times[-1]:
        f(t) = fill

    See ``scipy.interpolate.interp1d`` for details of interpolation
    types and other keyword arguments.  Default is 'kind' is linear,
    making this function, by default, have the same behavior as
    ``linear_interp``.

    Parameters
    ----------
    times : array-like
        Increasing sequence of times
    values : array-like
        Values at the specified times
    fill : None or float, optional
        Value on the interval (-np.inf, times[0]). Default 0. If None, raises
        error outside bounds
    name : None or str, optional
        Name of symbolic expression to use. If None, a default is used.
    \*\*kw : keyword args, optional
        passed to ``interp1d``

    Returns
    -------
    f : sympy expression
        A Function of t.

    Examples
    --------
    >>> s = interp([0,4,5.],[2.,4,6])
    >>> tval = np.array([-0.1,0.1,3.9,4.1,5.1])
    >>> res = lambdify_t(s)(tval)

    0 outside bounds by default

    >>> np.allclose(res, [0, 2.05, 3.95, 4.2, 0])
    True
    """
    if not fill is None:
        if kw.get('bounds_error') is True:
            raise ValueError('fill conflicts with bounds error')
        fv = kw.get('fill_value')
        if not (fv is None or fv is fill or fv == fill): # allow for fill=np.nan
            raise ValueError('fill conflicts with fill_value')
        kw['bounds_error'] = False
        kw['fill_value'] = fill
    interpolator = interp1d(times, values, **kw)
    # make a new name if none provided
    if name is None:
        name = 'interp%d' % interp.counter
        interp.counter += 1
    s = implemented_function(name, interpolator)
    return s(T)
Ejemplo n.º 11
0
def interp(times, values, fill=0, name=None, **kw):
    """ Generic interpolation function of t given `times` and `values`

    Imterpolator such that:
    
    f(times[i]) = values[i]

    if t < times[0]:
        f(t) = fill

    See ``scipy.interpolate.interp1d`` for details of interpolation
    types and other keyword arguments.  Default is 'kind' is linear,
    making this function, by default, have the same behavior as
    ``linear_interp``. 

    Parameters
    ----------
    times : array-like
        Increasing sequence of times
    values : array-like
        Values at the specified times
    fill : float, optional
        Value on the interval (-np.inf, times[0]). Default 0.
    name : None or str, optional
        Name of symbolic expression to use. If None, a default is used.
    **kw : keyword args, optional
        passed to ``interp1d``
        
    Returns
    -------
    f : sympy expression 
        A Function of t.

    Examples
    --------
    >>> s = interp([0,4,5.],[2.,4,6], bounds_error=False)
    >>> tval = np.array([-0.1,0.1,3.9,4.1,5.1])
    >>> res = lambdify_t(s)(tval)
    >>> # nans outside bounds
    >>> np.isnan(res)
    array([ True, False, False, False,  True], dtype=bool)
    >>> # interpolated values otherwise
    >>> np.allclose(res[1:-1], [2.05, 3.95, 4.2])
    True
    """
    interpolator = interp1d(times, values, **kw)
    # make a new name if none provided
    if name is None:
        name = "interp%d" % interp.counter
        interp.counter += 1
    s = implemented_function(name, interpolator)
    return s(T)
Ejemplo n.º 12
0
def test_1d():
    B = gen_BrownianMotion()
    Bs = implemented_function("B", B)
    t = sympy.Symbol('t')
    expr = 3*sympy.exp(Bs(t)) + 4
    expected = 3*np.exp(B.y)+4
    ee_vec = lambdify(t, expr)
    yield assert_almost_equal(ee_vec(B.x), expected)
    # with any arbitrary symbol
    b = sympy.Symbol('b')
    expr = 3*sympy.exp(Bs(b)) + 4
    ee_vec = lambdify(b, expr)
    yield assert_almost_equal(ee_vec(B.x), expected)
Ejemplo n.º 13
0
def test_1d():
    B = gen_BrownianMotion()
    Bs = implemented_function("B", B)
    t = sympy.Symbol('t')
    expr = 3 * sympy.exp(Bs(t)) + 4
    expected = 3 * np.exp(B.y) + 4
    ee_vec = lambdify(t, expr, "numpy")
    assert_almost_equal(ee_vec(B.x), expected)
    # with any arbitrary symbol
    b = sympy.Symbol('b')
    expr = 3 * sympy.exp(Bs(b)) + 4
    ee_vec = lambdify(b, expr, "numpy")
    assert_almost_equal(ee_vec(B.x), expected)
Ejemplo n.º 14
0
def step_function(times, values, name=None, fill=0):
    """ Right-continuous step function of time t

    Function of t such that

    f(times[i]) = values[i]

    if t < times[0]:
        f(t) = fill

    Parameters
    ----------
    times : (N,) sequence
       Increasing sequence of times
    values : (N,) sequence
       Values at the specified times
    fill : float
       Value on the interval (-np.inf, times[0])
    name : str
       Name of symbolic expression to use. If None, a default is used.

    Returns
    -------
    f_t : sympy expr
       Sympy expression f(t) where f is a sympy implemented anonymous
       function of time that implements the step function.  To get the
       numerical version of the function, use ``lambdify_t(f_t)``

    Examples
    --------
    >>> s = step_function([0,4,5],[2,4,6])
    >>> tval = np.array([-0.1,3.9,4.1,5.1])
    >>> lam = lambdify_t(s)
    >>> lam(tval)
    array([ 0.,  2.,  4.,  6.])
    """
    if name is None:
        name = 'step%d' % step_function.counter
        step_function.counter += 1

    def _imp(x):
        x = np.asarray(x)
        f = np.zeros(x.shape) + fill
        for time, val in zip(times, values):
            f[x >= time] = val
        return f

    s = implemented_function(name, _imp)
    return s(T)
Ejemplo n.º 15
0
def step_function(times, values, name=None, fill=0):
    """ Right-continuous step function of time t

    Function of t such that

    f(times[i]) = values[i]

    if t < times[0]:
        f(t) = fill

    Parameters
    ----------
    times : (N,) sequence
       Increasing sequence of times
    values : (N,) sequence
       Values at the specified times
    fill : float
       Value on the interval (-np.inf, times[0])
    name : str
       Name of symbolic expression to use. If None, a default is used.

    Returns
    -------
    f_t : sympy expr
       Sympy expression f(t) where f is a sympy implemented anonymous
       function of time that implements the step function.  To get the
       numerical version of the function, use ``lambdify_t(f_t)``

    Examples
    --------
    >>> s = step_function([0,4,5],[2,4,6])
    >>> tval = np.array([-0.1,3.9,4.1,5.1])
    >>> lam = lambdify_t(s)
    >>> lam(tval)
    array([ 0.,  2.,  4.,  6.])
    """
    if name is None:
        name = 'step%d' % step_function.counter
        step_function.counter += 1

    def _imp(x):
        x = np.asarray(x)
        f = np.zeros(x.shape) + fill
        for time, val in zip(times, values):
            f[x >= time] = val
        return f

    s = implemented_function(name, _imp)
    return s(T)
Ejemplo n.º 16
0
Archivo: fir.py Proyecto: FNNDSC/nipy
def linBspline(knots):
    """ Create a linear B spline that is zero outside [knots[0],
    knots[-1]] (knots is assumed to be sorted).
    """
    fns = []
    knots = np.array(knots)
    for i in range(knots.shape[0]-2):
        name = 'bs_%s' % i
        k1, k2, k3 = knots[i:i+3]
        d1 = k2-k1
        def anon(x,k1=k1,k2=k2,k3=k3):
            return ((x-k1) / d1 * np.greater(x, k1) * np.less_equal(x, k2) +
                    (k3-x) / d1 * np.greater(x, k2) * np.less(x, k3))
        fns.append(implemented_function(name, anon))
    return fns
Ejemplo n.º 17
0
Archivo: fir.py Proyecto: ofenlab/nipy
def linBspline(knots):
    """ Create linear B spline that is zero outside [knots[0], knots[-1]]

    (knots is assumed to be sorted).
    """
    fns = []
    knots = np.array(knots)
    for i in range(knots.shape[0] - 2):
        name = 'bs_%s' % i
        k1, k2, k3 = knots[i:i + 3]
        d1 = k2 - k1

        def anon(x, k1=k1, k2=k2, k3=k3):
            return ((x - k1) / d1 * np.greater(x, k1) * np.less_equal(x, k2) +
                    (k3 - x) / d1 * np.greater(x, k2) * np.less(x, k3))

        fns.append(implemented_function(name, anon))
    return fns
Ejemplo n.º 18
0
def define(name, expr):
    """ Create function of t expression from arbitrary expression `expr`

    Take an arbitrarily complicated expression `expr` of 't' and make it
    an expression that is a simple function of t, of form ``'%s(t)' %
    name`` such that when it evaluates (via ``lambdify``) it has the
    right values.

    Parameters
    ----------
    expr : sympy expression
       with only 't' as a Symbol
    name : str

    Returns
    -------
    nexpr: sympy expression

    Examples
    --------
    >>> t = Term('t')
    >>> expr = t**2 + 3*t
    >>> print expr #doctest: +SYMPY_EQUAL
    3*t + t**2
    >>> newexpr = define('f', expr)
    >>> print newexpr
    f(t)
    >>> f = lambdify_t(newexpr)
    >>> f(4)
    28
    >>> 3*4+4**2
    28
    """
    # make numerical implementation of expression
    v = lambdify(T, expr, "numpy")
    # convert numerical implementation to sympy function
    f = implemented_function(name, v)
    # Return expression that is function of time
    return f(T)
Ejemplo n.º 19
0
def define(name, expr):
    """ Create function of t expression from arbitrary expression `expr`

    Take an arbitrarily complicated expression `expr` of 't' and make it
    an expression that is a simple function of t, of form ``'%s(t)' %
    name`` such that when it evaluates (via ``lambdify``) it has the
    right values.

    Parameters
    ----------
    expr : sympy expression
       with only 't' as a Symbol
    name : str

    Returns
    -------
    nexpr: sympy expression

    Examples
    --------
    >>> t = Term('t')
    >>> expr = t**2 + 3*t
    >>> print expr #doctest: +SYMPY_EQUAL
    3*t + t**2
    >>> newexpr = define('f', expr)
    >>> print newexpr
    f(t)
    >>> f = lambdify_t(newexpr)
    >>> f(4)
    28
    >>> 3*4+4**2
    28
    """
    # make numerical implementation of expression
    v = lambdify(T, expr, "numpy")
    # convert numerical implementation to sympy function
    f = implemented_function(name, v)
    # Return expression that is function of time
    return f(T)
Ejemplo n.º 20
0
Archivo: hrf.py Proyecto: ofenlab/nipy
def taylor_approx(hrf2decompose,
                  time=None,
                  delta=None):
    """ A Taylor series approximation of an HRF shifted by times `delta`

    Returns original HRF and gradient of HRF

    Parameters
    ----------
    hrf2decompose : sympy expression
        An expression that can be lambdified as a function of 't'. This
        is the HRF to be expanded in PCA
    time : None or np.ndarray, optional
        None gives default value of np.linspace(-15,50,3251) chosen to
        match fMRIstat implementation.  This corresponds to a time
        interval of 0.02.  Presumed to be equally spaced.
    delta : None or np.ndarray, optional
        None results in default value of np.arange(-4.5, 4.6, 0.1)
        chosen to match fMRIstat implementation.

    Returns
    -------
    hrf : [sympy expressions]
        Sequence length 2 comprising (`hrf2decompose`, ``dhrf``) where
        ``dhrf`` is the first derivative of `hrf2decompose`.
    approx : 
        TODO

    References
    ----------
    Liao, C.H., Worsley, K.J., Poline, J-B., Aston, J.A.D., Duncan, G.H.,
    Evans, A.C. (2002). \'Estimating the delay of the response in fMRI
    data.\' NeuroImage, 16:593-606.
    """
    if time is None:
        time = np.linspace(-15,50,3251)
    dt = time[1] - time[0]
    if delta is None:
        delta = np.arange(-4.5, 4.6, 0.1)
    # make numerical implementation from hrf function and symbol t.
    # hrft returns function values when called with values for time as
    # input.
    hrft = lambdify_t(hrf2decompose(T))
    # interpolator for negative gradient of hrf
    dhrft = interp1d(time, -np.gradient(hrft(time), dt), bounds_error=False,
                    fill_value=0.)
    dhrft.y *= 2
    # Create stack of time-shifted HRFs.  Time varies over row, delta
    # over column.
    ts_hrf_vals = np.array([hrft(time - d) for d in delta]).T
    # hrf, dhrf
    W = np.array([hrft(time), dhrft(time)]).T
    # regress hrf, dhrf at times against stack of time-shifted hrfs
    WH = np.dot(npl.pinv(W), ts_hrf_vals)
    # put these into interpolators to get estimated coefficients for any
    # value of delta
    coef = [interp1d(delta, w, bounds_error=False,
                     fill_value=0.) for w in WH]
            
    def approx(time, delta):
        value = (coef[0](delta) * hrft(time)
                 + coef[1](delta) * dhrft(time))
        return value

    approx.coef = coef
    approx.components = [hrft, dhrft]
    (approx.theta,
     approx.inverse,
     approx.dinverse,
     approx.forward,
     approx.dforward) = invertR(delta, approx.coef)
    dhrf = implemented_function('d%s' % str(hrf2decompose), dhrft)
    return [hrf2decompose, dhrf], approx
Ejemplo n.º 21
0

# Glover canonical HRF models
# they are both Sympy objects

def _getint(f, dt=0.02, t=50):
    # numerical integral of function
    lf = lambdify_t(f)
    tt = np.arange(dt,t+dt,dt)
    return lf(tt).sum() * dt


_gexpr = gamma_expr(5.4, 5.2) - 0.35 * gamma_expr(10.8, 7.35)
_gexpr = _gexpr / _getint(_gexpr)
_glover = lambdify_t(_gexpr)
glover = implemented_function('glover', _glover)
glovert = lambdify_t(glover(T))

# Derivative of Glover HRF

_dgexpr = _gexpr.diff(T)
dpos = sympy.Derivative((T >= 0), T)
_dgexpr = _dgexpr.subs(dpos, 0)
_dgexpr = _dgexpr / _getint(sympy_abs(_dgexpr))
_dglover = lambdify_t(_dgexpr)
dglover = implemented_function('dglover', _dglover)
dglovert = lambdify_t(dglover(T))

del(_glover); del(_gexpr); del(dpos); del(_dgexpr); del(_dglover)

# AFNI's HRF
Ejemplo n.º 22
0
def interp(times, values, fill=0, name=None, **kw):
    """ Generic interpolation function of t given `times` and `values`

    Imterpolator such that:

    f(times[i]) = values[i]

    if t < times[0] or t > times[-1]:
        f(t) = fill

    See ``scipy.interpolate.interp1d`` for details of interpolation
    types and other keyword arguments.  Default is 'kind' is linear,
    making this function, by default, have the same behavior as
    ``linear_interp``.

    Parameters
    ----------
    times : array-like
        Increasing sequence of times
    values : array-like
        Values at the specified times
    fill : None or float, optional
        Value on the interval (-np.inf, times[0]). Default 0. If None, raises
        error outside bounds
    name : None or str, optional
        Name of symbolic expression to use. If None, a default is used.
    \*\*kw : keyword args, optional
        passed to ``interp1d``

    Returns
    -------
    f : sympy expression
        A Function of t.

    Examples
    --------
    >>> s = interp([0,4,5.],[2.,4,6])
    >>> tval = np.array([-0.1,0.1,3.9,4.1,5.1])
    >>> res = lambdify_t(s)(tval)

    0 outside bounds by default

    >>> np.allclose(res, [0, 2.05, 3.95, 4.2, 0])
    True
    """
    if not fill is None:
        if kw.get('bounds_error') is True:
            raise ValueError('fill conflicts with bounds error')
        fv = kw.get('fill_value')
        if not (fv is None or fv is fill
                or fv == fill):  # allow for fill=np.nan
            raise ValueError('fill conflicts with fill_value')
        kw['bounds_error'] = False
        kw['fill_value'] = fill
    interpolator = interp1d(times, values, **kw)
    # make a new name if none provided
    if name is None:
        name = 'interp%d' % interp.counter
        interp.counter += 1
    s = implemented_function(name, interpolator)
    return s(T)
Ejemplo n.º 23
0
Archivo: hrf.py Proyecto: ofenlab/nipy
def spectral_decomposition(hrf2decompose,
                           time=None,
                           delta=None,
                           ncomp=2):
    """ PCA decomposition of symbolic HRF shifted over time

    Perform a PCA expansion of a symbolic HRF, time shifted over the
    values in delta, returning the first ncomp components.

    This smooths out the HRF as compared to using a Taylor series
    approximation.

    Parameters
    ----------
    hrf2decompose : sympy expression
        An expression that can be lambdified as a function of 't'. This
        is the HRF to be expanded in PCA
    time : None or np.ndarray, optional
        None gives default value of np.linspace(-15,50,3251) chosen to
        match fMRIstat implementation.  This corresponds to a time
        interval of 0.02.  Presumed to be equally spaced.
    delta : None or np.ndarray, optional
        None results in default value of np.arange(-4.5, 4.6, 0.1)
        chosen to match fMRIstat implementation.
    ncomp : int, optional
        Number of principal components to retain.

    Returns
    -------
    hrf : [sympy expressions]
        A sequence length `ncomp` of symbolic HRFs that are the
        principal components.
    approx : 
        TODO
    """
    if time is None:
        time = np.linspace(-15,50,3251)
    dt = time[1] - time[0]
    if delta is None:
        delta = np.arange(-4.5, 4.6, 0.1)
    # make numerical implementation from hrf function and symbol t.
    # hrft returns function values when called with values for time as
    # input.
    hrft = lambdify_t(hrf2decompose(T))
    # Create stack of time-shifted HRFs.  Time varies over row, delta
    # over column.
    ts_hrf_vals = np.array([hrft(time - d) for d in delta]).T
    ts_hrf_vals = np.nan_to_num(ts_hrf_vals)
    # PCA 
    U, S, V = npl.svd(ts_hrf_vals, full_matrices=0)
    # make interpolators from the generated bases
    basis = []
    for i in range(ncomp):
        b = interp1d(time, U[:, i], bounds_error=False, fill_value=0.)
        # normalize components witn integral of abs of first component
        if i == 0: 
            d = np.fabs((b(time) * dt).sum())
        b.y /= d
        basis.append(b)
    # reconstruct time courses for all bases
    W = np.array([b(time) for b in basis]).T
    # regress basis time courses against original time shifted time
    # courses, ncomps by len(delta) parameter matrix
    WH = np.dot(npl.pinv(W), ts_hrf_vals)
    # put these into interpolators to get estimated coefficients for any
    # value of delta
    coef = [interp1d(delta, w, bounds_error=False, fill_value=0.) for w in WH]
    # swap sign of first component to match that of input HRF.  Swap
    # other components if we swap the first, to standardize signs of
    # components across SVD implementations.
    if coef[0](0) < 0: # coefficient at time shift of 0
        for i in range(ncomp):
            coef[i].y *= -1.
            basis[i].y *= -1.

    def approx(time, delta):
        value = 0
        for i in range(ncomp):
            value += coef[i](delta) * basis[i](time)
        return value

    approx.coef = coef
    approx.components = basis
    (approx.theta,
     approx.inverse,
     approx.dinverse,
     approx.forward,
     approx.dforward) = invertR(delta, approx.coef)
    # construct aliased functions from bases
    symbasis = []
    for i, b in enumerate(basis):
        symbasis.append(
            implemented_function('%s%d' % (str(hrf2decompose), i), b))
    return symbasis, approx
Ejemplo n.º 24
0
def natural_spline(t, knots=None, order=3, intercept=False):
    """ Return a Formula containing a natural spline

    Spline for a Term with specified `knots` and `order`.

    Parameters
    ----------
    t : ``Term``
    knots : None or sequence, optional
       Sequence of float.  Default None (same as empty list)
    order : int, optional
       Order of the spline. Defaults to a cubic (==3)
    intercept : bool, optional
       If True, include a constant function in the natural
       spline. Default is False

    Returns
    -------
    formula : Formula
         A Formula with (len(knots) + order) Terms (if intercept=False,
         otherwise includes one more Term), made up of the natural spline
         functions.

    Examples
    --------
    >>> x = Term('x')
    >>> n = natural_spline(x, knots=[1,3,4], order=3)
    >>> xval = np.array([3,5,7.]).view(np.dtype([('x', np.float)]))
    >>> n.design(xval, return_float=True)
    array([[   3.,    9.,   27.,    8.,    0.,   -0.],
           [   5.,   25.,  125.,   64.,    8.,    1.],
           [   7.,   49.,  343.,  216.,   64.,   27.]])
    >>> d = n.design(xval)
    >>> print d.dtype.descr
    [('ns_1(x)', '<f8'), ('ns_2(x)', '<f8'), ('ns_3(x)', '<f8'), ('ns_4(x)', '<f8'), ('ns_5(x)', '<f8'), ('ns_6(x)', '<f8')]
    """
    if knots is None:
        knots = {}
    fns = []
    for i in range(order + 1):
        n = 'ns_%d' % i

        def f(x, i=i):
            return x**i

        s = implemented_function(n, f)
        fns.append(s(t))

    for j, k in enumerate(knots):
        n = 'ns_%d' % (j + i + 1, )

        def f(x, k=k, order=order):
            return (x - k)**order * np.greater(x, k)

        s = implemented_function(n, f)
        fns.append(s(t))

    if not intercept:
        fns.pop(0)

    ff = Formula(fns)
    return ff