Пример #1
0
 def test_OverlayPoissonMixture(self):
     """Poisson mixture model overlay: an exponential distribution plus the model's solved distribution"""
     # Do nothing with mixture coef 0
     s = ddm.Model(drift=ddm.models.DriftConstant(drift=1)).solve()
     smix = ddm.models.OverlayPoissonMixture(pmixturecoef=0,
                                             rate=1).apply(s)
     assert s == smix
     # With mixture coef 1, integrate to 1
     s = ddm.Model(drift=ddm.models.DriftConstant(drift=2),
                   noise=ddm.models.NoiseConstant(noise=3)).solve()
     smix = ddm.models.OverlayPoissonMixture(pmixturecoef=1,
                                             rate=10).apply(s)
     assert np.isclose(np.sum(smix.corr) + np.sum(smix.err), 1)
     # Should be monotonic decreasing on uniform distribution
     s = self.FakeUniformModel(dt=.001).solve()
     smix = ddm.models.OverlayPoissonMixture(pmixturecoef=.2,
                                             rate=1).apply(s)
     assert np.all([
         smix.corr[i - 1] - smix.corr[i] > 0
         for i in range(1, len(smix.corr))
     ])
     assert np.all([
         smix.err[i - 1] - smix.err[i] > 0 for i in range(1, len(smix.err))
     ])
     # Don't change total probability
     s = ddm.Model(ddm.models.DriftConstant(drift=1)).solve()
     smix = ddm.models.OverlayPoissonMixture(pmixturecoef=.2,
                                             rate=7).apply(s)
     assert np.isclose(
         np.sum(s.corr) + np.sum(s.err),
         np.sum(smix.corr) + np.sum(smix.err))
Пример #2
0
    def setUp(self):
        self.basic = ddm.Model(dx=.005,
                               dt=.01,
                               T_dur=2,
                               drift=ddm.DriftConstant(drift=.4),
                               noise=ddm.NoiseConstant(noise=1),
                               bound=ddm.BoundConstant(B=1))

        class NoiseCond(ddm.Noise):
            name = "Noise with a condition"
            required_conditions = ['cond']
            required_parameters = []

            def get_noise(self, conditions, **kwargs):
                return conditions["cond"]

        self.withcond = ddm.Model(noise=NoiseCond())

        class FancyBounds(ddm.Bound):
            name = "Increasing/decreasing bounds"
            required_conditions = []
            required_parameters = []

            def get_bound(self, conditions, t, **kwargs):
                if t <= 1:
                    return 1 + t
                if t > 1:
                    return 2 / t

        self.bound = ddm.Model(bound=FancyBounds())
Пример #3
0
    def setUp(self):
        class DriftSimple(ddm.Drift):
            name = "Test drift"
            required_conditions = ['coher']
            required_parameters = []

            def get_drift(self, conditions, **kwargs):
                return conditions["coher"]

        class DriftSimpleStringArg(ddm.Drift):
            name = "Test drift"
            required_conditions = ['type']
            required_parameters = []

            def get_drift(self, conditions, **kwargs):
                if conditions['type'] == "a":
                    return .3
                else:
                    return .1

        class DriftSimpleTupleArg(ddm.Drift):
            name = "Test drift"
            required_conditions = ['cohs']
            required_parameters = []

            def get_drift(self, conditions, **kwargs):
                return conditions['cohs'][0]

        # No undecided
        self.quick_ana = ddm.Model(T_dur=2, dt=.02).solve_analytical()
        # Includes undecided
        self.quick_cn = ddm.Model(T_dur=.5).solve_numerical_cn()
        # Includes undecided
        self.quick_imp = ddm.Model(T_dur=.5).solve_numerical_implicit()
        # No undecided, with parameters
        self.params_ana = ddm.Model(drift=DriftSimple(), T_dur=2.5,
                                    dt=.005).solve_analytical({"coher": .3})
        # Includes undecided, with parameters
        self.params_cn = ddm.Model(
            drift=DriftSimple(),
            T_dur=.5).solve_numerical_cn(conditions={"coher": .1})
        # Includes undecided, with parameters
        self.params_imp = ddm.Model(
            drift=DriftSimple(),
            T_dur=.5).solve_numerical_implicit(conditions={"coher": .1})
        # Dependence with a string argument
        self.params_strarg = ddm.Model(
            drift=DriftSimpleStringArg(),
            T_dur=.5).solve_analytical(conditions={"type": "a"})
        # Dependence with a tuple argument
        self.params_tuplearg = ddm.Model(
            drift=DriftSimpleTupleArg(),
            T_dur=.5).solve_analytical(conditions={"cohs": (.2, 1, 2)})
        self.all_sols = [
            self.quick_ana, self.quick_cn, self.quick_imp, self.params_ana,
            self.params_cn, self.params_imp, self.params_strarg,
            self.params_tuplearg
        ]
