def test_fully_cross_with_transition_in_design(design):
    block = fully_cross_block(design, [color, text], [])

    backend_request = BackendRequest(23)
    FullyCross.apply(block, backend_request)

    (expected_cnf, _) = to_cnf_tseitin(
        And([
            Iff(23, And([1, 3])),
            Iff(24, And([1, 4])),
            Iff(25, And([2, 3])),
            Iff(26, And([2, 4])),
            Iff(27, And([5, 7])),
            Iff(28, And([5, 8])),
            Iff(29, And([6, 7])),
            Iff(30, And([6, 8])),
            Iff(31, And([9, 11])),
            Iff(32, And([9, 12])),
            Iff(33, And([10, 11])),
            Iff(34, And([10, 12])),
            Iff(35, And([13, 15])),
            Iff(36, And([13, 16])),
            Iff(37, And([14, 15])),
            Iff(38, And([14, 16]))
        ]), 39)

    assert backend_request.fresh == 72
    assert backend_request.cnfs == [expected_cnf]
    assert backend_request.ll_requests == [
        LowLevelRequest("GT", 0, [23, 27, 31, 35]),
        LowLevelRequest("GT", 0, [24, 28, 32, 36]),
        LowLevelRequest("GT", 0, [25, 29, 33, 37]),
        LowLevelRequest("GT", 0, [26, 30, 34, 38])
    ]
def test_fully_cross_with_uncrossed_simple_factors():
    other = Factor('other', ['l1', 'l2'])
    block = fully_cross_block([color, text, other], [color, text], [])

    backend_request = BackendRequest(25)
    FullyCross.apply(block, backend_request)

    (expected_cnf, _) = to_cnf_tseitin(
        And([
            Iff(25, And([1, 3])),
            Iff(26, And([1, 4])),
            Iff(27, And([2, 3])),
            Iff(28, And([2, 4])),
            Iff(29, And([7, 9])),
            Iff(30, And([7, 10])),
            Iff(31, And([8, 9])),
            Iff(32, And([8, 10])),
            Iff(33, And([13, 15])),
            Iff(34, And([13, 16])),
            Iff(35, And([14, 15])),
            Iff(36, And([14, 16])),
            Iff(37, And([19, 21])),
            Iff(38, And([19, 22])),
            Iff(39, And([20, 21])),
            Iff(40, And([20, 22]))
        ]), 41)

    assert backend_request.fresh == 74
    assert backend_request.cnfs == [expected_cnf]
    assert backend_request.ll_requests == [
        LowLevelRequest("GT", 0, [25, 29, 33, 37]),
        LowLevelRequest("GT", 0, [26, 30, 34, 38]),
        LowLevelRequest("GT", 0, [27, 31, 35, 39]),
        LowLevelRequest("GT", 0, [28, 32, 36, 40])
    ]
def test_fully_cross_simple():
    block = fully_cross_block([color, text], [color, text], [])

    (expected_cnf, _) = to_cnf_tseitin(
        And([
            Iff(17, And([1, 3])),
            Iff(18, And([1, 4])),
            Iff(19, And([2, 3])),
            Iff(20, And([2, 4])),
            Iff(21, And([5, 7])),
            Iff(22, And([5, 8])),
            Iff(23, And([6, 7])),
            Iff(24, And([6, 8])),
            Iff(25, And([9, 11])),
            Iff(26, And([9, 12])),
            Iff(27, And([10, 11])),
            Iff(28, And([10, 12])),
            Iff(29, And([13, 15])),
            Iff(30, And([13, 16])),
            Iff(31, And([14, 15])),
            Iff(32, And([14, 16]))
        ]), 33)

    backend_request = BackendRequest(17)
    FullyCross.apply(block, backend_request)

    assert backend_request.fresh == 66
    assert backend_request.cnfs == [expected_cnf]
    assert backend_request.ll_requests == [
        LowLevelRequest("GT", 0, [17, 21, 25, 29]),
        LowLevelRequest("GT", 0, [18, 22, 26, 30]),
        LowLevelRequest("GT", 0, [19, 23, 27, 31]),
        LowLevelRequest("GT", 0, [20, 24, 28, 32])
    ]
