def test_QuestPlusHandler(): import sys if not (sys.version_info.major == 3 and sys.version_info.minor >= 6): pytest.skip('QUEST+ only works on Python 3.6+') from psychopy.data.staircase import QuestPlusHandler thresholds = np.arange(-40, 0 + 1) slope, guess, lapse = 3.5, 0.5, 0.02 contrasts = thresholds.copy() expected_contrasts = [ -18, -22, -25, -28, -30, -22, -13, -15, -16, -18, -19, -20, -21, -22, -23, -19, -20, -20, -18, -18, -19, -17, -17, -18, -18, -18, -19, -19, -19, -19, -19, -19 ] responses = [ 'Correct', 'Correct', 'Correct', 'Correct', 'Incorrect', 'Incorrect', 'Correct', 'Correct', 'Correct', 'Correct', 'Correct', 'Correct', 'Correct', 'Correct', 'Incorrect', 'Correct', 'Correct', 'Incorrect', 'Correct', 'Correct', 'Incorrect', 'Correct', 'Correct', 'Correct', 'Correct', 'Correct', 'Correct', 'Correct', 'Correct', 'Correct', 'Correct', 'Correct' ] expected_mode_threshold = -20 scale = 'dB' stim_selection_method = 'minEntropy' param_estimation_method = 'mode' func = 'weibull' response_vals = ['Correct', 'Incorrect'] q = QuestPlusHandler(nTrials=len(expected_contrasts), intensityVals=contrasts, thresholdVals=thresholds, slopeVals=slope, lowerAsymptoteVals=guess, lapseRateVals=lapse, responseVals=response_vals, psychometricFunc=func, stimSelectionMethod=stim_selection_method, stimScale=scale, paramEstimationMethod=param_estimation_method) for trial_index, next_contrast in enumerate(q): assert next_contrast == expected_contrasts[trial_index] q.addResponse(response=responses[trial_index]) assert np.allclose(q.paramEstimate['threshold'], expected_mode_threshold)
def test_QuesPlusHandler_prior(): import sys if not (sys.version_info.major == 3 and sys.version_info.minor >= 6): pytest.skip('QUEST+ only works on Python 3.6+') from psychopy.data.staircase import QuestPlusHandler thresholds = np.arange(-40, 0 + 1) slope, guess, lapse = 3.5, 0.5, 0.02 contrasts = thresholds.copy() threshold_prior_vals = np.random.randint(low=1, high=10, size=len(thresholds)) threshold_prior_vals = threshold_prior_vals / threshold_prior_vals.sum() prior = dict(threshold=threshold_prior_vals) q = QuestPlusHandler(nTrials=20, intensityVals=contrasts, thresholdVals=thresholds, slopeVals=slope, lowerAsymptoteVals=guess, lapseRateVals=lapse, prior=prior) assert np.allclose(q._qp.prior.squeeze().values, threshold_prior_vals) # Even though we only specified a prior for threshold, all parameters # should be present (auto-populated) in q.prior. assert all([ k in q.prior for k in ('threshold', 'slope', 'lowerAsymptote', 'lapseRate') ])
def test_QuestPlusHandler_posterior_weibull(): import sys if not (sys.version_info.major == 3 and sys.version_info.minor >= 6): pytest.skip('QUEST+ only works on Python 3.6+') from psychopy.data.staircase import QuestPlusHandler thresholds = np.arange(-40, 0 + 1) slope, guess, lapse = 3.5, 0.5, 0.02 contrasts = thresholds.copy() response_vals = ['Correct', 'Incorrect'] func = 'weibull' q = QuestPlusHandler(nTrials=20, intensityVals=contrasts, thresholdVals=thresholds, slopeVals=slope, lowerAsymptoteVals=guess, lapseRateVals=lapse, responseVals=response_vals, psychometricFunc=func) assert 'threshold' in q.posterior.keys() assert 'slope' in q.posterior.keys() assert 'lowerAsymptote' in q.posterior.keys() assert 'lapseRate' in q.posterior.keys()
def test_QuestPlusHandler_startIntensity(): import sys if not (sys.version_info.major == 3 and sys.version_info.minor >= 6): pytest.skip('QUEST+ only works on Python 3.6+') from psychopy.data.staircase import QuestPlusHandler thresholds = np.arange(-40, 0 + 1) slope, guess, lapse = 3.5, 0.5, 0.02 contrasts = thresholds.copy() response_vals = ['Correct', 'Incorrect'] start_intensity = contrasts[10] scale = 'dB' stim_selection_method = 'minEntropy' param_estimation_method = 'mode' func = 'weibull' q = QuestPlusHandler(nTrials=10, startIntensity=start_intensity, intensityVals=contrasts, thresholdVals=thresholds, slopeVals=slope, lowerAsymptoteVals=guess, lapseRateVals=lapse, responseVals=response_vals, psychometricFunc=func, stimSelectionMethod=stim_selection_method, stimScale=scale, paramEstimationMethod=param_estimation_method) assert q.startIntensity == start_intensity assert q._nextIntensity == start_intensity
def test_QuesPlusHandler_stimSelectionOptions(): import sys if not (sys.version_info.major == 3 and sys.version_info.minor >= 6): pytest.skip('QUEST+ only works on Python 3.6+') from psychopy.data.staircase import QuestPlusHandler thresholds = np.arange(-40, 0 + 1) slope, guess, lapse = 3.5, 0.5, 0.02 contrasts = thresholds.copy() response_vals = ['Correct', 'Incorrect'] func = 'weibull' stim_scale = 'linear' stim_selection_method = 'minNEntropy' stim_selection_options = dict(N=10, maxConsecutiveReps=4, randomSeed=0) stim_selection_options_qp = dict(n=10, max_consecutive_reps=4, random_seed=0) q = QuestPlusHandler(nTrials=20, intensityVals=contrasts, thresholdVals=thresholds, slopeVals=slope, lowerAsymptoteVals=guess, lapseRateVals=lapse, responseVals=response_vals, psychometricFunc=func, stimScale=stim_scale, stimSelectionMethod=stim_selection_method, stimSelectionOptions=stim_selection_options) assert q.stimSelectionOptions == stim_selection_options assert q._qp.stim_selection_options == stim_selection_options_qp
def test_QuesPlusHandler_unused_StairHandler_attribs(): import sys if not (sys.version_info.major == 3 and sys.version_info.minor >= 6): pytest.skip('QUEST+ only works on Python 3.6+') from psychopy.data.staircase import QuestPlusHandler thresholds = np.arange(-40, 0 + 1) slope, guess, lapse = 3.5, 0.5, 0.02 contrasts = thresholds.copy() response_vals = ['Correct', 'Incorrect'] func = 'weibull' stim_scale = 'linear' q = QuestPlusHandler(nTrials=20, intensityVals=contrasts, thresholdVals=thresholds, slopeVals=slope, lowerAsymptoteVals=guess, lapseRateVals=lapse, responseVals=response_vals, psychometricFunc=func, stimScale=stim_scale) assert q.currentDirection is None assert q.stepSizeCurrent is None assert q.stepType == q.stimScale
def test_QuesPlusHandler_unknown_stimSelectionOptions(): import sys if not (sys.version_info.major == 3 and sys.version_info.minor >= 6): pytest.skip('QUEST+ only works on Python 3.6+') from psychopy.data.staircase import QuestPlusHandler thresholds = np.arange(-40, 0 + 1) slope, guess, lapse = 3.5, 0.5, 0.02 contrasts = thresholds.copy() stim_selection_method = 'minNEntropy' stim_selection_options = dict(unknownParam=1) with pytest.raises(ValueError): q = QuestPlusHandler(nTrials=20, intensityVals=contrasts, thresholdVals=thresholds, slopeVals=slope, lowerAsymptoteVals=guess, lapseRateVals=lapse, stimSelectionMethod=stim_selection_method, stimSelectionOptions=stim_selection_options)
def test_QuesPlusHandler_invalid_prior_params(): import sys if not (sys.version_info.major == 3 and sys.version_info.minor >= 6): pytest.skip('QUEST+ only works on Python 3.6+') from psychopy.data.staircase import QuestPlusHandler thresholds = np.arange(-40, 0 + 1) slope, guess, lapse = 3.5, 0.5, 0.02 contrasts = thresholds.copy() prior_vals = np.random.randint(low=1, high=10, size=len(thresholds)) prior_vals = prior_vals / prior_vals.sum() prior = dict(unknownParam=prior_vals) with pytest.raises(ValueError): q = QuestPlusHandler(nTrials=20, intensityVals=contrasts, thresholdVals=thresholds, slopeVals=slope, lowerAsymptoteVals=guess, lapseRateVals=lapse, prior=prior)
def test_QuesPlusHandler_unknown_kwargs(): import sys if not (sys.version_info.major == 3 and sys.version_info.minor >= 6): pytest.skip('QUEST+ only works on Python 3.6+') from psychopy.data.staircase import QuestPlusHandler thresholds = np.arange(-40, 0 + 1) slope, guess, lapse = 3.5, 0.5, 0.02 contrasts = thresholds.copy() response_vals = ['Correct', 'Incorrect'] func = 'weibull' unknown_kwargs = dict(foo=1, bar='baz') with pytest.warns(RuntimeWarning): QuestPlusHandler(nTrials=20, intensityVals=contrasts, thresholdVals=thresholds, slopeVals=slope, lowerAsymptoteVals=guess, lapseRateVals=lapse, responseVals=response_vals, psychometricFunc=func, **unknown_kwargs)
def test_QuestPlusHandler_saveAsJson(): import sys if not (sys.version_info.major == 3 and sys.version_info.minor >= 6): pytest.skip('QUEST+ only works on Python 3.6+') from psychopy.data.staircase import QuestPlusHandler thresholds = np.arange(-40, 0 + 1) slope, guess, lapse = 3.5, 0.5, 0.02 contrasts = thresholds.copy() response_vals = ['Correct', 'Incorrect'] scale = 'dB' stim_selection_method = 'minEntropy' param_estimation_method = 'mode' func = 'weibull' q = QuestPlusHandler(nTrials=20, intensityVals=contrasts, thresholdVals=thresholds, slopeVals=slope, lowerAsymptoteVals=guess, lapseRateVals=lapse, responseVals=response_vals, psychometricFunc=func, stimSelectionMethod=stim_selection_method, stimScale=scale, paramEstimationMethod=param_estimation_method) q.origin = '' # Add some random responses. q.__next__() q.addResponse(response='Correct') q.__next__() q.addResponse(response='Incorrect') # Test dump to memory. q.saveAsJson() # Test dump to file. temp_dir = mkdtemp(prefix='psychopy-tests-testdata') _, path = mkstemp(dir=temp_dir, suffix='.json') q.saveAsJson(fileName=path, fileCollisionMethod='overwrite') # Test loading from file. q_loaded = fromFile(path) assert q == q_loaded # Check if it still works afterwards. q.addResponse(response='Correct') shutil.rmtree(temp_dir)