Example #1
0
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
Example #2
0
def is_cnf_still_sat(block: Block, additional_clauses: List[And]) -> bool:
    backend_request = block.build_backend_request()
    cnf = CNF(backend_request.get_cnfs_as_json()) + CNF(
        cnf_to_json(additional_clauses))
    combined_cnf = combine_cnf_with_requests(
        cnf, backend_request.fresh - 1, block.variables_per_sample(),
        backend_request.get_requests_as_generation_requests())
    return cnf_is_satisfiable(combined_cnf)
Example #3
0
def build_cnf(block: Block) -> CNF:
    """Converts a Block into a CNF represented as a Unigen-compatible string.
    """
    backend_request = block.build_backend_request()
    cnf = CNF(backend_request.get_cnfs_as_json())
    combined_cnf = combine_cnf_with_requests(
        cnf, backend_request.fresh - 1, block.variables_per_sample(),
        backend_request.get_requests_as_generation_requests())
    return combined_cnf
Example #4
0
    def sample(block: Block, sample_count: int) -> SamplingResult:
        backend_request = block.build_backend_request()
        if block.errors:
            for e in block.errors:
                print(e)
                if "WARNING" not in e:
                    return SamplingResult([], {})

        solutions = sample_non_uniform(
            sample_count, CNF(backend_request.get_cnfs_as_json()),
            backend_request.fresh - 1, block.variables_per_sample(),
            backend_request.get_requests_as_generation_requests())

        result = list(
            map(lambda s: SamplingStrategy.decode(block, s.assignment),
                solutions))
        return SamplingResult(result, {})
Example #5
0
def __decode(block: Block, solution: List[int]) -> dict:
    gt0 = lambda n: n > 0
    simple_variables = list(filter(gt0, solution[:block.grid_variables()]))
    complex_variables = list(
        filter(gt0,
               solution[block.grid_variables():block.variables_per_sample()]))

    experiment = cast(dict, {})

    # Simple factors
    tuples = list(map(lambda v: block.decode_variable(v), simple_variables))
    for (factor_name, level_name) in tuples:
        if factor_name not in experiment:
            experiment[factor_name] = []
        experiment[factor_name].append(level_name)

    # Complex factors - The challenge here is knowing when to insert '', rather than using the variables.
    # Start after 'width' trials, and shift 'stride' trials for each variable.
    complex_factors = list(
        filter(lambda f: f.has_complex_window(), block.design))
    for f in complex_factors:
        # Get variables for this factor
        start = block.first_variable_for_level(f.name, f.levels[0].name) + 1
        end = start + block.variables_for_factor(f)
        variables = list(
            filter(lambda n: n in range(start, end), complex_variables))

        # Get the level names for the variables in the solution.
        level_names = list(
            map(lambda v: block.decode_variable(v)[1], variables))

        # Intersperse empty strings for the trials to which this factor does not apply.
        level_names = list(
            intersperse('', level_names, f.levels[0].window.stride - 1))
        level_names = list(repeat('',
                                  f.levels[0].window.width - 1)) + level_names

        experiment[f.name] = level_names

    return experiment
Example #6
0
def __generate_json_data(block: Block) -> str:
    backend_request = __desugar(block)
    support = block.variables_per_sample()
    solution_count = __count_solutions(block)
    return backend_request.to_json(support, solution_count)
Example #7
0
def __run_kinarow(c: Constraint, block: Block = block) -> BackendRequest:
    backend_request = BackendRequest(block.variables_per_sample() + 1)
    for dc in c.desugar():
        dc.apply(block, backend_request)
    return backend_request