def test_fully_cross_with_constraint():
    (expected_cnf, _) = to_cnf_tseitin(
        And([
            Iff(25, And([1, 3])),
            Iff(26, And([1, 4])),
            Iff(27, And([2, 3])),
            Iff(28, And([2, 4])),
            Iff(29, And([7, 9])),
            Iff(30, And([7, 10])),
            Iff(31, And([8, 9])),
            Iff(32, And([8, 10])),
            Iff(33, And([13, 15])),
            Iff(34, And([13, 16])),
            Iff(35, And([14, 15])),
            Iff(36, And([14, 16])),
            Iff(37, And([19, 21])),
            Iff(38, And([19, 22])),
            Iff(39, And([20, 21])),
            Iff(40, And([20, 22]))
        ]), 41)

    backend_request = BackendRequest(25)
    FullyCross.apply(block, backend_request)

    assert backend_request.fresh == 74
    assert backend_request.cnfs == [expected_cnf]
    assert backend_request.ll_requests == [
        LowLevelRequest("GT", 0, [25, 29, 33, 37]),
        LowLevelRequest("GT", 0, [26, 30, 34, 38]),
        LowLevelRequest("GT", 0, [27, 31, 35, 39]),
        LowLevelRequest("GT", 0, [28, 32, 36, 40])
    ]
def test_nomorethankinarow_sugar():
    backend_request = __run_kinarow(
        NoMoreThanKInARow(1, (color, get_level_from_name(color, "red"))))
    assert backend_request.ll_requests == [
        LowLevelRequest("LT", 2, [1, 7]),
        LowLevelRequest("LT", 2, [7, 13]),
        LowLevelRequest("LT", 2, [13, 19])
    ]
Beispiel #6
0
def test_low_level_request_validation():
    # Acceptable requests
    LowLevelRequest('EQ', 1, [1, 2, 3])
    LowLevelRequest('LT', 1, [1, 2, 3])
    LowLevelRequest('GT', 1, [1, 2, 3])

    # Invalid comparison
    with pytest.raises(ValueError):
        LowLevelRequest('bad', 1, [1, 2, 3])

    # Non-numeric k
    with pytest.raises(ValueError):
        LowLevelRequest('EQ', '5', [1, 2, 3])
def test_consistency():
    # From standard example
    # [ LowLevelRequest("EQ", 1, [1, 2]), LowLevelRequest("EQ", 1, [3, 4]), ...]
    backend_request = BackendRequest(0)

    Consistency.apply(block, backend_request)
    assert backend_request.ll_requests == \
        list(map(lambda x: LowLevelRequest("EQ", 1, [x, x+1]), range(1, 24, 2)))

    # Different case
    backend_request = BackendRequest(0)
    f = Factor("a", ["b", "c", "d", "e"])
    f_block = fully_cross_block([f], [f], [])

    Consistency.apply(f_block, backend_request)
    assert backend_request.ll_requests == \
        list(map(lambda x: LowLevelRequest("EQ", 1, [x, x+1, x+2, x+3]), range(1, 16, 4)))

    # Varied level lengths
    backend_request = BackendRequest(0)
    f1 = Factor("a", ["b", "c", "d"])
    f2 = Factor("e", ["f"])
    f_block = fully_cross_block([f1, f2], [f1, f2], [])

    Consistency.apply(f_block, backend_request)
    assert backend_request.ll_requests == [
        LowLevelRequest("EQ", 1, [1, 2, 3]),
        LowLevelRequest("EQ", 1, [4]),
        LowLevelRequest("EQ", 1, [5, 6, 7]),
        LowLevelRequest("EQ", 1, [8]),
        LowLevelRequest("EQ", 1, [9, 10, 11]),
        LowLevelRequest("EQ", 1, [12])
    ]