Пример #4
0
 def setUp(self):
     from integration_test_models import DriftCond
     self.DriftCond = DriftCond
     self.cond_m = ddm.Model(drift=self.DriftCond(param=1))
     self.cond_s = self.cond_m.solve(conditions={"cond": .1}).resample(4000) + \
                   self.cond_m.solve(conditions={"cond": 1}).resample(4000) + \
                   self.cond_m.solve(conditions={"cond": 2}).resample(4000)
Пример #5
0
 def test_analytic_lin_collapse(self):
     """Make sure linearly collapsing bounds stops at 0"""
     # Will collapse to 0 by t=1
     b = ddm.models.bound.BoundCollapsingLinear(B=1, t=1)
     m = ddm.Model(bound=b, T_dur=2)
     s = m.solve()
     assert len(s.pdf_corr()) == len(m.t_domain())
Пример #6
0
 def test_OverlaySimplePause(self):
     """Pause at some point in the trial and then continue, leaving 0 probability in the gap"""
     # Should do nothing with no shift
     s = ddm.Model().solve()
     assert s == ddm.models.OverlaySimplePause(pausestart=.4,
                                               pausestop=.4).apply(s)
     # Shift should make a gap in the uniform model
     s = self.FakeUniformModel().solve()
     smix = ddm.models.OverlaySimplePause(pausestart=.3,
                                          pausestop=.6).apply(s)
     assert len(set(smix.corr).union(set(smix.err))) == 2
     assert len(list(groupby(
         smix.corr))) == 3  # Looks like ----____----------
     # Should start with 0 and then go to constant with pausestart=.3
     s = self.FakeUniformModel(dt=.01).solve()
     smix = ddm.models.OverlaySimplePause(pausestart=0,
                                          pausestop=.05).apply(s)
     assert len(set(smix.corr).union(set(smix.err))) == 2
     assert len(list(groupby(smix.corr))) == 2  # Looks like ____----------
     assert np.all(smix.corr[0:5] == 0) and smix.corr[6] != 0
     # Truncate when time bin doesn't align
     s = self.FakePointModel(dt=.01).solve()
     sshift = ddm.models.OverlaySimplePause(pausestart=.01,
                                            pausestop=.029).apply(s)
     assert s.corr[1] == sshift.corr[2]
     assert s.err[1] == sshift.err[2]
Пример #7
0
 def test_fit_drift(self):
     """A simple one-parameter fit"""
     m = ddm.Model(name="DDM", drift=ddm.DriftConstant(drift=2))
     s = m.solve()
     sample = s.resample(10000)
     mfit = ddm.Model(
         name="DDM",
         drift=ddm.DriftConstant(drift=ddm.Fittable(minval=0, maxval=10)))
     ddm.fit_adjust_model(model=mfit, sample=sample)
     # Within 10%
     if SHOW_PLOTS:
         mfit.name = "Fitted solution"
         sfit = mfit.solve()
         plot_compare_solutions(s, sfit)
         plt.show()
     _verify_param_match("drift", "drift", m, mfit)