Example #8
0
    def sample(block: Block,
               sample_count: int,
               min_search: bool = False) -> SamplingResult:

        backend_request = block.build_backend_request()
        if block.errors:
            for e in block.errors:
                print(e)
                if "WARNING" not in e:
                    return SamplingResult([], {})

        solutions = sample_uniform(
            sample_count, CNF(backend_request.get_cnfs_as_json()),
            backend_request.fresh - 1, block.variables_per_sample(),
            backend_request.get_requests_as_generation_requests(), False)

        if not solutions:
            from sweetpea.constraints import AtLeastKInARow
            if min_search:
                return SamplingResult([], {})
            else:
                max_constraints = list(
                    map(
                        lambda x: cast(AtLeastKInARow, x).max_trials_required,
                        filter(lambda c: isinstance(c, AtLeastKInARow),
                               block.constraints)))

                if max_constraints:
                    print(
                        "No solution found... We require a minimum trials contraint to find a solution."
                    )
                    max_constraint = max(max_constraints)
                    min_constraint = block.trials_per_sample() + 1
                    original_min_trials = block.min_trials
                    last_valid_min_contraint = max_constraint
                    last_valid = SamplingResult([], {})
                    progress = tqdm(total=math.ceil(
                        math.log(max_constraint - min_constraint)) + 1,
                                    file=sys.stdout)
                    while True:
                        current_constraint = int(
                            (max_constraint - min_constraint + 1) /
                            2) + min_constraint
                        block.min_trials = original_min_trials
                        c = minimum_trials(current_constraint)
                        c.validate(block)
                        c.apply(block, None)
                        block.constraints.append(c)
                        res = UnigenSamplingStrategy.sample(
                            block, sample_count, True)
                        progress.update(1)
                        if res.samples:
                            if current_constraint <= min_constraint:
                                print(
                                    "Optimal minimum trials contraint is at ",
                                    current_constraint, ".")
                                return res
                            else:
                                last_valid_min_contraint = current_constraint
                                last_valid = res
                                max_constraint = current_constraint - 1
                        else:
                            if max_constraint <= current_constraint:
                                print(
                                    "Optimal minimum trials contraint is at ",
                                    last_valid_min_contraint, ".")
                                return last_valid
                            else:
                                min_constraint = current_constraint + 1
                    progress.close()
                    return result
                else:
                    return SamplingResult([], {})

        result = list(
            map(lambda s: SamplingStrategy.decode(block, s.assignment),
                solutions))
        return SamplingResult(result, {})
Example #9
0
def __generate_encoding_diagram(blk: Block) -> str:
    diagram_str = ""

    design_size = blk.variables_per_trial()
    num_trials = blk.trials_per_sample()
    num_vars = blk.variables_per_sample()

    largest_number_len = len(str(num_vars))

    header_widths = []
    row_format_str = '| {:>7} |'
    for f in blk.design:
        # length of all levels concatenated for this factor
        level_names = list(map(get_external_level_name, f.levels))
        level_name_widths = [
            max(largest_number_len, l) for l in list(map(len, level_names))
        ]

        level_names_width = sum(level_name_widths) + len(
            level_names) - 1  # Extra length for spaces in between names.
        factor_header_width = max(len(f.factor_name), level_names_width)
        header_widths.append(factor_header_width)

        # If the header is longer than the level widths combined, then they need to be lengthened.
        diff = factor_header_width - level_names_width
        if diff > 0:
            idx = 0
            while diff > 0:
                level_name_widths[idx] += 1
                idx += 1
                diff -= 1
                if idx >= len(level_name_widths):
                    idx = 0

        # While we're here, build up the row format str.
        row_format_str = reduce(lambda a, b: a + ' {{:^{}}}'.format(b),
                                level_name_widths, row_format_str)
        row_format_str += ' |'

    header_format_str = reduce(lambda a, b: a + ' {{:^{}}} |'.format(b),
                               header_widths, '| {:>7} |')
    factor_names = list(map(lambda f: f.factor_name, blk.design))
    header_str = header_format_str.format(*["Trial"] + factor_names)
    row_width = len(header_str)

    # First line
    diagram_str += ('-' * row_width) + '\n'

    # Header
    diagram_str += header_str + '\n'

    # Level names
    all_level_names = [
        ln for (fn, ln) in get_all_external_level_names(blk.design)
    ]
    diagram_str += row_format_str.format(*['#'] + all_level_names) + '\n'

    # Separator
    diagram_str += ('-' * row_width) + '\n'

    # Variables
    for t in range(num_trials):
        args = [str(t + 1)]
        for f in blk.design:
            if f.applies_to_trial(t + 1):
                variables = [
                    blk.first_variable_for_level(f, l) + 1 for l in f.levels
                ]
                if f.has_complex_window():

                    def acc_width(w) -> int:
                        return w.width + (
                            acc_width(w.args[0].levels[0].window) -
                            1 if w.args[0].has_complex_window() else 0)

                    width = acc_width(f.levels[0].window)
                    stride = f.levels[0].window.stride
                    stride_offset = (stride - 1) * int(t / stride)
                    offset = t - width + 1 - stride_offset
                    variables = list(
                        map(lambda n: n + len(variables) * offset, variables))
                else:
                    variables = list(
                        map(lambda n: n + design_size * t, variables))

                args += list(map(str, variables))
            else:
                args += list(repeat('', len(f.levels)))

        diagram_str += row_format_str.format(*args) + '\n'

    # Footer
    diagram_str += ('-' * row_width) + '\n'
    return diagram_str