Beispiel #8
0
    def apply(block: Block, backend_request: BackendRequest) -> None:
        next_var = 1
        for _ in range(block.trials_per_sample()):
            for f in filter(lambda f: not f.has_complex_window, block.design):
                number_of_levels = len(f.levels)
                new_request = LowLevelRequest("EQ", 1, list(range(next_var, next_var + number_of_levels)))
                backend_request.ll_requests.append(new_request)
                next_var += number_of_levels

        for f in filter(lambda f: f.has_complex_window, block.design):
            variables_for_factor = block.variables_for_factor(f)
            var_list = list(map(lambda n: n + next_var, range(variables_for_factor)))
            chunks = list(chunk_list(var_list, len(f.levels)))
            backend_request.ll_requests += list(map(lambda v: LowLevelRequest("EQ", 1, v), chunks))
            next_var += variables_for_factor
Beispiel #9
0
 def apply_to_backend_request(self,
                              block: Block,
                              level: Tuple[Factor, Union[SimpleLevel, DerivedLevel]],
                              backend_request: BackendRequest
                              ) -> None:
     sublists = block.build_variable_list(level)
     backend_request.ll_requests.append(LowLevelRequest("EQ", self.k, sublists))
Beispiel #10
0
def test_nomorethankinarow_with_transition(design):
    block = fully_cross_block(design, [color, text], [])

    backend_request = __run_nomorethankinarow(
        NoMoreThanKInARow(1, ("color repeats?", "yes")), block)
    assert backend_request.ll_requests == [
        LowLevelRequest("LT", 2, [17, 19]),
        LowLevelRequest("LT", 2, [19, 21])
    ]

    backend_request = __run_nomorethankinarow(
        NoMoreThanKInARow(1, ("color repeats?", "no")), block)
    assert backend_request.ll_requests == [
        LowLevelRequest("LT", 2, [18, 20]),
        LowLevelRequest("LT", 2, [20, 22])
    ]
def test_consistency_with_multiple_transitions(design):
    block = fully_cross_block(design, [color, text], [])

    backend_request = BackendRequest(0)
    Consistency.apply(block, backend_request)

    assert backend_request.ll_requests == \
        list(map(lambda x: LowLevelRequest("EQ", 1, [x, x+1]), range(1, 28, 2)))
Beispiel #12
0
def test_nomorethankinarow_with_multiple_transitions():
    block = fully_cross_block(
        [color, text, color_repeats_factor, text_repeats_factor],
        [color, text], [])

    backend_request = __run_nomorethankinarow(
        NoMoreThanKInARow(1, ("text repeats?", "yes")), block)
    assert backend_request.ll_requests == [
        LowLevelRequest("LT", 2, [23, 25]),
        LowLevelRequest("LT", 2, [25, 27])
    ]

    backend_request = __run_nomorethankinarow(
        NoMoreThanKInARow(1, ("text repeats?", "no")), block)
    assert backend_request.ll_requests == [
        LowLevelRequest("LT", 2, [24, 26]),
        LowLevelRequest("LT", 2, [26, 28])
    ]
def test_consistency_with_transition(design):
    block = fully_cross_block(design, [color, text], [])

    backend_request = BackendRequest(0)
    Consistency.apply(block, backend_request)

    # Because the color_repeats_factor doesn't apply to the first trial, (there isn't a previous trial
    # to compare to) the variables only go up to 22.
    assert backend_request.ll_requests == \
        list(map(lambda x: LowLevelRequest("EQ", 1, [x, x+1]), range(1, 22, 2)))
