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]) ]
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 test_forbid(): f = Forbid(("color", "red")) backend_request = BackendRequest(0) f.apply(block, backend_request) assert backend_request.cnfs == [And([-1, -7, -13, -19])] f = Forbid(("congruent?", "con")) backend_request = BackendRequest(0) f.apply(block, backend_request) assert backend_request.cnfs == [And([-5, -11, -17, -23])]
def test_exclude(): f = Exclude(color, get_level_from_name(color, "red")) backend_request = BackendRequest(0) f.apply(block, backend_request) assert backend_request.cnfs == [And([-1, -7, -13, -19])] f = Exclude(con_factor, get_level_from_name(con_factor, "con")) backend_request = BackendRequest(0) f.apply(block, backend_request) assert backend_request.cnfs == [And([-5, -11, -17, -23])]
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_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_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_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_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]) ]
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) implications = [] # Handle the regular cases (1 => 2 ^ ... ^ n ^ ~n+1) trim = len(sublists) if self.k > 1 else len(sublists) - 1 for idx, l in enumerate(sublists[:trim]): if idx > 0: p_list = [Not(sublists[idx-1][0]), l[0]] p = And(p_list) if len(p_list) > 1 else p_list[0] else: p = l[0] if idx < len(sublists) - 1: q_list = cast(List[Any], l[1:]) + [Not(sublists[idx+1][-1])] q = And(q_list) if len(q_list) > 1 else q_list[0] else: q = And(l[1:]) if len(l[1:]) > 1 else l[self.k - 1] implications.append(If(p, q)) # Handle the tail if len(sublists[-1]) > 1: tail = sublists[-1] tail.reverse() for idx in range(len(tail) - 1): implications.append(If(l[idx], l[idx + 1])) (cnf, new_fresh) = block.cnf_fn(And(implications), backend_request.fresh) backend_request.cnfs.append(cnf) backend_request.fresh = new_fresh
def test_exclude_with_three_derived_levels(): color_list = ["red", "green", "blue"] color = Factor("color", color_list) text = Factor("text", color_list) def count_diff(colors, texts): changes = 0 if (colors[0] != colors[1]): changes += 1 if (texts[0] != texts[1]): changes += 1 return changes def make_k_diff_level(k): def k_diff(colors, texts): return count_diff(colors, texts) == k return DerivedLevel(str(k), Transition(k_diff, [color, text])) changed = Factor( "changed", [make_k_diff_level(0), make_k_diff_level(1), make_k_diff_level(2)]) exclude_constraint = Exclude(changed, get_level_from_name(changed, "2")) design = [color, text, changed] crossing = [color, text] block = fully_cross_block(design, crossing, [exclude_constraint]) backend_request = BackendRequest(0) exclude_constraint.apply(block, backend_request) assert backend_request.cnfs == [ And([-57, -60, -63, -66, -69, -72, -75, -78]) ]
def __desugar(block: Block) -> BackendRequest: fresh = 1 + block.variables_per_sample() backend_request = BackendRequest(fresh) for c in block.constraints: c.apply(block, backend_request) return backend_request
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)))
def test_exclude_with_transition(): block = fully_cross_block([color, text, color_repeats_factor], [color, text], []) c = Exclude(color_repeats_factor, get_level_from_name(color_repeats_factor, "yes")) backend_request = BackendRequest(0) c.apply(block, backend_request) assert backend_request.cnfs == [And([-17, -19, -21])]
def test_exclude_with_general_window(): block = fully_cross_block([color, text, congruent_bookend], [color, text], []) c = Exclude(congruent_bookend, get_level_from_name(congruent_bookend, "yes")) backend_request = BackendRequest(0) c.apply(block, backend_request) assert backend_request.cnfs == [And([-17, -19])]
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)))
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 build_backend_request(self) -> BackendRequest: fresh = 1 + self.variables_per_sample() backend_request = BackendRequest(fresh) from sweetpea.constraints import MinimumTrials for c in self.constraints: if isinstance(c, MinimumTrials): continue c.apply(self, backend_request) return backend_request
def __apply_derivation(self, block: Block, backend_request: BackendRequest) -> None: trial_size = block.variables_per_trial() cross_size = block.trials_per_sample() iffs = [] for n in range(cross_size): or_clause = Or(list(And(list(map(lambda x: x + (n * trial_size) + 1, l))) for l in self.dependent_idxs)) iffs.append(Iff(self.derived_idx + (n * trial_size) + 1, or_clause)) (cnf, new_fresh) = block.cnf_fn(And(iffs), backend_request.fresh) backend_request.cnfs.append(cnf) backend_request.fresh = new_fresh
def build_backend_request(self) -> BackendRequest: """Apply all constraints to build a :class:`.BackendRequest`. Formerly known as ``__desugar``. """ fresh = 1 + self.variables_per_sample() backend_request = BackendRequest(fresh) from sweetpea.constraints import MinimumTrials for c in self.constraints: if isinstance(c, MinimumTrials): continue c.apply(self, backend_request) return backend_request
def apply_to_backend_request(self, block: Block, level: Tuple[Factor, Union[SimpleLevel, DerivedLevel]], backend_request: BackendRequest) -> None: # Request sublists for k+1 to allow us to determine the transition sublists = self._build_variable_sublists(block, level, self.k + 1) implications = [] if sublists: # Starting corner case implications.append(If(sublists[0][0], And(sublists[0][1:-1]))) for sublist in sublists: implications.append(If(And([Not(sublist[0]), sublist[1]]), And(sublist[2:]))) # Ending corner case implications.append(If(sublists[-1][-1], And(sublists[-1][1:-1]))) (cnf, new_fresh) = block.cnf_fn(And(implications), backend_request.fresh) backend_request.cnfs.append(cnf) backend_request.fresh = new_fresh
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]
def __apply_derivation_with_complex_window(self, block: Block, backend_request: BackendRequest) -> None: trial_size = block.variables_per_trial() trial_count = block.trials_per_sample() iffs = [] f = self.factor window = f.levels[0].window t = 0 for n in range(trial_count): if not f.applies_to_trial(n + 1): continue num_levels = len(f.levels) get_trial_size = lambda x: trial_size if x < block.grid_variables() else len(block.decode_variable(x+1)[0].levels) or_clause = Or(list(And(list(map(lambda x: x + (t * window.stride * get_trial_size(x) + 1), l))) for l in self.dependent_idxs)) iffs.append(Iff(self.derived_idx + (t * num_levels) + 1, or_clause)) t += 1 (cnf, new_fresh) = block.cnf_fn(And(iffs), backend_request.fresh) backend_request.cnfs.append(cnf) backend_request.fresh = new_fresh
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_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_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])]
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]