Example #10
0
    def sample(block: Block,
               sample_count: int,
               min_search: bool = False) -> SamplingResult:

        backend_request = block.build_backend_request()
        if block.errors:
            for e in block.errors:
                print(e)
                if "WARNING" not in e:
                    return SamplingResult([], {})

        solutions = sample_uniform(
            sample_count, CNF(backend_request.get_cnfs_as_json()),
            backend_request.fresh - 1, block.variables_per_sample(),
            backend_request.get_requests_as_generation_requests(), False)

        # This section deals with the problem caused by a corner case created
        # by at_least_k_in_a_row_constraint. I.e. in some cases this cotnraint
        # requires the support of a minimum_trials contraint to find valid
        # solutions. This will find the optimal minimum trials constraint to
        # the user using binary search with trial and error.
        if not solutions:
            from sweetpea.constraints import AtLeastKInARow
            if min_search:
                return SamplingResult([], {})
            else:
                atleast_constraints = cast(
                    List[AtLeastKInARow],
                    filter(lambda c: isinstance(c, AtLeastKInARow),
                           block.constraints))
                max_constraints = list(
                    map(lambda x: x.max_trials_required, atleast_constraints))

                if max_constraints:
                    print(
                        "No solution found... We require a minimum trials contraint to find a solution."
                    )
                    max_constraint = max(max_constraints)
                    min_constraint = block.trials_per_sample() + 1
                    original_min_trials = block.min_trials
                    last_valid_min_contraint = max_constraint
                    last_valid = SamplingResult([], {})
                    progress = tqdm(
                        total=ceil(log(max_constraint - min_constraint)) + 1,
                        file=sys.stdout)
                    while True:
                        current_constraint = int(
                            (max_constraint - min_constraint + 1) /
                            2) + min_constraint
                        block.min_trials = original_min_trials
                        c = minimum_trials(current_constraint)
                        c.validate(block)
                        c.apply(block, None)
                        block.constraints.append(c)
                        res = UnigenSamplingStrategy.sample(
                            block, sample_count, True)
                        progress.update(1)
                        if res.samples:
                            if current_constraint <= min_constraint:
                                print(
                                    "Optimal minimum trials contraint is at ",
                                    current_constraint, ".")
                                return res
                            else:
                                last_valid_min_contraint = current_constraint
                                last_valid = res
                                max_constraint = current_constraint - 1
                        else:
                            if max_constraint <= current_constraint:
                                print(
                                    "Optimal minimum trials contraint is at ",
                                    last_valid_min_contraint, ".")
                                return last_valid
                            else:
                                min_constraint = current_constraint + 1
                    progress.close()
                    return result
                else:
                    return SamplingResult([], {})

        result = list(
            map(lambda s: SamplingStrategy.decode(block, s.assignment),
                solutions))
        return SamplingResult(result, {})