Beispiel #1
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)
    ]
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)
        ]
Beispiel #5
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
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)
    ]
def test_derivation_with_general_window():
    block = fully_cross_block([color, text, congruent_bookend], [color, text],
                              [])
    # congruent bookend - yes
    d = Derivation(16, [[0, 2], [1, 3]], congruent_bookend)
    backend_request = BackendRequest(19)
    d.apply(block, backend_request)

    (expected_cnf, expected_fresh) = to_cnf_tseitin(
        And([
            Iff(17, Or([And([1, 3]), And([2, 4])])),
            Iff(19, Or([And([13, 15]), And([14, 16])]))
        ]), 19)

    assert backend_request.fresh == expected_fresh
    assert backend_request.cnfs == [expected_cnf]

    # congruent bookend - no
    d = Derivation(17, [[0, 3], [1, 2]], congruent_bookend)
    backend_request = BackendRequest(19)
    d.apply(block, backend_request)

    (expected_cnf, expected_fresh) = to_cnf_tseitin(
        And([
            Iff(18, Or([And([1, 4]), And([2, 3])])),
            Iff(20, Or([And([13, 16]), And([14, 15])]))
        ]), 19)

    assert backend_request.fresh == expected_fresh
    assert backend_request.cnfs == [expected_cnf]
def test_derivation_with_multiple_transitions():
    block = fully_cross_block(
        [color, text, color_repeats_factor, text_repeats_factor],
        [color, text], [])

    # Text repeats derivation
    d = Derivation(22, [[2, 6], [3, 7]], text_repeats_factor)
    backend_request = BackendRequest(29)
    d.apply(block, backend_request)

    (expected_cnf, expected_fresh) = to_cnf_tseitin(
        And([
            Iff(23, Or([And([3, 7]), And([4, 8])])),
            Iff(25, Or([And([7, 11]), And([8, 12])])),
            Iff(27, Or([And([11, 15]), And([12, 16])]))
        ]), 29)

    assert backend_request.fresh == expected_fresh
    assert backend_request.cnfs == [expected_cnf]

    # Text does not repeat derivation
    d = Derivation(23, [[2, 7], [3, 6]], text_repeats_factor)
    backend_request = BackendRequest(29)
    d.apply(block, backend_request)

    (expected_cnf, expected_fresh) = to_cnf_tseitin(
        And([
            Iff(24, Or([And([3, 8]), And([4, 7])])),
            Iff(26, Or([And([7, 12]), And([8, 11])])),
            Iff(28, Or([And([11, 16]), And([12, 15])]))
        ]), 29)

    assert backend_request.fresh == expected_fresh
    assert backend_request.cnfs == [expected_cnf]
def test_derivation_with_transition():
    block = fully_cross_block([color, text, color_repeats_factor],
                              [color, text], [])

    # Color repeats derivation
    d = Derivation(16, [[0, 4], [1, 5]], color_repeats_factor)
    backend_request = BackendRequest(23)
    d.apply(block, backend_request)

    (expected_cnf, expected_fresh) = to_cnf_tseitin(
        And([
            Iff(17, Or([And([1, 5]), And([2, 6])])),
            Iff(19, Or([And([5, 9]), And([6, 10])])),
            Iff(21, Or([And([9, 13]), And([10, 14])]))
        ]), 23)

    assert backend_request.fresh == expected_fresh
    assert backend_request.cnfs == [expected_cnf]

    # Color does not repeat derivation
    d = Derivation(17, [[0, 5], [1, 4]], color_repeats_factor)
    backend_request = BackendRequest(23)
    d.apply(block, backend_request)

    (expected_cnf, expected_fresh) = to_cnf_tseitin(
        And([
            Iff(18, Or([And([1, 6]), And([2, 5])])),
            Iff(20, Or([And([5, 10]), And([6, 9])])),
            Iff(22, Or([And([9, 14]), And([10, 13])]))
        ]), 23)

    assert backend_request.fresh == expected_fresh
    assert backend_request.cnfs == [expected_cnf]
