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_generate_argument_list_with_within_trial():
    x_product = con_level.get_dependent_cross_product()

    assert DerivationProcessor.generate_argument_list(con_level, x_product[0]) == ['red', 'red']
    assert DerivationProcessor.generate_argument_list(con_level, x_product[1]) == ['red', 'blue']
    assert DerivationProcessor.generate_argument_list(con_level, x_product[2]) == ['blue', 'red']
    assert DerivationProcessor.generate_argument_list(con_level, x_product[3]) == ['blue', 'blue']
def test_shift_window():
    assert DerivationProcessor.shift_window([[0, 0, 2, 3]], one_level.window,
                                            4) == [[0, 4, 2, 7]]
    assert DerivationProcessor.shift_window([[1, 1, 3, 2]], one_level.window,
                                            4) == [[1, 5, 3, 6]]

    assert DerivationProcessor.shift_window([[0, 0, 2, 2]], other_level.window,
                                            4) == [[0, 4, 2, 6]]
    assert DerivationProcessor.shift_window([[0, 0, 3, 3]], other_level.window,
                                            4) == [[0, 4, 3, 7]]
def test_generate_argument_list_with_transition():
    color_repeats_level = DerivedLevel(
        "yes", Transition(lambda colors: colors[0] == colors[1], [color]))
    x_product = color_repeats_level.get_dependent_cross_product()

    assert DerivationProcessor.generate_argument_list(
        color_repeats_level, x_product[0]) == [['red', 'red']]
    assert DerivationProcessor.generate_argument_list(
        color_repeats_level, x_product[1]) == [['red', 'blue']]
    assert DerivationProcessor.generate_argument_list(
        color_repeats_level, x_product[2]) == [['blue', 'red']]
    assert DerivationProcessor.generate_argument_list(
        color_repeats_level, x_product[3]) == [['blue', 'blue']]

    double_repeat_level = DerivedLevel(
        "name", Transition(lambda colors, texts: True, [color, text]))
    x_product = double_repeat_level.get_dependent_cross_product()

    assert DerivationProcessor.generate_argument_list(
        color_repeats_level, x_product[0]) == [['red', 'red'], ['red', 'red']]
    assert DerivationProcessor.generate_argument_list(
        color_repeats_level, x_product[1]) == [['red', 'red'], ['red', 'blue']]
    assert DerivationProcessor.generate_argument_list(
        color_repeats_level, x_product[2]) == [['red', 'red'], ['blue', 'red']]
    assert DerivationProcessor.generate_argument_list(
        color_repeats_level, x_product[3]) == [['red', 'red'],
                                               ['blue', 'blue']]

    assert DerivationProcessor.generate_argument_list(
        color_repeats_level, x_product[15]) == [['blue', 'blue'],
                                                ['blue', 'blue']]
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]]
Ejemplo n.º 6
0
def test_generate_derivations_when_derived_factor_precedes_dependencies():
    block = fully_cross_block([congruency, motion, color, task],
                              [color, motion, task], [])
    derivations = DerivationProcessor.generate_derivations(block)

    assert Derivation(0, [[4, 2], [5, 3]], congruency) in derivations
    assert Derivation(1, [[4, 3], [5, 2]], congruency) in derivations
def test_generate_derivations_with_window():
    block = fully_cross_block([color, text, congruent_bookend], [color, text], [])

    assert DerivationProcessor.generate_derivations(block) == [
        Derivation(16, [[0, 2], [1, 3]], congruent_bookend),
        Derivation(17, [[0, 3], [1, 2]], congruent_bookend)
    ]
def test_generate_derivations_transition(design):
    block = fully_cross_block(design, [color, text], [])

    assert DerivationProcessor.generate_derivations(block) == [
        Derivation(16, [[0, 4], [1, 5]], color_repeats_factor),
        Derivation(17, [[0, 5], [1, 4]], color_repeats_factor)
    ]
Ejemplo n.º 9
0
def fully_cross_block(design: List[Factor],
                      crossing: List[Factor],
                      constraints: List[Constraint],
                      cnf_fn=to_cnf_tseitin) -> Block:
    all_constraints = cast(List[Constraint],
                           [FullyCross, Consistency]) + constraints
    block = FullyCrossBlock(design, crossing, all_constraints, cnf_fn)
    block.constraints += DerivationProcessor.generate_derivations(block)
    return block
Ejemplo n.º 10
0
def test_generate_derivations_with_transition_that_depends_on_derived_levels():
    block = fully_cross_block(
        [color, motion, task, response, response_transition],
        [color, motion, task], [])
    derivations = DerivationProcessor.generate_derivations(block)

    assert Derivation(64, [[6, 14], [7, 15]],
                      response_transition) in derivations
    assert Derivation(65, [[6, 15], [7, 14]],
                      response_transition) in derivations