Пример #8
0
 def test_OverlayNonDecisionUniform(self):
     """Uniform-distributed non-decision time shifts the histogram"""
     # Should give the same results as OverlayNonDecision when halfwidth=0
     s = ddm.Model().solve()
     for nondectime in [0, -.1, .01, .0099, .011111, 1]:
         ndunif = ddm.models.OverlayNonDecisionUniform(
             nondectime=nondectime, halfwidth=0).apply(s)
         ndpoint = ddm.models.OverlayNonDecision(
             nondectime=nondectime).apply(s)
         assert np.all(np.isclose(ndunif.corr,
                                  ndpoint.corr)), (nondectime,
                                                   list(ndunif.corr),
                                                   list(ndpoint.corr))
         assert np.all(np.isclose(ndunif.err, ndpoint.err))
     # Simple shift example
     s = self.FakePointModel(dt=.01).solve()
     sshift = ddm.models.OverlayNonDecisionUniform(nondectime=.02,
                                                   halfwidth=.01).apply(s)
     assert sshift.corr[2] == sshift.corr[3] == sshift.corr[4]
     assert sshift.err[2] == sshift.err[3] == sshift.err[4]
     assert sshift.corr[0] == sshift.corr[1] == sshift.corr[5] == 0
     assert sshift.err[0] == sshift.err[1] == sshift.err[5] == 0
     # Off-boundary and behind 0 example
     s = self.FakePointModel(dt=.01).solve()
     sshift = ddm.models.OverlayNonDecisionUniform(
         nondectime=.021111, halfwidth=.033333).apply(s)
     assert sshift.corr[0] == sshift.corr[1]
     assert sshift.err[0] == sshift.err[1]
     assert len(set(sshift.corr)) == 2
     assert len(set(sshift.err)) == 2
Пример #9
0
 def test_OverlayBlurredPause(self):
     """Like OverlaySimplePause but with a gamma distribution on delay times"""
     # Don't change total probability when there are no undecided responses
     s = ddm.Model(drift=ddm.models.DriftConstant(drift=1),
                   T_dur=10).solve()
     smix = ddm.models.OverlayBlurredPause(pausestart=.3,
                                           pausestop=.6,
                                           pauseblurwidth=.1).apply(s)
     assert np.isclose(
         np.sum(s.corr) + np.sum(s.err),
         np.sum(smix.corr) + np.sum(smix.err))
     # Make sure responses before the pause aren't affected
     s = self.FakePointModel(dt=.01).solve()
     sshift = ddm.models.OverlayBlurredPause(pausestart=.02,
                                             pausestop=.03,
                                             pauseblurwidth=.002).apply(s)
     assert s.corr[1] == sshift.corr[1] != 0
     assert s.err[1] == sshift.err[1] != 0
     # Make sure responses after look like a gamma distribution
     s = self.FakePointModel(dt=.01).solve()
     sshift = ddm.models.OverlayBlurredPause(pausestart=0,
                                             pausestop=.05,
                                             pauseblurwidth=.01).apply(s)
     positive = (sshift.corr[2:] > sshift.err[1:-1]).astype(
         int
     )  # Excluding first 0 point, should go from + to - slope only once
     assert positive[0] == 1 and positive[-1] == 0 and len(
         set(positive)) == 2
Пример #10
0
 def test_OverlayNone(self):
     """No overlay"""
     s = ddm.Model().solve()
     assert s == ddm.models.OverlayNone().apply(s)
     s = self.FakeUniformModel().solve()
     assert s == ddm.models.OverlayNone().apply(s)
     s = self.FakePointModel().solve()
     assert s == ddm.models.OverlayNone().apply(s)
