Exemple #1
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)
def test_uniform_combinatoric_is_always_valid(filename):

    failures = []
    contents = None
    with open(filename, 'r') as f:
        contents = f.read()
        exec(contents, globals(), locals())

    if 'block' not in vars():
        pytest.fail(
            "File did not produce a variable named 'block', aborting. file={}".
            format(filename))

    # Build the CNF for this block
    build_cnf_result = build_cnf(vars()['block'])

    # Build the sampler
    enumerator = UCSolutionEnumerator(vars()['block'])

    # Generate some samples, make sure they're all SAT.
    sample_count = min(enumerator.solution_count(), 200)
    print("Checking that UC samples are SAT for {}, sample count={}".format(
        filename, sample_count))
    for s in range(sample_count):
        sample = enumerator.generate_solution_variables()
        if not cnf_is_satisfiable(build_cnf_result +
                                  CNF(cnf_to_json([And(sample)]))):
            failures.append("Found UNSAT solution! Solution={} File={}".format(
                sample, filename))

    if failures:
        pytest.fail(
            '{} failures occurred in SAT checks for UC sampler: {}'.format(
                len(failures), failures))
Exemple #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
Exemple #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, {})
#!/usr/bin/env python3


"""A small script to test whether calls to Unigen work.

NOTE: These calls may be nonsensical --- I just put something together.
"""


from sweetpea.core import (
    AssertionType, CNF, GenerationRequest, Var,
    cnf_is_satisfiable, sample_uniform, sample_non_uniform)

cnf = CNF()
a, b = cnf.get_n_fresh(2)
_, _ = cnf.half_adder(a, b)

print("Calling sample_uniform...")
sample_uniform(cnf, 2, 0, [GenerationRequest(AssertionType.EQ, 3, [Var(1)])])
print("Success.")

print("")
print("Calling sample_non_uniform...")
sample_non_uniform(2, cnf, 2, 3, [GenerationRequest(AssertionType.EQ, 2, [Var(-2)])])
print("Success.")

print("")
print("Calling cnf_is_satisfiable...")
cnf_is_satisfiable(cnf)
print("Success.")
Exemple #6
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, {})
Exemple #7
0
    def __generate_sample(block: Block, cnf: CNF,
                          sample_metrics: dict) -> dict:
        sample_metrics['trials'] = []

        # Start a 'committed' list of CNFs
        committed = cast(List[And], [])

        for trial_number in range(block.trials_per_sample()):
            trial_start_time = time()

            trial_metrics = {'t': trial_number + 1, 'solver_calls': []}
            solver_calls = cast(List[dict], trial_metrics['solver_calls'])

            #  Get the variable list for this trial.
            variables = block.variable_list_for_trial(trial_number + 1)
            variables = list(filter(lambda i: i != [], variables))
            potential_trials = list(map(list, product(*variables)))

            trial_metrics['potential_trials'] = len(potential_trials)

            # Use env var to switch between filtering and not
            if GuidedSamplingStrategy.__prefilter_enabled():
                # Flatten the list
                flat_vars = list(chain(*variables))

                # Check SAT for each one
                unsat = []
                for v in flat_vars:
                    t_start = time()
                    full_cnf = cnf + CNF(cnf_to_json(committed)) + CNF(
                        cnf_to_json([And([v])]))
                    allowed = cnf_is_satisfiable(full_cnf)
                    duration_seconds = time() - t_start
                    solver_calls.append({
                        'time': duration_seconds,
                        'SAT': allowed
                    })
                    if not allowed:
                        unsat.append(v)

                # TODO: Count filtering SAT calls separately?

                # Filter out any potential trials with those vars set
                filtered_pts = []
                for pt in potential_trials:
                    if any(uv in pt for uv in unsat):
                        continue
                    else:
                        filtered_pts.append(pt)

                # Record the number filterd out for metrics
                trial_metrics['prefiltered_out'] = len(potential_trials) - len(
                    filtered_pts)
                potential_trials = filtered_pts

            allowed_trials = []
            for potential_trial in potential_trials:
                start_time = time()
                full_cnf = cnf + CNF(cnf_to_json(committed)) + CNF(
                    cnf_to_json([And(potential_trial)]))
                allowed = cnf_is_satisfiable(full_cnf)
                duration_seconds = time() - start_time

                solver_calls.append({'time': duration_seconds, 'SAT': allowed})

                if allowed:
                    allowed_trials.append(potential_trial)

            trial_metrics['allowed_trials'] = len(allowed_trials)
            trial_metrics['solver_call_count'] = len(solver_calls)
            sample_metrics['trials'].append(trial_metrics)

            # Randomly sample a single trial from the uniform distribution of the allowed trials,
            # and commit that trial to the committed sequence.
            trial_idx = np.random.randint(0, len(allowed_trials))
            committed.append(And(allowed_trials[trial_idx]))

            trial_metrics['time'] = time() - trial_start_time

        # Aggregate the total solver calls
        sample_metrics['solver_call_count'] = 0
        for tm in sample_metrics['trials']:
            sample_metrics['solver_call_count'] += tm['solver_call_count']

        # Flatten the committed trials into a list of integers and decode it.
        solution = GuidedSamplingStrategy.__committed_to_solution(committed)
        return SamplingStrategy.decode(block, solution)
Exemple #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)

        # 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, {})