def test_derivation():
    # Congruent derivation
    d = Derivation(4, [[0, 2], [1, 3]], con_factor)
    backend_request = BackendRequest(24)
    d.apply(block, backend_request)

    (expected_cnf, expected_fresh) = to_cnf_tseitin(
        And([
            Iff(5, Or([And([1, 3]), And([2, 4])])),
            Iff(11, Or([And([7, 9]), And([8, 10])])),
            Iff(17, Or([And([13, 15]), And([14, 16])])),
            Iff(23, Or([And([19, 21]), And([20, 22])]))
        ]), 24)

    assert backend_request.fresh == expected_fresh
    assert backend_request.cnfs == [expected_cnf]

    # Incongruent derivation
    d = Derivation(5, [[0, 3], [1, 2]], con_factor)
    backend_request = BackendRequest(24)
    d.apply(block, backend_request)

    (expected_cnf, expected_fresh) = to_cnf_tseitin(
        And([
            Iff(6, Or([And([1, 4]), And([2, 3])])),
            Iff(12, Or([And([7, 10]), And([8, 9])])),
            Iff(18, Or([And([13, 16]), And([14, 15])])),
            Iff(24, Or([And([19, 22]), And([20, 21])]))
        ]), 24)

    assert backend_request.fresh == expected_fresh
    assert backend_request.cnfs == [expected_cnf]
    def generate_derivations(block: Block) -> List[Derivation]:
        derived_factors = list(filter(lambda f: f.is_derived(), block.design))
        accum = []

        for fact in derived_factors:
            for level in fact.levels:
                level_index = block.first_variable_for_level(
                    fact.name, level.name)
                x_product = level.get_dependent_cross_product()

                # filter to valid tuples, and get their idxs
                valid_tuples = [
                    tup for tup in x_product if level.window.fn(
                        *DerivationProcessor.generate_argument_list(
                            level, tup))
                ]
                valid_idxs = [[
                    block.first_variable_for_level(pair[0], pair[1])
                    for pair in tup_list
                ] for tup_list in valid_tuples]
                shifted_idxs = DerivationProcessor.shift_window(
                    valid_idxs, level.window, block.variables_per_trial())
                accum.append(Derivation(level_index, shifted_idxs, fact))

        return accum
def test_derivation_with_unusual_order():
    d = Derivation(0, [[4, 2], [5, 3]], congruency)
    backend_request = BackendRequest(64)
    d.apply(block, backend_request)

    (expected_cnf, expected_fresh) = to_cnf_tseitin(
        And([
            Iff(1, Or([And([5, 3]), And([6, 4])])),
            Iff(9, Or([And([13, 11]), And([14, 12])])),
            Iff(17, Or([And([21, 19]), And([22, 20])])),
            Iff(25, Or([And([29, 27]), And([30, 28])])),
            Iff(33, Or([And([37, 35]), And([38, 36])])),
            Iff(41, Or([And([45, 43]), And([46, 44])])),
            Iff(49, Or([And([53, 51]), And([54, 52])])),
            Iff(57, Or([And([61, 59]), And([62, 60])])),
        ]), 64)

    assert backend_request.fresh == expected_fresh
    assert backend_request.cnfs == [expected_cnf]
Beispiel #14
0
    def generate_derivations(block: Block) -> List[Derivation]:
        derived_factors = list(filter(lambda f: f.is_derived(), block.design))
        accum = []

        for fact in derived_factors:
            according_level: Dict[Tuple[Any, ...], DerivedLevel] = {}
            # according_level = {}
            for level in fact.levels:
                level_index = block.first_variable_for_level(fact, level)
                x_product = level.get_dependent_cross_product()

                # filter to valid tuples, and get their idxs
                valid_tuples = []
                for tup in x_product:
                    args = DerivationProcessor.generate_argument_list(
                        level, tup)
                    fn_result = level.window.fn(*args)

                    # Make sure the fn returned a boolean
                    if not isinstance(fn_result, bool):
                        raise ValueError(
                            'Derivation function did not return a boolean! factor={} level={} fn={} return={} args={} '
                            .format(fact.factor_name,
                                    get_external_level_name(level),
                                    level.window.fn, fn_result, args))

                    # If the result was true, add the tuple to the list
                    if fn_result:
                        valid_tuples.append(tup)
                        if tup in according_level.keys():
                            raise ValueError(
                                'Factor={} matches both level={} and level={} with assignment={}'
                                .format(fact.factor_name, according_level[tup],
                                        get_external_level_name(level), args))
                        else:
                            according_level[tup] = get_external_level_name(
                                level)

                if not valid_tuples:
                    print(
                        'WARNING: There is no assignment that matches factor={} level={}'
                        .format(fact.factor_name,
                                get_external_level_name(level)))

                valid_idxs = [[
                    block.first_variable_for_level(pair[0], pair[1])
                    for pair in tup_list
                ] for tup_list in valid_tuples]
                shifted_idxs = DerivationProcessor.shift_window(
                    valid_idxs, level.window, block.variables_per_trial())
                accum.append(Derivation(level_index, shifted_idxs, fact))

        return accum