Пример #11
0
    def setUp(self):
        self.basic = ddm.Model(dx=.005,
                               dt=.01,
                               T_dur=2,
                               drift=ddm.DriftConstant(drift=.4),
                               noise=ddm.NoiseConstant(noise=1),
                               bound=ddm.BoundConstant(B=1))

        class NoiseCond(ddm.Noise):
            name = "Noise with a condition"
            required_conditions = ['cond']
            required_parameters = []

            def get_noise(self, conditions, **kwargs):
                return conditions["cond"]

        self.withcond = ddm.Model(noise=NoiseCond())
Пример #12
0
 def test_collapsing_bounds(self):
     """Bounds collapse to zero"""
     m = ddm.Model(bound=ddm.BoundCollapsingLinear(B=1, t=2))
     _modeltest_numerical_vs_analytical(m,
                                        method="implicit",
                                        max_diff=.3,
                                        mean_diff=.2,
                                        prob_diff=.05)
Пример #13
0
 def test_OverlayUniformMixture(self):
     """Uniform mixture model overlay: a uniform distribution plus the model's solved distribution"""
     # Do nothing with 0 probability
     s = ddm.Model(drift=ddm.models.DriftConstant(drift=1)).solve()
     smix = ddm.models.OverlayUniformMixture(umixturecoef=0).apply(s)
     assert s == smix
     # With mixture coef 1, integrate to 1
     s = ddm.Model(drift=ddm.models.DriftConstant(drift=2), noise=ddm.models.NoiseConstant(noise=3)).solve()
     smix = ddm.models.OverlayUniformMixture(umixturecoef=1).apply(s)
     assert np.isclose(np.sum(smix.corr) + np.sum(smix.err), 1)
     # Should not change uniform distribution
     s = self.FakeUniformModel(dt=.001).solve()
     assert s == ddm.models.OverlayUniformMixture(umixturecoef=.2).apply(s)
     # Don't change total probability
     s = ddm.Model(drift=ddm.models.DriftConstant(drift=1)).solve()
     smix = ddm.models.OverlayUniformMixture(umixturecoef=.2).apply(s)
     assert np.isclose(np.sum(s.corr) + np.sum(s.err),
                       np.sum(smix.corr) + np.sum(smix.err))
Пример #14
0
 def test_ICPoint_collapsing_bounds(self):
     m = ddm.Model(name='ICPoint_BCollapsingLin_test',
                   drift=ddm.DriftConstant(drift=2),
                   noise=ddm.NoiseConstant(noise=1.5),
                   bound=ddm.BoundCollapsingLinear(B=1, t=0.5),
                   IC=ddm.ICPoint(x0=-.25))
     _modeltest_numerical_vs_analytical(m,
                                        method="implicit",
                                        max_diff=.3,
                                        mean_diff=.2,
                                        prob_diff=.05)
Пример #15
0
 def test_ICPoint(self):
     """Arbitrary pointwise initial condition"""
     m = ddm.Model(name='ICPoint_test',
                   drift=ddm.DriftConstant(drift=2),
                   noise=ddm.NoiseConstant(noise=1.5),
                   bound=ddm.BoundConstant(B=1),
                   IC=ddm.ICPoint(x0=-.25))
     _modeltest_numerical_vs_analytical(m,
                                        method="implicit",
                                        max_diff=.3,
                                        mean_diff=.2,
                                        prob_diff=.05)
Пример #16
0
 def test_get_set_parameters_functions(self):
     """Test get_parameters, set_parameters, and get_parameter_names"""
     p1 = ddm.Fittable(minval=0, maxval=1)
     p2 = ddm.Fittable(minval=.3, maxval=.9, default=.4)
     m = ddm.Model(drift=ddm.DriftConstant(drift=p1), noise=ddm.NoiseLinear(noise=p2, x=.2, t=p1))
     print(m.get_model_parameters())
     assert all(id(a) == id(b) for a,b in zip(m.get_model_parameters(), [p1, p2]))
     assert all(a == b for a,b in zip(m.get_model_parameter_names(), ["drift/t", "noise"]))
     m.set_model_parameters(m.get_model_parameters())
     assert all(id(a) == id(b) for a,b in zip(m.get_model_parameters(), [p1, p2]))
     m.set_model_parameters([.5, .5])
     assert all(a == b for a,b in zip(m.get_model_parameters(), [.5, .5]))