Beispiel #14
0
    def apply(block: MultipleCrossBlock, backend_request: BackendRequest) -> None:
        # Treat each crossing seperately, and repeat the same process as fullycross
        for c in block.crossing:
            fresh = backend_request.fresh

            # Step 1: Get a list of the trials that are involved in the crossing.
            crossing_size = max(block.min_trials, block.crossing_size())
            crossing_trials = list(filter(lambda t: all(map(lambda f: f.applies_to_trial(t),
                                                            c)),
                                          range(1, block.trials_per_sample() + 1)))
            crossing_trials = crossing_trials[:crossing_size]

            # Step 2: For each trial, cross all levels of all factors in the crossing.
            crossing_factors = list(map(lambda t: (list(product(*[block.factor_variables_for_trial(f, t) for f in c]))), crossing_trials))

            # Step 3: For each trial, cross all levels of all design-only factors in the crossing.
            design_factors = cast(List[List[List[int]]], [])
            design_factors = list(map(lambda _: [], crossing_trials))
            for f in list(filter(lambda f: f not in c and not f.has_complex_window, block.design)):
                for i, t in enumerate(crossing_trials):
                    design_factors[i].append(block.factor_variables_for_trial(f, t))
            design_combinations = cast(List[List[Tuple[int, ...]]], [])
            design_combinations = list(map(lambda l: list(product(*l)), design_factors))

            # Step 4: For each trial, combine each of the crossing factors with all of the design-only factors.
            crossings = cast(List[List[List[Tuple[int, ...]]]], [])
            for i, t in enumerate(crossing_trials):
                crossings.append(list(map(lambda c: [c] + design_combinations[i], crossing_factors[i])))

            # Step 5: Remove crossings that are not possible.
            # From here on ignore all values other than the first in every list.
            crossings = block.filter_excluded_derived_levels(crossings)

            # Step 6: Allocate additional variables to represent each crossing.
            num_state_vars = list(map(lambda c: len(c), crossings))
            state_vars = list(range(fresh, fresh + sum(num_state_vars)))
            fresh += sum(num_state_vars)

            # Step 7: Associate each state variable with its crossing.
            flattened_crossings = list(chain.from_iterable(crossings))
            iffs = list(map(lambda n: Iff(state_vars[n], And([*flattened_crossings[n][0]])), range(len(state_vars))))

            # Step 8: Constrain each crossing to occur in only one trial.
            states = list(chunk(state_vars, block.crossing_size()))
            transposed = cast(List[List[int]], list(map(list, zip(*states))))

            # We Use n < 2 rather than n = 1 here because they may exclude some levels from the crossing.
            # This ensures that there won't be duplicates, while still allowing some to be missing.
            # backend_request.ll_requests += list(map(lambda l: LowLevelRequest("LT", 2, l), transposed))
            backend_request.ll_requests += list(map(lambda l: LowLevelRequest("GT", 0, l), transposed))

            (cnf, new_fresh) = block.cnf_fn(And(iffs), fresh)

            backend_request.cnfs.append(cnf)
            backend_request.fresh = new_fresh
def test_atmostkinarow_with_transition(design):
    block = fully_cross_block(design, [color, text], [])

    backend_request = __run_kinarow(
        AtMostKInARow(1, (color_repeats_factor,
                          get_level_from_name(color_repeats_factor, "yes"))),
        block)
    assert backend_request.ll_requests == [
        LowLevelRequest("LT", 2, [17, 19]),
        LowLevelRequest("LT", 2, [19, 21])
    ]

    backend_request = __run_kinarow(
        AtMostKInARow(1, (color_repeats_factor,
                          get_level_from_name(color_repeats_factor, "no"))),
        block)
    assert backend_request.ll_requests == [
        LowLevelRequest("LT", 2, [18, 20]),
        LowLevelRequest("LT", 2, [20, 22])
    ]
def test_consistency_with_general_window():
    design = [color, text, congruent_bookend]
    crossing = [color, text]
    block = fully_cross_block(design, crossing, [])

    backend_request = BackendRequest(0)
    Consistency.apply(block, backend_request)

    assert backend_request.ll_requests == [
        LowLevelRequest("EQ", 1, [1, 2]),
        LowLevelRequest("EQ", 1, [3, 4]),
        LowLevelRequest("EQ", 1, [5, 6]),
        LowLevelRequest("EQ", 1, [7, 8]),
        LowLevelRequest("EQ", 1, [9, 10]),
        LowLevelRequest("EQ", 1, [11, 12]),
        LowLevelRequest("EQ", 1, [13, 14]),
        LowLevelRequest("EQ", 1, [15, 16]),
        LowLevelRequest("EQ", 1, [17, 18]),
        LowLevelRequest("EQ", 1, [19, 20])
    ]
