def test_generate_derivations_within_trial(): assert DerivationProcessor.generate_derivations(blk) == [ Derivation(4, [[0, 2], [1, 3]], con_factor), Derivation(5, [[0, 3], [1, 2]], con_factor) ] integer = Factor("integer", ["1", "2"]) numeral = Factor("numeral", ["I", "II"]) text = Factor("text", ["one", "two"]) twoConLevel = DerivedLevel("twoCon", WithinTrial(two_con, [integer, numeral, text])) twoNotConLevel = DerivedLevel( "twoNotCon", WithinTrial(two_not_con, [integer, numeral, text])) two_con_factor = Factor("twoCon?", [twoConLevel, twoNotConLevel]) one_two_design = [integer, numeral, text, two_con_factor] one_two_crossing = [integer, numeral, text] assert DerivationProcessor.generate_derivations( fully_cross_block(one_two_design, one_two_crossing, [])) == [ Derivation(6, [[0, 2, 5], [0, 3, 4], [0, 3, 5], [1, 2, 4], [1, 2, 5], [1, 3, 4]], two_con_factor), Derivation(7, [[0, 2, 4], [1, 3, 5]], two_con_factor) ]
def test_fully_cross_block_crossing_size_with_overlapping_exclude(): # How about with two overlapping exclude constraints? Initial crossing size # should be 3 x 3 = 9. # Excluding congruent pairs will reduce that to 9 - 3 = 6 # Then excluding red and green on top of that should make it 5. color = Factor("color", ["red", "blue", "green"]) text = Factor("text", ["red", "blue", "green"]) congruent_factor = Factor("congruent?", [ DerivedLevel("congruent", WithinTrial(op.eq, [color, text])), DerivedLevel("incongruent", WithinTrial(op.ne, [color, text])), ]) def illegal(color, text): return (color == "red" and text == "green") or color == text def legal(color, text): return not illegal(color, text) legal_factor = Factor("legal", [ DerivedLevel("yes", WithinTrial(legal, [color, text])), DerivedLevel("no", WithinTrial(illegal, [color, text])) ]) assert FullyCrossBlock( [color, text, congruent_factor, legal_factor], [[color, text]], [ Exclude(congruent_factor, get_level_from_name(congruent_factor, "congruent")), # Excludes 3 Exclude(legal_factor, get_level_from_name(legal_factor, "no")) ], # Exludes 4, but 3 were already excluded require_complete_crossing=False).crossing_size() == 5
def test_derived_level_validation(): DerivedLevel(42, WithinTrial(op.eq, [color, text])) DerivedLevel("name", WithinTrial(lambda x: x, [color])) # Invalid Window with pytest.raises(ValueError): DerivedLevel("name", 42)
def __get_response_transition() -> Factor: color = Factor("color", ["red", "blue", "green"]) motion = Factor("motion", ["up", "down"]) task = Factor("task", ["color", "motion"]) # Response Definition def response_left(task, color, motion): return (task == "color" and color == "red") or \ (task == "motion" and motion == "up") def response_right(task, color, motion): return not response_left(task, color, motion) response = Factor("response", [ DerivedLevel("left", WithinTrial(response_left, [task, color, motion])), DerivedLevel("right", WithinTrial(response_right, [task, color, motion])) ]) return Factor("response transition", [ DerivedLevel( "repeat", Transition(lambda responses: responses[0] == responses[1], [response])), DerivedLevel( "switch", Transition(lambda responses: responses[0] != responses[1], [response])) ])
def test_base_window_validation(): # Nonfactor argument with pytest.raises(ValueError): WithinTrial(op.eq, [42]) # Duplicated factors with pytest.raises(ValueError): DerivedLevel("name", WithinTrial(lambda x, y: x, [color, color]))
def test_generate_derivations_should_raise_error_if_some_factor_matches_multiple_levels( ): local_con_factor = Factor("congruent?", [ DerivedLevel("con", WithinTrial(op.eq, [color, text])), DerivedLevel("inc", WithinTrial(op.eq, [color, text])) ]) with pytest.raises(ValueError): fully_cross_block([color, text, local_con_factor], [color, text], [])
def test_generate_derivations_should_produce_warning_if_some_level_is_unreachable(capsys): local_con_factor = Factor("congruent?", [ DerivedLevel("con", WithinTrial(op.eq, [color, text])), DerivedLevel("inc", WithinTrial(op.ne, [color, text])), DerivedLevel("dum", WithinTrial(lambda c, t: c=='green', [color, text])) ]) fully_cross_block([color, text, local_con_factor], [color, text], []) assert capsys.readouterr().out == "WARNING: There is no assignment that matches factor congruent? with level dum.\n"
def __build_stroop_block(color_count): color = Factor("color", color_list[:color_count]) text = Factor("text", color_list[:color_count]) congruent = Factor("congruent?", [ DerivedLevel("yes", WithinTrial(op.eq, [color, text])), DerivedLevel("no", WithinTrial(op.ne, [color, text])) ]) constraints = [AtMostKInARow(1, ("congruent?", "yes"))] return fully_cross_block([color, text, congruent], [color, text], constraints)
def test_derived_level_validation(): # Non-str name with pytest.raises(ValueError): DerivedLevel(42, WithinTrial(op.eq, [color, text])) # Invalid Window with pytest.raises(ValueError): DerivedLevel("name", 42) # Repeated factors in argument list. with pytest.raises(ValueError): DerivedLevel("name", WithinTrial(lambda x: x, [color, color]))
def test_generate_derivations_should_raise_error_if_fn_doesnt_return_a_boolean(): def local_eq(color, text): color == text # Notice the missing return stmt local_con_factor = Factor("congruent?", [ DerivedLevel("con", WithinTrial(local_eq, [color, text])), DerivedLevel("inc", WithinTrial(lambda c, t: not local_eq(c, t), [color, text])) ]) with pytest.raises(ValueError): fully_cross_block([color, text, local_con_factor], [color, text], [])
def test_generate_sample_basic_stroop_uneven_colors(sequence_number, expected_solution): text = Factor("text", ["red", "blue", "green"]) congruency = Factor("congruency", [ DerivedLevel("congruent", WithinTrial(op.eq, [color, text])), DerivedLevel("incongruent", WithinTrial(op.ne, [color, text])) ]) block = fully_cross_block([color, text, congruency], [color, congruency], []) enumerator = UCSolutionEnumerator(block) print(enumerator.generate_sample(sequence_number)) assert enumerator.generate_sample(sequence_number) == expected_solution
def test_factor_validation(): Factor("factor name", ["level 1", "level 2"]) Factor("name", [1, 2]) # Duplicated name with pytest.raises(ValueError): Factor("name", ["a", "b", "a"]) with pytest.raises(ValueError): Factor("name", [ DerivedLevel("a", WithinTrial(op.eq, [color, text])), ElseLevel("a") ]) # Non-string name with pytest.raises(ValueError): Factor(56, ["level "]) # Non-list levels with pytest.raises(TypeError): Factor("name", 42) # Empty list with pytest.raises(ValueError): Factor("name", []) # Valid level types, but not uniform. with pytest.raises(ValueError): Factor("name", ["level1", con_level]) # Derived levels with non-uniform window types with pytest.raises(ValueError): Factor("name", [ con_level, DerivedLevel("other", WithinTrial(lambda color: color, [color])) ]) # Derived levels with different window arguments with pytest.raises(ValueError): Factor("name", [ con_level, DerivedLevel( "other", Transition(lambda colors: colors[0] == colors[1], [color])) ])
def test_derived_level_get_dependent_cross_product(): assert [((tup[0][0].factor_name, tup[0][1].external_name), (tup[1][0].factor_name, tup[1][1].external_name)) for tup in con_level.get_dependent_cross_product() ] == [(('color', 'red'), ('text', 'red')), (('color', 'red'), ('text', 'blue')), (('color', 'blue'), ('text', 'red')), (('color', 'blue'), ('text', 'blue'))] integer = Factor("integer", ["1", "2"]) numeral = Factor("numeral", ["I", "II"]) text = Factor("text", ["one", "two"]) two_con_level = DerivedLevel( "twoCon", WithinTrial(lambda x: x, [integer, numeral, text])) assert [((tup[0][0].factor_name, tup[0][1].external_name), (tup[1][0].factor_name, tup[1][1].external_name), (tup[2][0].factor_name, tup[2][1].external_name)) for tup in two_con_level.get_dependent_cross_product() ] == [(('integer', '1'), ('numeral', 'I'), ('text', 'one')), (('integer', '1'), ('numeral', 'I'), ('text', 'two')), (('integer', '1'), ('numeral', 'II'), ('text', 'one')), (('integer', '1'), ('numeral', 'II'), ('text', 'two')), (('integer', '2'), ('numeral', 'I'), ('text', 'one')), (('integer', '2'), ('numeral', 'I'), ('text', 'two')), (('integer', '2'), ('numeral', 'II'), ('text', 'one')), (('integer', '2'), ('numeral', 'II'), ('text', 'two'))] mixed_level = DerivedLevel( "mixed", WithinTrial(lambda x: x, [ Factor("color", ["red", "blue", "green"]), Factor("boolean", ["true", "false"]) ])) assert [((tup[0][0].factor_name, tup[0][1].external_name), (tup[1][0].factor_name, tup[1][1].external_name)) for tup in mixed_level.get_dependent_cross_product() ] == [(('color', 'red'), ('boolean', 'true')), (('color', 'red'), ('boolean', 'false')), (('color', 'blue'), ('boolean', 'true')), (('color', 'blue'), ('boolean', 'false')), (('color', 'green'), ('boolean', 'true')), (('color', 'green'), ('boolean', 'false'))]
def test_shift_window(): assert DerivationProcessor.shift_window([[0, 0], [1, 1]], WithinTrial(lambda x: x, None), 0) == [[0, 0], [1, 1]] assert DerivationProcessor.shift_window([[0, 0], [1, 1]], Transition(lambda x: x, None), 4) == [[0, 4], [1, 5]] assert DerivationProcessor.shift_window([[0, 2, 4], [1, 3, 5]], Window(lambda x: x, [1, 2], 2, 3), 6) == [[0, 8, 16], [1, 9, 17]] assert DerivationProcessor.shift_window([[1, 1, 1, 1], [2, 2, 2, 2]], Window(lambda x: x, [1, 2], 2, 4), 10) == \ [[1, 11, 21, 31], [2, 12, 22, 32]]
def test_exclude_with_reduced_crossing(): color = Factor("color", ["red", "blue", "green"]) text = Factor("text", ["red", "blue"]) def illegal_stimulus(color, text): return color == "green" and text == "blue" def legal_stimulus(color, text): return not illegal_stimulus(color, text) stimulus_configuration = Factor("stimulus configuration", [ DerivedLevel("legal", WithinTrial(legal_stimulus, [color, text])), DerivedLevel("illegal", WithinTrial(illegal_stimulus, [color, text])) ]) c = Exclude(stimulus_configuration, get_level_from_name(stimulus_configuration, "illegal")) block = fully_cross_block([color, text, stimulus_configuration], [color, text], [c], require_complete_crossing=False) backend_request = BackendRequest(0) c.apply(block, backend_request) assert backend_request.cnfs == [And([-7, -14, -21, -28, -35])]
deviantMovementObject): return (deviantColorObject != deviantOrientationObject) and ( deviantColorObject != deviantMovementObject) and ( deviantOrientationObject != deviantMovementObject) def illegalObjectConfiguration(deviantColorObject, deviantOrientationObject, deviantMovementObject): return not legalObjectConfiguration( deviantColorObject, deviantOrientationObject, deviantMovementObject) illegalLevel = DerivedLevel( "illegal", WithinTrial( illegalObjectConfiguration, [deviantColorObject, deviantOrientationObject, deviantMovementObject])) legalLevel = DerivedLevel( "legal", WithinTrial( legalObjectConfiguration, [deviantColorObject, deviantOrientationObject, deviantMovementObject])) objectConfiguration = Factor("object configuration", [illegalLevel, legalLevel]) # DEFINE TASK AND TASK TRANSITION task = Factor("task", ["color task", "movement task", "orientation task"])
# DEFINE STIMULUS FACTORS colorCoherence = Factor("color coherence", ["0.3", "0.53", "0.76", "1.0"]) motionCoherence = Factor("motion coherence", ["0.3", "0.53", "0.76", "1.0"]) color = Factor("color direction", ["red", "blue"]) motion = Factor("motion direction", ["up", "down"]) # DEFINE RESPONSE FACTORS def leftResponse(stimulusDimension): return (stimulusDimension == "red" or stimulusDimension == "up") def rightResponse(stimulusDimension): return (stimulusDimension == "blue" or stimulusDimension == "down") leftColorResponseLevel = DerivedLevel("-1", WithinTrial(leftResponse, [color])) rightColorResponseLevel = DerivedLevel("1", WithinTrial(rightResponse, [color])) leftMotionResponseLevel = DerivedLevel("-1", WithinTrial(leftResponse, [motion])) rightMotionResponseLevel = DerivedLevel("1", WithinTrial(rightResponse, [motion])) colorResponse = Factor("correct color response", [ leftColorResponseLevel, rightColorResponseLevel ]) print("[SWEETPEA]: GENERATED COLOR RESPONSE FACTOR") motionResponse = Factor("correct motion response", [ leftMotionResponseLevel, rightMotionResponseLevel
from sweetpea.server import build_cnf color = Factor("color", ["red", "blue", "green"]) word = Factor("motion", ["red", "blue"]) def illegal_stimulus(color, word): return color == "green" and word == "blue" def legal_stimulus(color, word): return not illegal_stimulus(color, word) stimulus_configuration = Factor("stimulus configuration", [ DerivedLevel("legal", WithinTrial(legal_stimulus, [color, word])), DerivedLevel("illegal", WithinTrial(illegal_stimulus, [color, word])) ]) constraints = [ exclude(stimulus_configuration, get_level_from_name(stimulus_configuration, "illegal")) ] design = [color, word, stimulus_configuration] crossing = [color, word] def test_no_solutions_without_override_flag(): block = fully_cross_block(design, crossing, constraints) experiments = synthesize_trials_non_uniform(block, 500)
import operator as op from sweetpea import fully_cross_block from sweetpea.primitives import Factor, DerivedLevel, WithinTrial color_list = ["red", "orange", "yellow", "green", "blue", "indigo"] color = Factor("color", color_list) text = Factor("text", color_list) congruency = Factor("congruency", [ DerivedLevel("congruent", WithinTrial(op.eq, [color, text])), DerivedLevel("incongruent", WithinTrial(op.ne, [color, text])) ]) design = [color, text, congruency] crossing = [color, text] block = fully_cross_block(design, crossing, []) # ASSERT COUNT = 371993326789901217467999448150835200000000
def test_else_level(): color = Factor("color", ["red", "blue"]) text = Factor("text", ["red", "blue"]) conLevel = DerivedLevel("con", WithinTrial(op.eq, [color, text])) conFactor = Factor("congruent?", [conLevel, ElseLevel("inc")])
color = Factor("color", ["red", "blue", "green"]) text = Factor("text", ["red", "blue", "green"]) # Global keyword needed to make this work when the tests exec() this file global correct_order def correct_order(color, text): return (color == "red" and text == "blue") or \ (color == "blue" and text == "green") or \ (color == "green" and text == "red") global incorrect_order def incorrect_order(color, text): return not correct_order(color, text) order = Factor("order", [ DerivedLevel("correct", WithinTrial(correct_order, [color, text])), DerivedLevel("incorrect", WithinTrial(incorrect_order, [color, text])) ]) design = [color, text, order] crossing = [color, order] block = fully_cross_block(design, crossing, []) # ASSERT COUNT = 5760
# Make SweetPea visible regardless of whether it's been installed. import sys sys.path.append("..") import operator from sweetpea.primitives import Factor, DerivedLevel, WithinTrial, Transition from sweetpea import fully_cross_block, synthesize_trials_non_uniform, print_experiments, at_most_k_in_a_row, exclude color_list = ["red", "green", "blue"] color = Factor("color", color_list) word = Factor("word", color_list) congruent = DerivedLevel("con", WithinTrial(operator.eq, [color, word])) incongruent = DerivedLevel("inc", WithinTrial(operator.ne, [color, word])) congruence = Factor("congruence", [congruent, incongruent]) one_con_at_a_time = at_most_k_in_a_row(1, (congruence, congruent)) def one_diff(colors, words): if (colors[0] == colors[1]): return words[0] != words[1] else: return words[0] == words[1] def both_diff(colors, words): return not one_diff(colors, words)
color = Factor("color", ["red", "blue"]) motion = Factor("motion", ["up", "down"]) task = Factor("task", ["color", "motion"]) def color_motion_congruent(color, motion): return ((color == "red") and (motion == "up")) or \ ((color == "blue") and (motion == "down")) def color_motion_incongruent(color, motion): return not color_motion_congruent(color, motion) congruency = Factor("congruency", [ DerivedLevel("con", WithinTrial(color_motion_congruent, [color, motion])), DerivedLevel("inc", WithinTrial(color_motion_incongruent, [color, motion])) ]) block = fully_cross_block([congruency, color, motion, task], [color, motion, task], []) def test_fully_cross_with_three_factors(): (expected_cnf, _) = to_cnf_tseitin( And([ Iff(65, And([3, 5, 7])), Iff(66, And([3, 5, 8])), Iff(67, And([3, 6, 7])), Iff(68, And([3, 6, 8])), Iff(69, And([4, 5, 7])),
motionCoherence = Factor("motion coherence", ["0.3", "0.53", "0.76", "1.0"]) color = Factor("color direction", ["red", "blue"]) motion = Factor("motion direction", ["up", "down"]) # DEFINE RESPONSE FACTORS def leftResponse(stimulusDimension): return (stimulusDimension == "red" or stimulusDimension == "up") def rightResponse(stimulusDimension): return (stimulusDimension == "blue" or stimulusDimension == "down") leftColorResponseLevel = DerivedLevel("-1", WithinTrial(leftResponse, [color])) rightColorResponseLevel = DerivedLevel("1", WithinTrial(rightResponse, [color])) leftMotionResponseLevel = DerivedLevel("-1", WithinTrial(leftResponse, [motion])) rightMotionResponseLevel = DerivedLevel("1", WithinTrial(rightResponse, [motion])) colorResponse = Factor("correct color response", [leftColorResponseLevel, rightColorResponseLevel]) motionResponse = Factor("correct motion response", [leftMotionResponseLevel, rightMotionResponseLevel]) # DEFINE CONGRUENCY FACTOR
return False """ btw, this is the same as: def response_left(task, color, motion): return (task == color && color == red) || (task == motion && motion == up) """ def response_right(task, color, motion): return not response_left(task, color, motion) response = Factor("response", [ derived_level("left", WithinTrial(response_left, [task, color, motion])), derived_level("right", WithinTrial(response_right, [task, color, motion])) ]) """ congruency (congruent, incongruent): dependent Factor. if current color == red & current motion == up then response = congruent if current color == blue & current motion == down then response = congruent . if current color == red & current motion == down then response = incongruent if current color == blue & current motion == up then response = incongruent """ def congruent(color, motion): return ((color == "red") and (motion == "up")) or ((color == "blue") and (motion == "down"))
import operator as op import pytest from sweetpea.primitives import Factor, DerivedLevel, WithinTrial, Transition from sweetpea.constraints import at_most_k_in_a_row, exactly_k_in_a_row from sweetpea.sampling_strategies.guided import GuidedSamplingStrategy from sweetpea import fully_cross_block, synthesize_trials from sweetpea.tests.test_utils import get_level_from_name # Basic setup color_list = ["red", "blue"] color = Factor("color", color_list) text = Factor("text", color_list) # Congruent Factor con_level = DerivedLevel("con", WithinTrial(op.eq, [color, text])) inc_level = DerivedLevel("inc", WithinTrial(op.ne, [color, text])) con_factor = Factor("congruent?", [con_level, inc_level]) design = [color, text, con_factor] crossing = [color, text] constraints = [] block = fully_cross_block(design, crossing, constraints) def test_guided_sampling_works(): trials = synthesize_trials(block, 5, sampling_strategy=GuidedSamplingStrategy)
left = Factor("left", ["0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"]) right = Factor("right", ["0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"]) # ALL POSSIBLE COMBINATIONS # DEFINE CONGRUENCY FACTOR def congruent_stimulus(left, right): return left[0] == right[0] and left[1] == right[1] def incongruent_stimulus(left, right): return not congruent_stimulus(left, right) cong_stimulus = DerivedLevel("cong_stimulus", WithinTrial(congruent_stimulus, [left, right])) incong_stimulus = DerivedLevel("incong_stimulus", WithinTrial(incongruent_stimulus, [left, right])) stimulus = Factor("stimulus", [ cong_stimulus, incong_stimulus ]) # DEFINE CONGRUENCY FACTOR def congruent_context(left, right): return left[2] == right[2] and left[3] == right[3] def incongruent_context(left, right): return not congruent_context(left, right)
color = Factor("color", ["red", "blue", "green", "brown"]) word = Factor("motion", ["red", "blue", "green", "brown"]) # congruency factor def congruent(color, word): return color == word def incongruent(color, word): return not congruent(color, word) conLevel = DerivedLevel("con", WithinTrial(congruent, [color, word])) incLevel = DerivedLevel("inc", WithinTrial(incongruent, [color, word])) congruency = Factor("congruency", [conLevel, incLevel]) # response factor def response_up(color): return color == "red" def response_down(color): return color == "blue"
color = Factor("color", ["red", "blue"]) motion = Factor("motion", ["up", "down"]) task = Factor("task", ["color", "motion"]) def color_motion_congruent(color, motion): return ((color == "red") and (motion == "up")) or \ ((color == "blue") and (motion == "down")) def color_motion_incongruent(color, motion): return not color_motion_congruent(color, motion) congruency = Factor("congruency", [ DerivedLevel("con", WithinTrial(color_motion_congruent, [color, motion])), DerivedLevel("inc", WithinTrial(color_motion_incongruent, [color, motion])) ]) def response_left(task, color, motion): return (task == "color" and color == "red") or \ (task == "motion" and motion == "up") def response_right(task, color, motion): return not response_left(task, color, motion) response = Factor("response", [ DerivedLevel("left", WithinTrial(response_left, [task, color, motion])),
import operator as op import pytest from sweetpea import fully_cross_block from sweetpea.primitives import Factor, DerivedLevel, WithinTrial from sweetpea.design_partitions import DesignPartitions color = Factor("color", ["red", "blue"]) text = Factor("text", ["red", "blue"]) congruency = Factor("congruency", [ DerivedLevel("congruent", WithinTrial(op.eq, [color, text])), DerivedLevel("incongruent", WithinTrial(op.ne, [color, text])) ]) color_red = Factor("color red", [ DerivedLevel("yes", WithinTrial(lambda c: c == "red", [color])), DerivedLevel("no", WithinTrial(lambda c: c != "red", [color])) ]) design = [color, text, congruency, color_red] crossing = [color, congruency] block = fully_cross_block(design, crossing, []) def test_get_crossed_factors(): partitions = DesignPartitions(block) assert partitions.get_crossed_factors() == crossing def test_get_crossed_factors_derived(): partitions = DesignPartitions(block) assert partitions.get_crossed_factors_derived() == [congruency]