Example #1
0
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')
    ])
Example #3
0
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()
Example #4
0
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)
Example #10
0
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)