Пример #17
0
 def test_overlay_chain_distribution_integrates_to_1(self):
     """Overlays integrate to 1"""
     m = ddm.Model(name="Overlay_test",
                   drift=ddm.DriftConstant(drift=2),
                   T_dur=5,
                   overlay=ddm.OverlayChain(overlays=[
                       ddm.OverlayPoissonMixture(pmixturecoef=.2, rate=2),
                       ddm.OverlayUniformMixture(umixturecoef=.2),
                       ddm.OverlayNonDecision(nondectime=.2)
                   ]))
     s = m.solve()
     distsum = s.prob_correct() + s.prob_error()
     assert .99 < distsum < 1.0001, "Distribution doesn't sum to 1"
Пример #18
0
 def test_fit_with_condition(self):
     """A simple one-parameter fit with conditions"""
     m = self.cond_m
     s = self.cond_s
     mfit = ddm.Model(drift=self.DriftCond(
         param=ddm.Fittable(minval=.1, maxval=3)))
     ddm.fit_adjust_model(model=mfit, sample=s)
     # Within 10%
     if SHOW_PLOTS:
         mfit.name = "Fitted solution"
         sfit = mfit.solve()
         plot_compare_solutions(s, sfit)
         plt.show()
     _verify_param_match("drift", "param", m, mfit)
Пример #19
0
 def test_ICArbitrary(self):
     """Arbitrary starting conditions from a distribution"""
     # Make sure we get out the same distribution we put in
     m = ddm.Model()
     unif = ddm.models.ICUniform()
     unif_a = ddm.models.ICArbitrary(unif.get_IC(m.x_domain({})))
     assert np.all(unif.get_IC(m.x_domain({})) == unif_a.get_IC(m.x_domain({})))
     point = ddm.models.ICPointSourceCenter()
     point_a = ddm.models.ICArbitrary(point.get_IC(m.x_domain({})))
     assert np.all(point.get_IC(m.x_domain({})) == point_a.get_IC(m.x_domain({})))
     # Make sure the distribution integrates to 1
     fails(lambda : ddm.models.ICArbitrary(aa([.1, .1, 0, 0, 0])))
     fails(lambda : ddm.models.ICArbitrary(aa([0, .6, .6, 0])))
     assert ddm.models.ICArbitrary(aa([1]))
 def __init__(self, ndt='gaussian'):
     overlay = (ddm.OverlayNonDecisionUniform(nondectime=ddm.Fittable(minval=0, maxval=0.5),
                                             halfwidth=ddm.Fittable(minval=0.001, maxval=0.3)) 
                 if ndt=='uniform' else 
                self.OverlayNonDecisionGaussian(nondectime=ddm.Fittable(minval=0, maxval=0.6),
                                                ndsigma=ddm.Fittable(minval=0.001, maxval=0.3)))
                                             
     self.model = ddm.Model(name='5 TTA- and d-dependent drift and bounds and uniformly distributed nondecision time',
                              drift=self.DriftTtaDistance(alpha=ddm.Fittable(minval=0.1, maxval=3),
                                                          beta=ddm.Fittable(minval=0, maxval=1),
                                                          theta=ddm.Fittable(minval=4, maxval=40)),
                              noise=ddm.NoiseConstant(noise=1),
                              bound=self.BoundCollapsingTta(b_0=ddm.Fittable(minval=0.5, maxval=5), 
                                                            k=ddm.Fittable(minval=0.1, maxval=2),
                                                            tta_crit=ddm.Fittable(minval=3, maxval=6)),
                              overlay=overlay,
                              T_dur=self.T_dur)