def test_atmostkinarow_with_multiple_transitions():
    block = fully_cross_block(
        [color, text, color_repeats_factor, text_repeats_factor],
        [color, text], [])

    backend_request = __run_kinarow(
        AtMostKInARow(1, (text_repeats_factor,
                          get_level_from_name(text_repeats_factor, "yes"))),
        block)
    assert backend_request.ll_requests == [
        LowLevelRequest("LT", 2, [23, 25]),
        LowLevelRequest("LT", 2, [25, 27])
    ]

    backend_request = __run_kinarow(
        AtMostKInARow(1, (text_repeats_factor,
                          get_level_from_name(text_repeats_factor, "no"))),
        block)
    assert backend_request.ll_requests == [
        LowLevelRequest("LT", 2, [24, 26]),
        LowLevelRequest("LT", 2, [26, 28])
    ]
def test_fully_cross_with_transition_in_crossing():
    direction = Factor("direction", ["up", "down"])

    block = fully_cross_block([direction, color, color_repeats_factor],
                              [direction, color_repeats_factor], [])

    backend_request = BackendRequest(29)
    FullyCross.apply(block, backend_request)

    (expected_cnf, _) = to_cnf_tseitin(
        And([
            Iff(29, And([5, 21])),
            Iff(30, And([5, 22])),
            Iff(31, And([6, 21])),
            Iff(32, And([6, 22])),
            Iff(33, And([9, 23])),
            Iff(34, And([9, 24])),
            Iff(35, And([10, 23])),
            Iff(36, And([10, 24])),
            Iff(37, And([13, 25])),
            Iff(38, And([13, 26])),
            Iff(39, And([14, 25])),
            Iff(40, And([14, 26])),
            Iff(41, And([17, 27])),
            Iff(42, And([17, 28])),
            Iff(43, And([18, 27])),
            Iff(44, And([18, 28])),
        ]), 45)

    assert backend_request.fresh == 78
    assert backend_request.cnfs == [expected_cnf]
    assert backend_request.ll_requests == [
        LowLevelRequest("GT", 0, [29, 33, 37, 41]),
        LowLevelRequest("GT", 0, [30, 34, 38, 42]),
        LowLevelRequest("GT", 0, [31, 35, 39, 43]),
        LowLevelRequest("GT", 0, [32, 36, 40, 44])
    ]
def test_consistency_with_transition_first_and_uneven_level_lengths():
    color3 = Factor("color3", ["red", "blue", "green"])

    yes_fn = lambda colors: colors[0] == colors[1] == colors[2]
    no_fn = lambda colors: not yes_fn(colors)
    color3_repeats_factor = Factor("color3 repeats?", [
        DerivedLevel("yes", Window(yes_fn, [color3], 3, 1)),
        DerivedLevel("no", Window(no_fn, [color3], 3, 1))
    ])

    block = fully_cross_block([color3_repeats_factor, color3, text],
                              [color3, text], [])

    backend_request = BackendRequest(0)
    Consistency.apply(block, backend_request)

    assert backend_request.ll_requests == [
        LowLevelRequest("EQ", 1, [1, 2, 3]),
        LowLevelRequest("EQ", 1, [4, 5]),
        LowLevelRequest("EQ", 1, [6, 7, 8]),
        LowLevelRequest("EQ", 1, [9, 10]),
        LowLevelRequest("EQ", 1, [11, 12, 13]),
        LowLevelRequest("EQ", 1, [14, 15]),
        LowLevelRequest("EQ", 1, [16, 17, 18]),
        LowLevelRequest("EQ", 1, [19, 20]),
        LowLevelRequest("EQ", 1, [21, 22, 23]),
        LowLevelRequest("EQ", 1, [24, 25]),
        LowLevelRequest("EQ", 1, [26, 27, 28]),
        LowLevelRequest("EQ", 1, [29, 30]),
        LowLevelRequest("EQ", 1, [31, 32]),
        LowLevelRequest("EQ", 1, [33, 34]),
        LowLevelRequest("EQ", 1, [35, 36]),
        LowLevelRequest("EQ", 1, [37, 38])
    ]