Ejemplo n.º 11
0
def fully_cross_block(design: List[Factor],
                      crossing: List[Factor],
                      constraints: List[Constraint],
                      require_complete_crossing=True,
                      cnf_fn=to_cnf_tseitin) -> Block:
    """Returns a fully crossed :class:`.Block` meant to be used in experiment
    synthesis. This is the preferred mechanism for describing an experiment.

    :param design:
        A :class:`list` of all the :class:`Factors <.Factor>` in the design.
        When a sequence of trials is generated, each trial will have one level
        from each factor in ``design``.

    :param crossing:
        A :class:`list` of :class:`Factors <.Factor>` used to produce
        crossings. The number of trials in each run of the experiment is
        determined as the product of the number of levels of factors in
        ``crossing``.

        If ``require_complete_crossing`` is ``False``, the ``constraints`` can
        reduce the total number of trials.

        Different trial sequences of the experiment will have different
        combinations of levels in different orders. The factors in ``crossing``
        supply an implicit constraint that every combination of levels in the
        cross should appear once. Derived factors impose additional
        constraints: only combinations of levels that are consistent with
        derivations can appear as a trial. Additional constraints can be
        manually imposed via the ``constraints`` parameter.

    :param constraints:
        A :class:`list` of :class:`Constraints <.Constraint>` that restrict the
        generated trials.

    :param require_complete_crossing:
        Whether every combination in ``crossing`` must appear in a block of
        trials. ``True`` by default. A ``False`` value is appropriate if
        combinations are excluded through an :class:`.Exclude`
        :class:`.Constraint`.

    :param cnf_fn:
        A CNF conversion function. Default is :func:`.to_cnf_tseitin`.
    """
    all_constraints = cast(List[Constraint],
                           [FullyCross(), Consistency()]) + constraints
    all_constraints = __desugar_constraints(
        all_constraints)  #expand the constraints into a form we can process.
    block = FullyCrossBlock(design, [crossing], all_constraints,
                            require_complete_crossing, cnf_fn)
    block.constraints += DerivationProcessor.generate_derivations(block)
    if not constraints and not list(filter(
            lambda f: f.is_derived(), crossing)) and not list(
                filter(lambda f: f.has_complex_window, design)):
        block.complex_factors_or_constraints = False
    return block
def test_generate_derivations_with_multiple_transitions(design):
    block = fully_cross_block([color, text, color_repeats_factor, text_repeats_factor],
                              [color, text],
                              [])

    assert DerivationProcessor.generate_derivations(block) == [
        Derivation(16, [[0, 4], [1, 5]], color_repeats_factor),
        Derivation(17, [[0, 5], [1, 4]], color_repeats_factor),
        Derivation(22, [[2, 6], [3, 7]], text_repeats_factor),
        Derivation(23, [[2, 7], [3, 6]], text_repeats_factor)
    ]
def test_generate_derivations():
    assert DerivationProcessor.generate_derivations(block) == [
        Derivation(16,
                   [[0, 4, 2, 7], [0, 4, 3, 6], [0, 5, 2, 6], [0, 5, 3, 7],
                    [1, 4, 2, 6], [1, 4, 3, 7], [1, 5, 2, 7], [1, 5, 3, 6]],
                   change),
        Derivation(17,
                   [[0, 4, 2, 6], [0, 4, 3, 7], [0, 5, 2, 7], [0, 5, 3, 6],
                    [1, 4, 2, 7], [1, 4, 3, 6], [1, 5, 2, 6], [1, 5, 3, 7]],
                   change)
    ]
Ejemplo n.º 14
0
def multiple_cross_block(design: List[Factor],
                         crossings: List[List[Factor]],
                         constraints: List[Constraint],
                         require_complete_crossing=True,
                         cnf_fn=to_cnf_tseitin) -> Block:
    """Returns a :class:`.Block` with multiple crossings, meant to be used in
    experiment synthesis. Similar to :func:`fully_cross_block`, except it can
    be configured with multiple crossings.

    :param design:
        A :class:`list` of all the :class:`Factors <.Factor>` in the design.
        When a sequence of trials is generated, each trial will have one level
        from each factor in ``design``.

    :param crossings:
        A :class:`list` of :class:`lists <list>` of :class:`Factors <.Factor>`
        representing crossings. The number of trials in each run of the
        experiment is determined by the *maximum* product among the number of
        levels in the crossings.

        Every combination of levels in each individual crossing in
        ``crossings`` appears at least once. Different crossings can refer to
        the same factors, which constrains how factor levels are chosen across
        crossings.

    :param constraints:
        A :class:`list` of :class:`Constraints <.Constraint>` that restrict the
        generated trials.

    :param require_complete_crossing:
        Whether every combination in ``crossings`` must appear in a block of
        trials. ``True`` by default. A ``False`` value is appropriate if
        combinations are excluded through an :class:`.Exclude`
        :class:`.Constraint.`

    :param cnf_fn:
        A CNF conversion function. Default is :func:`.to_cnf_tseitin`.
    """
    all_constraints = cast(List[Constraint],
                           [MultipleCross(), Consistency()]) + constraints
    all_constraints = __desugar_constraints(
        all_constraints)  #expand the constraints into a form we can process.
    block = MultipleCrossBlock(design, crossings, all_constraints,
                               require_complete_crossing, cnf_fn)
    block.constraints += DerivationProcessor.generate_derivations(block)
    return block