Пример #21
0
 def test_OverlayNonDecision(self):
     """Non-decision time shifts the histogram"""
     # Should do nothing with no shift
     s = ddm.Model().solve()
     assert s == ddm.models.OverlayNonDecision(nondectime=0).apply(s)
     # Shifts a single point distribution
     s = self.FakePointModel(dt=.01).solve()
     sshift = ddm.models.OverlayNonDecision(nondectime=.01).apply(s)
     assert s.corr[1] == sshift.corr[2]
     assert s.err[1] == sshift.err[2]
     # Shift the other way
     s = self.FakePointModel(dt=.01).solve()
     sshift = ddm.models.OverlayNonDecision(nondectime=-.01).apply(s)
     assert s.corr[1] == sshift.corr[0]
     assert s.err[1] == sshift.err[0]
     # Truncate when time bin doesn't align
     s = self.FakePointModel(dt=.01).solve()
     sshift = ddm.models.OverlayNonDecision(nondectime=.019).apply(s)
     assert s.corr[1] == sshift.corr[2]
     assert s.err[1] == sshift.err[2]
Пример #22
0
    def test_double_fit(self):
        """Fit different parameters in the same (or a different) model using a single Fittable object"""
        class NoiseDouble(ddm.Noise):
            name = "time-varying noise"
            required_parameters = ["noise1", "noise2"]

            def get_noise(self, **kwargs):
                if np.random.rand() > .5:
                    return self.noise1
                else:
                    return self.noise2

        class NoiseConstantButNot(ddm.Noise
                                  ):  # To avoid the numerical simulations
            name = "almost noise constant"
            required_parameters = ["noise"]

            def get_noise(self, **kwargs):
                return self.noise

        # Generate data
        m = ddm.Model(name="DDM",
                      drift=ddm.DriftConstant(drift=1),
                      noise=ddm.NoiseConstant(noise=1.7))
        s = m.solve_numerical(
        )  # Solving analytical and then fitting numerical may give a bias
        sample = s.resample(10000)
        mone = ddm.fit_model(
            sample,
            drift=ddm.DriftConstant(drift=1),
            noise=NoiseConstantButNot(noise=ddm.Fittable(minval=.5, maxval=3)))
        sigs = ddm.Fittable(minval=.5, maxval=3)
        msam = ddm.fit_model(sample,
                             drift=ddm.DriftConstant(drift=1),
                             noise=NoiseDouble(noise1=sigs, noise2=sigs))
        assert msam._noisedep.noise1 == msam._noisedep.noise2, "Fitting to be the same failed"
        assert abs(msam._noisedep.noise1 -
                   mone._noisedep.noise) < 0.1 * mone._noisedep.noise
Пример #23
0
 m = ddm.Model(
     drift=DriftDip(
         snr=snr,
         noise=noise,
         t1=t1,
         t1slope=t1slope,
         leak=leak,
         maxcoh=70,
         leaktarget=x0,
         leaktargramp=leaktargramp,
         dipstart=dipstart,
         dipstop=dipstop,
         diptype=diptype,
         dipparam=dipparam,
     ),
     noise=NoiseDip(
         noise=noise,
         t1=t1,
         t1slope=t1slope,
         dipstart=dipstart,
         dipstop=dipstop,
         diptype=diptype,
     ),
     IC=ICPoint(x0=x0),
     bound=BoundDip(B=1,
                    dipstart=dipstart,
                    dipstop=dipstop,
                    diptype=diptype),
     overlay=ddm.OverlayChain(overlays=[
         ddm.OverlayNonDecision(nondectime=nondectime),
         OverlayDipRatio(detect=detect, diptype=diptype),
         ddm.OverlayPoissonMixture(pmixturecoef=pmixturecoef, rate=rate)
     ]),
     dx=0.002,
     dt=0.002,
     T_dur=3.0)