Beispiel #20
0
def test_nomorethankinarow():
    backend_request = __run_nomorethankinarow(NoMoreThanKInARow(3, color))
    assert backend_request.ll_requests == [
        LowLevelRequest("LT", 4, [1, 7, 13, 19]),
        LowLevelRequest("LT", 4, [2, 8, 14, 20])
    ]

    backend_request = __run_nomorethankinarow(
        NoMoreThanKInARow(1, ("color", "red")))
    assert backend_request.ll_requests == [
        LowLevelRequest("LT", 2, [1, 7]),
        LowLevelRequest("LT", 2, [7, 13]),
        LowLevelRequest("LT", 2, [13, 19])
    ]

    backend_request = __run_nomorethankinarow(
        NoMoreThanKInARow(2, ("color", "red")))
    assert backend_request.ll_requests == [
        LowLevelRequest("LT", 3, [1, 7, 13]),
        LowLevelRequest("LT", 3, [7, 13, 19])
    ]

    backend_request = __run_nomorethankinarow(
        NoMoreThanKInARow(1, ("color", "blue")))
    assert backend_request.ll_requests == [
        LowLevelRequest("LT", 2, [2, 8]),
        LowLevelRequest("LT", 2, [8, 14]),
        LowLevelRequest("LT", 2, [14, 20])
    ]

    backend_request = __run_nomorethankinarow(
        NoMoreThanKInARow(2, ("color", "blue")))
    assert backend_request.ll_requests == [
        LowLevelRequest("LT", 3, [2, 8, 14]),
        LowLevelRequest("LT", 3, [8, 14, 20])
    ]

    backend_request = __run_nomorethankinarow(
        NoMoreThanKInARow(3, ("congruent?", "con")))
    assert backend_request.ll_requests == [
        LowLevelRequest("LT", 4, [5, 11, 17, 23])
    ]

    backend_request = __run_nomorethankinarow(
        NoMoreThanKInARow(0, ("congruent?", "con")))
    assert backend_request.ll_requests == [
        LowLevelRequest("LT", 1, [5]),
        LowLevelRequest("LT", 1, [11]),
        LowLevelRequest("LT", 1, [17]),
        LowLevelRequest("LT", 1, [23])
    ]
def test_atmostkinarow():
    backend_request = __run_kinarow(AtMostKInARow(3, color))
    assert backend_request.ll_requests == [
        LowLevelRequest("LT", 4, [1, 7, 13, 19]),
        LowLevelRequest("LT", 4, [2, 8, 14, 20])
    ]

    backend_request = __run_kinarow(
        AtMostKInARow(1, (color, get_level_from_name(color, "red"))))
    assert backend_request.ll_requests == [
        LowLevelRequest("LT", 2, [1, 7]),
        LowLevelRequest("LT", 2, [7, 13]),
        LowLevelRequest("LT", 2, [13, 19])
    ]

    backend_request = __run_kinarow(
        AtMostKInARow(2, (color, get_level_from_name(color, "red"))))
    assert backend_request.ll_requests == [
        LowLevelRequest("LT", 3, [1, 7, 13]),
        LowLevelRequest("LT", 3, [7, 13, 19])
    ]

    backend_request = __run_kinarow(
        AtMostKInARow(1, (color, get_level_from_name(color, "blue"))))
    assert backend_request.ll_requests == [
        LowLevelRequest("LT", 2, [2, 8]),
        LowLevelRequest("LT", 2, [8, 14]),
        LowLevelRequest("LT", 2, [14, 20])
    ]

    backend_request = __run_kinarow(
        AtMostKInARow(2, (color, get_level_from_name(color, "blue"))))
    assert backend_request.ll_requests == [
        LowLevelRequest("LT", 3, [2, 8, 14]),
        LowLevelRequest("LT", 3, [8, 14, 20])
    ]

    backend_request = __run_kinarow(
        AtMostKInARow(3, (con_factor, get_level_from_name(con_factor, "con"))))
    assert backend_request.ll_requests == [
        LowLevelRequest("LT", 4, [5, 11, 17, 23])
    ]
