def test_alias(): x = F.Term('x') f = F.aliased_function('f', lambda x: 2*x) g = F.aliased_function('g', lambda x: np.sqrt(x)) ff = F.Formula([f(x), g(x)**2]) n = F.make_recarray([2,4,5], 'x') yield assert_almost_equal(ff.design(n)['f(x)'], n['x']*2) yield assert_almost_equal(ff.design(n)['g(x)**2'], n['x'])
def test_alias(): x = F.Term("x") f = F.aliased_function("f", lambda x: 2 * x) g = F.aliased_function("g", lambda x: np.sqrt(x)) ff = F.Formula([f(x), g(x) ** 2]) n = F.make_recarray([2, 4, 5], "x") yield assert_almost_equal(ff.design(n)["f(x)"], n["x"] * 2) yield assert_almost_equal(ff.design(n)["g(x)**2"], n["x"])
def test_2d(): B1, B2 = [gen_BrownianMotion() for _ in range(2)] B1s = formula.aliased_function("B1", B1) B2s = formula.aliased_function("B2", B2) t = sympy.DeferredVector('t') s = sympy.DeferredVector('s') e = B1s(s)+B2s(t) n={}; aliased._add_aliases_to_namespace(n, e) ee = sympy.lambdify((s,t), e, (n, 'numpy')) yield assert_almost_equal(ee(B1.x, B2.x), B1.y + B2.y)
def test_alias2(): f = F.aliased_function('f', lambda x: 2*x) g = F.aliased_function('f', lambda x: np.sqrt(x)) x = sympy.Symbol('x') l1 = aliased.lambdify(x, f(x)) l2 = aliased.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)
def test_1d(): B = gen_BrownianMotion() Bs = formula.aliased_function("B", B) t = sympy.DeferredVector('t') n={}; aliased._add_aliases_to_namespace(n, Bs) expr = 3*sympy.exp(Bs(t)) + 4 ee = sympy.lambdify(t, expr, (n, 'numpy')) yield assert_almost_equal(ee(B.x), 3*np.exp(B.y)+4)
def spectral_decomposition(hrf2decompose, ncomp=2, time=None, delta=None): """ Perform a PCA expansion of a symbolic HRF, evshifted 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 vectorized as a function of 't'. This is the HRF to be expanded in PCA ncomp : int Number of principal components to retain. time : np.ndarray Default value of np.linspace(-15,50,3751) chosen to match fMRIstat implementation. Presumed to be equally spaced. delta : np.ndarray Default value of np.arange(-4.5, 4.6, 0.1) chosen to match fMRIstat implementation. Returns ------- hrf : [sympy expressions] A sequence of symbolic HRFs that are the principal components. approx : TODO """ if time is None: time = np.linspace(-15,50,3751) dt = time[1] - time[0] if delta is None: delta = np.arange(-4.5, 4.6, 0.1) hrft = hrf.vectorize(hrf2decompose(hrf.t)) H = [] for i in range(delta.shape[0]): H.append(hrft(time - delta[i])) H = np.nan_to_num(np.asarray(H)) U, S, V = L.svd(H.T, full_matrices=0) basis = [] for i in range(ncomp): b = interp1d(time, U[:, i], bounds_error=False, fill_value=0.) if i == 0: d = np.fabs((b(time) * dt).sum()) b.y /= d basis.append(b) W = np.array([b(time) for b in basis[:ncomp]]) WH = np.dot(L.pinv(W.T), H.T) coef = [interp1d(delta, w, bounds_error=False, fill_value=0.) for w in WH] if coef[0](0) < 0: coef[0].y *= -1. basis[0].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) symbasis = [] for i, b in enumerate(basis): symbasis.append(formula.aliased_function('%s%d' % (str(hrf2decompose), i), b)) return symbasis, approx
def taylor_approx(hrf2decompose, tmax=50, tmin=-15, dt=0.02, delta=np.arange(-4.5, 4.6, 0.1)): """ Perform a PCA expansion of fn, 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 vectorized as a function of 't'. This is the HRF to be expanded in PCA ncomp : int Number of principal components to retain. 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. """ hrft = hrf.vectorize(hrf2decompose(hrf.t)) time = np.arange(tmin, tmax, dt) dhrft = interp1d(time, -np.gradient(hrft(time), dt), bounds_error=False, fill_value=0.) dhrft.y *= 2 H = np.array([hrft(time - d) for d in delta]) W = np.array([hrft(time), dhrft(time)]) W = W.T WH = np.dot(L.pinv(W), H.T) 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 = formula.aliased_function('d%s' % str(hrf2decompose), dhrft) return [hrf2decompose, dhrf], approx
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 vectorized 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 vectorizer from hrf function and symbol t. hrft returns # function values when called with values for time as input. hrft = hrf.vectorize(hrf2decompose(hrf.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( formula.aliased_function('%s%d' % (str(hrf2decompose), i), b)) return symbasis, approx
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 vectorized as a function of 't'. 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 vectorizer from hrf function and symbol t. hrft returns # function values when called with values for time as input. hrft = hrf.vectorize(hrf2decompose(hrf.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 = formula.aliased_function('d%s' % str(hrf2decompose), dhrft) return [hrf2decompose, dhrf], approx
def interpolate(name, col, t): i = interp1d(t, formula.vectorize(col)(t)) return formula.aliased_function(name, i)(formula.t)