Skip to content

Commit f94c6b7

Browse files
committed
Fix uniform mixture model to not depend on undecided trials
1 parent 15cd5dd commit f94c6b7

File tree

3 files changed

+13
-19
lines changed

3 files changed

+13
-19
lines changed

pyddm/functions.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,7 +1011,7 @@ def get_nondecision_time(self, conditions):
10111011
_required_parameters_mixc = list(set(_required_parameters_mixc+[mixture_coef_name]))
10121012
# If mixture coefficient is a parameter or value
10131013
if mixture_distribution is None:
1014-
mixture_distribution = lambda T : np.ones(len(T))/(np.max(T)+T[1]-T[0])
1014+
mixture_distribution = lambda T : np.ones(len(T))/(len(T)*(T[1]-T[0]))
10151015
typ, parsed, mixture_dist = _parse_dep(mixture_distribution, "mixture_distribution", ["upper", "T"])
10161016
if typ == "func":
10171017
_required_parameters_mix,_required_conditions_mix,_required_uT_mix = parsed
@@ -1026,7 +1026,6 @@ def apply(self, solution):
10261026
choice_lower = solution.choice_lower
10271027
m = solution.model
10281028
cond = solution.conditions
1029-
undec = solution.undec
10301029
evolution = solution.evolution
10311030
if _mixc_typ == "val":
10321031
if isinstance(mixture_coef, Fittable):
@@ -1056,6 +1055,7 @@ def apply(self, solution):
10561055
assert mix_coef_upper + mix_coef_lower <= 1.001, f"Mixture coefficients cannot be > 1, currently are {mix_coef_upper} and {mix_coef_lower}"
10571056
choice_upper = choice_upper*(1-(mix_coef_upper+mix_coef_lower)) + lapses_upper*mix_coef_upper*m.dt
10581057
choice_lower = choice_lower*(1-(mix_coef_upper+mix_coef_lower)) + lapses_lower*mix_coef_lower*m.dt
1058+
undec = None if solution.undec is None else solution.undec*(1-(mix_coef_upper+mix_coef_lower))
10591059
return Solution(choice_upper, choice_lower, m, cond, undec, evolution)
10601060
overlayobjs.append(OverlayMixtureEasy(**{fname:fval for fname,fval in _fittables.items() if fname in list(set(_required_parameters_mix+_required_parameters_mixc))}))
10611061
else:

pyddm/models/overlay.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -207,14 +207,10 @@ def apply(self, solution):
207207
choice_lower = solution.choice_lower
208208
m = solution.model
209209
cond = solution.conditions
210-
undec = solution.undec
210+
undec = None if solution.undec is None else solution.undec*(1-self.umixturecoef)
211211
evolution = solution.evolution
212-
# To make this work with undecided probability, we need to
213-
# normalize by the sum of the decided density. That way, this
214-
# function will never touch the undecided pieces.
215-
norm = np.sum(choice_upper)+np.sum(choice_lower)
216-
choice_upper = choice_upper*(1-self.umixturecoef) + .5*self.umixturecoef/len(m.t_domain())*norm
217-
choice_lower = choice_lower*(1-self.umixturecoef) + .5*self.umixturecoef/len(m.t_domain())*norm
212+
choice_upper = choice_upper*(1-self.umixturecoef) + .5*self.umixturecoef/len(m.t_domain())
213+
choice_lower = choice_lower*(1-self.umixturecoef) + .5*self.umixturecoef/len(m.t_domain())
218214
return Solution(choice_upper, choice_lower, m, cond, undec, evolution)
219215

220216
@paranoidclass

unit_tests.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,13 @@ def setUp(self):
3131
"""Create fake models which act like models but are actually much simpler."""
3232
# Fake model which solves to be a uniform distribution
3333
class FakeUniformModel(ddm.Model):
34+
def __init__(self, *args, p_undecided=.2, **kwargs):
35+
self.p_undecided = p_undecided
36+
return super().__init__(*args, **kwargs)
3437
def solve(self, conditions={}, *args, **kwargs):
35-
choice_upper = self.t_domain()*0+.4/len(self.t_domain())
36-
choice_lower = self.t_domain()*0+.4/len(self.t_domain())
37-
undec = self.x_domain(conditions=conditions)*0+.2/len(self.x_domain(conditions=conditions))
38+
choice_upper = self.t_domain()*0+(1-self.p_undecided)/2/len(self.t_domain())
39+
choice_lower = self.t_domain()*0+(1-self.p_undecided)/2/len(self.t_domain())
40+
undec = self.x_domain(conditions=conditions)*0+self.p_undecided/len(self.x_domain(conditions=conditions))
3841
return ddm.Solution(choice_upper, choice_lower, self, conditions, undec)
3942
FakeUniformModel.solve_analytical = FakeUniformModel.solve
4043
FakeUniformModel.solve_numerical = FakeUniformModel.solve
@@ -213,14 +216,9 @@ def test_OverlayUniformMixture(self):
213216
s = ddm.Model(drift=ddm.models.DriftConstant(drift=2), noise=ddm.models.NoiseConstant(noise=3)).solve()
214217
smix = ddm.models.OverlayUniformMixture(umixturecoef=1).apply(s)
215218
assert np.isclose(np.sum(smix.choice_upper) + np.sum(smix.choice_lower), 1, atol=1e-4)
216-
# Should not change uniform distribution
217-
s = self.FakeUniformModel(dt=.001).solve()
219+
# Should not change uniform distribution if no undecideds
220+
s = self.FakeUniformModel(p_undecided=0, dt=.001).solve()
218221
assert s == ddm.models.OverlayUniformMixture(umixturecoef=.2).apply(s)
219-
# Don't change total probability
220-
s = ddm.Model(drift=ddm.models.DriftConstant(drift=1)).solve()
221-
smix = ddm.models.OverlayUniformMixture(umixturecoef=.2).apply(s)
222-
assert np.isclose(np.sum(s.choice_upper) + np.sum(s.choice_lower),
223-
np.sum(smix.choice_upper) + np.sum(smix.choice_lower))
224222

225223
def test_OverlayPoissonMixture(self):
226224
"""Poisson mixture model overlay: an exponential distribution plus the model's solved distribution"""

0 commit comments

Comments
 (0)