Beispiel #22
0
    def apply_to_backend_request(self, block: Block, level: Tuple[Factor, Union[SimpleLevel, DerivedLevel]], backend_request: BackendRequest) -> None:
        sublists = self._build_variable_sublists(block, level, self.k + 1)

        # Build the requests
        backend_request.ll_requests += list(map(lambda l: LowLevelRequest("LT", self.k + 1, l), sublists))
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])),
            Iff(70, And([4, 5, 8])),
            Iff(71, And([4, 6, 7])),
            Iff(72, And([4, 6, 8])),
            Iff(73, And([11, 13, 15])),
            Iff(74, And([11, 13, 16])),
            Iff(75, And([11, 14, 15])),
            Iff(76, And([11, 14, 16])),
            Iff(77, And([12, 13, 15])),
            Iff(78, And([12, 13, 16])),
            Iff(79, And([12, 14, 15])),
            Iff(80, And([12, 14, 16])),
            Iff(81, And([19, 21, 23])),
            Iff(82, And([19, 21, 24])),
            Iff(83, And([19, 22, 23])),
            Iff(84, And([19, 22, 24])),
            Iff(85, And([20, 21, 23])),
            Iff(86, And([20, 21, 24])),
            Iff(87, And([20, 22, 23])),
            Iff(88, And([20, 22, 24])),
            Iff(89, And([27, 29, 31])),
            Iff(90, And([27, 29, 32])),
            Iff(91, And([27, 30, 31])),
            Iff(92, And([27, 30, 32])),
            Iff(93, And([28, 29, 31])),
            Iff(94, And([28, 29, 32])),
            Iff(95, And([28, 30, 31])),
            Iff(96, And([28, 30, 32])),
            Iff(97, And([35, 37, 39])),
            Iff(98, And([35, 37, 40])),
            Iff(99, And([35, 38, 39])),
            Iff(100, And([35, 38, 40])),
            Iff(101, And([36, 37, 39])),
            Iff(102, And([36, 37, 40])),
            Iff(103, And([36, 38, 39])),
            Iff(104, And([36, 38, 40])),
            Iff(105, And([43, 45, 47])),
            Iff(106, And([43, 45, 48])),
            Iff(107, And([43, 46, 47])),
            Iff(108, And([43, 46, 48])),
            Iff(109, And([44, 45, 47])),
            Iff(110, And([44, 45, 48])),
            Iff(111, And([44, 46, 47])),
            Iff(112, And([44, 46, 48])),
            Iff(113, And([51, 53, 55])),
            Iff(114, And([51, 53, 56])),
            Iff(115, And([51, 54, 55])),
            Iff(116, And([51, 54, 56])),
            Iff(117, And([52, 53, 55])),
            Iff(118, And([52, 53, 56])),
            Iff(119, And([52, 54, 55])),
            Iff(120, And([52, 54, 56])),
            Iff(121, And([59, 61, 63])),
            Iff(122, And([59, 61, 64])),
            Iff(123, And([59, 62, 63])),
            Iff(124, And([59, 62, 64])),
            Iff(125, And([60, 61, 63])),
            Iff(126, And([60, 61, 64])),
            Iff(127, And([60, 62, 63])),
            Iff(128, And([60, 62, 64])),
        ]), 129)

    backend_request = BackendRequest(65)
    FullyCross.apply(block, backend_request)

    assert backend_request.fresh == 258
    assert backend_request.cnfs == [expected_cnf]
    assert backend_request.ll_requests == [
        LowLevelRequest("GT", 0, [65, 73, 81, 89, 97, 105, 113, 121]),
        LowLevelRequest("GT", 0, [66, 74, 82, 90, 98, 106, 114, 122]),
        LowLevelRequest("GT", 0, [67, 75, 83, 91, 99, 107, 115, 123]),
        LowLevelRequest("GT", 0, [68, 76, 84, 92, 100, 108, 116, 124]),
        LowLevelRequest("GT", 0, [69, 77, 85, 93, 101, 109, 117, 125]),
        LowLevelRequest("GT", 0, [70, 78, 86, 94, 102, 110, 118, 126]),
        LowLevelRequest("GT", 0, [71, 79, 87, 95, 103, 111, 119, 127]),
        LowLevelRequest("GT", 0, [72, 80, 88, 96, 104, 112, 120, 128])
    ]