def test_derivation_with_three_level_transition():
    f = Factor("f", ["a", "b", "c"])
    f_transition = Factor("transition", [
        DerivedLevel("aa",
                     Transition(lambda c: c[0] == "a" and c[1] == "a", [f])),
        DerivedLevel("ab",
                     Transition(lambda c: c[0] == "a" and c[1] == "b", [f])),
        DerivedLevel("ac",
                     Transition(lambda c: c[0] == "a" and c[1] == "c", [f])),
        DerivedLevel("ba",
                     Transition(lambda c: c[0] == "b" and c[1] == "a", [f])),
        DerivedLevel("bb",
                     Transition(lambda c: c[0] == "b" and c[1] == "b", [f])),
        DerivedLevel("bc",
                     Transition(lambda c: c[0] == "b" and c[1] == "c", [f])),
        DerivedLevel("ca",
                     Transition(lambda c: c[0] == "c" and c[1] == "a", [f])),
        DerivedLevel("cb",
                     Transition(lambda c: c[0] == "c" and c[1] == "b", [f])),
        DerivedLevel("cc",
                     Transition(lambda c: c[0] == "c" and c[1] == "c", [f])),
    ])

    block = fully_cross_block([f, f_transition], [f], [])

    # a-a derivation
    d = Derivation(9, [[0, 3]], f_transition)
    backend_request = BackendRequest(28)
    d.apply(block, backend_request)

    (expected_cnf, expected_fresh) = to_cnf_tseitin(
        And([Iff(10, Or([And([1, 4])])),
             Iff(19, Or([And([4, 7])]))]), 28)

    assert backend_request.fresh == expected_fresh
    assert backend_request.cnfs == [expected_cnf]
    def generate_derivations(block: Block) -> List[Derivation]:
        """Usage::

            >>> import operator as op
            >>> color = Factor("color", ["red", "blue"])
            >>> text  = Factor("text",  ["red", "blue"])
            >>> conLevel  = DerivedLevel("con", WithinTrial(op.eq, [color, text]))
            >>> incLevel  = DerivedLevel("inc", WithinTrial(op.ne, [color, text]))
            >>> conFactor = Factor("congruent?", [conLevel, incLevel])
            >>> design = [color, text, conFactor]
            >>> crossing = [color, text]
            >>> block = fully_cross_block(design, crossing, [])
            >>> DerivationProcessor.generate_derivations(block)
            [Derivation(derivedIdx=4, dependentIdxs=[[0, 2], [1, 3]]), Derivation(derivedIdx=5, dependentIdxs=[[0, 3], [1, 2]])]

        In the example above, the indicies of the design are:

        ===  =============
        idx  level
        ===  =============
        0    color:red
        1    color:blue
        2    text:red
        3    text:blue
        4    conFactor:con
        5    conFactor:inc
        ===  =============

        So the tuple ``(4, [[0,2], [1,3]])`` represents the information that
        the derivedLevel con is true iff ``(color:red && text:red) ||
        (color:blue && text:blue)`` by pairing the relevant indices together.

        :rtype:
            returns a list of tuples. Each tuple is structured as:
            ``(index of the derived level, list of dependent levels)``
        """
        derived_factors: List[DerivedFactor] = [factor for factor in block.design if isinstance(factor, DerivedFactor)]
        accum = []

        for factor in derived_factors:
            according_level: Dict[Tuple[Any, ...], DerivedLevel] = {}
            for level in factor.levels:
                cross_product: List[Tuple[Level, ...]] = level.get_dependent_cross_product()
                valid_tuples: List[Tuple[Level, ...]] = []
                for level_tuple in cross_product:
                    names = [level.name for level in level_tuple]
                    if level.window.width != 1:
                        # NOTE: mypy doesn't like this, but I'm not rewriting
                        #       it right now. Need to replace `chunk_list` with
                        #       a better version.
                        names = list(chunk_list(names, level.window.width))  # type: ignore
                    result = level.window.predicate(*names)
                    if not isinstance(result, bool):
                        raise ValueError(f"Expected derivation predicate to return bool; got {type(result)}.")
                    if level.window.predicate(*names):
                        valid_tuples.append(level_tuple)
                        if level_tuple in according_level:
                            raise ValueError(f"Factor {factor.name} matches {according_level[level_tuple].name} and "
                                             f"{level.name} with assignment {names}.")
                        according_level[level_tuple] = level

                if not valid_tuples:
                    print(f"WARNING: There is no assignment that matches factor {factor.name} with level {level.name}.")

                valid_indices = [[block.first_variable_for_level(level.factor, level) for level in valid_tuple]
                                 for valid_tuple in valid_tuples]
                shifted_indices = DerivationProcessor.shift_window(valid_indices,
                                                                   level.window,
                                                                   block.variables_per_trial())
                level_index = block.first_variable_for_level(factor, level)
                accum.append(Derivation(level_index, shifted_indices, factor))
        return accum