Beispiel #1
0
 def to_smtlib(self):
     """Return a SMT_LIB string representation of the formula."""
     sc.reset_env()
     i_f = sc.And(*[bv2pysmt(a) for a in self.inner_problem.assertions])
     o_f = sc.And(*[bv2pysmt(a) for a in self.outer_problem.assertions])
     pysmt_formula = sc.And(i_f, o_f)
     return sc.to_smtlib(pysmt_formula, daggify=False)
Beispiel #2
0
def generate_strict_cnf(domain, and_count, or_count, half_space_count):
    half_spaces = [generate_half_space_sample(domain, len(domain.real_vars)) for _ in range(half_space_count)]
    candidates = [domain.get_symbol(v) for v in domain.bool_vars] + half_spaces
    candidates += [smt.Not(c) for c in candidates]

    formulas = []
    iteration = 0
    max_iterations = 100 * and_count
    while len(formulas) < and_count:
        if iteration >= max_iterations:
            return generate_strict_cnf(domain, and_count, or_count, half_space_count)
        iteration += 1
        formula_candidates = [c for c in candidates]
        random.shuffle(formula_candidates)
        formula = []
        try:
            while len(formula) < or_count:
                next_term = formula_candidates.pop(0)
                if len(formula) == 0 or smt.is_sat(~smt.Or(*formula) & next_term):
                    formula.append(next_term)
        except IndexError:
            continue
        if len(formulas) == 0 or smt.is_sat(~smt.And(*[smt.Or(*f) for f in formulas]) & smt.Or(*formula)):
            formulas.append(formula)
    return smt.And(*[smt.Or(*f) for f in formulas])
Beispiel #3
0
    def pysmt_formula_size(self):
        """The size of the underlying bit-vector formula according to pySMT."""
        sc.reset_env()
        i_f = sc.And(*[bv2pysmt(a) for a in self.inner_problem.assertions])
        o_f = sc.And(*[bv2pysmt(a) for a in self.outer_problem.assertions])
        pysmt_formula = sc.And(i_f, o_f)

        return sc.get_formula_size(pysmt_formula)
Beispiel #4
0
    def to_smtlib(self):
        """Return a SMT_LIB string representation of the formula.

            >>> from arxpy.bitvector.function import Function
            >>> from arxpy.diffcrypt.difference import XorDiff, DiffVar
            >>> from arxpy.diffcrypt.characteristic import Characteristic
            >>> from arxpy.diffcrypt.smt import SmtProblem
            >>> class MyFunction(Function):
            ...     input_widths = [8, 8, 8]
            ...     output_widths = [8, 8]
            ...     @classmethod
            ...     def eval(cls, x, y, k):
            ...         return (y + k, (y + k) ^ x)
            >>> x, y, k = DiffVar("x", 8), DiffVar("y", 8), DiffVar("k", 8)
            >>> ch = Characteristic(MyFunction, XorDiff, [x, y, k])
            >>> smt_problem = SmtProblem(ch, 0)
            >>> print(smt_problem.to_smtlib())  # doctest:+ELLIPSIS
            (and (not (= #b000000000000000000000000 (concat (concat x y) k))) ...

        Note that a more human-readable from can be obtained by
        printing the SmtProblem directly (print(smt_problem)).
        """
        sc.reset_env()
        pysmt_formula = sc.And(*[bv2pysmt(a) for a in self.assertions])
        return sc.to_smtlib(pysmt_formula, daggify=False)
Beispiel #5
0
def make_from_graph(graph):
    n = graph.vcount()
    domain = Domain.make([], [f"x{i}" for i in range(n)], real_bounds=(-1, 1))
    X = domain.get_symbols()
    support = smt.And(*((X[e.source] + 1 <= X[e.target]) | (X[e.target] <= X[e.source] - 1)
                        for e in graph.es))
    return Density(domain, support & domain.get_bounds(), smt.Real(1))
Beispiel #6
0
    def get_formula(self, name, literal_pool):
        print("Generate formula:")
        for i in range(self.max_tries):
            terms = [self.get_term(literal_pool) for _ in range(self.k)]
            formula = smt.And(*list(zip(*terms))[0])

            covered = np.ones(self.sample_count)
            significant_terms = 0
            for _, labels in terms:
                prev_size = sum(covered)
                covered = np.logical_and(covered, labels)
                if (prev_size - sum(covered)) / self.sample_count >= 0.05:
                    significant_terms += 1

            if significant_terms == self.k and self.test_ratio(covered):
                print("y({:.2f})".format(sum(covered) / self.sample_count),
                      end="")
                return SyntheticFormula(self.domain, formula, "cnf", self.k,
                                        self.l, self.h, name)
            else:
                if significant_terms == self.k:
                    print("Ratio not satisfied")
                else:
                    print("Not enough significant terms")
        print("Failed to generate formula after {} tries".format(
            self.max_tries))
        raise GeneratorError()
Beispiel #7
0
    def get_formula(self, name, literal_pool):
        from bitarray import bitarray

        print("Generate formula:")
        for i in range(self.max_tries):
            terms = [self.get_term(literal_pool) for _ in range(self.k)]
            formula = smt.And(*list(zip(*terms))[0])

            covered = bitarray(self.sample_count)
            covered.setall(True)
            significant_terms = 0
            for _, bits in terms:
                prev_size = covered.count()
                covered &= bits
                if (prev_size - covered.count()) / self.sample_count >= 0.05:
                    significant_terms += 1

            if significant_terms == self.k and self.test_ratio(covered):
                print("y({:.2f})".format(covered.count() / self.sample_count), end="")
                data_set = self.get_data_set(name, formula)
                data_set_positives = bitarray([example[1] for example in data_set.samples])
                if self.test_ratio(data_set_positives):
                    print("c({:.2f})".format(data_set_positives.count() / self.sample_count))
                    return data_set
                else:
                    print("r({:.2f})".format(data_set_positives.count() / self.sample_count))
            else:
                if not self.test_ratio(covered):
                    print("Ratio not satisfied")
                else:
                    print("Not enough significant terms")
        print("Failed to generate formula after {} tries".format(self.max_tries))
        raise GeneratorError()
Beispiel #8
0
def univariate(n):
    domain = Domain.make([], ["x{}".format(i) for i in range(n)], real_bounds=(-2, 2))
    x_vars = domain.get_symbols()
    support = smt.And(*[x > 0.5 for x in x_vars])
    weight = smt.Times(*[smt.Ite((x > -1) & (x < 1), smt.Ite(x < 0, x + smt.Real(1), -x + smt.Real(1)), smt.Real(0))
                         for x in x_vars])
    return FileDensity(domain, support, weight)
Beispiel #9
0
    def add_dip_checker(self, dis_boolean, dis_out):
        for d in range(self.unroll_depth + 1):
            c0, c1 = self.attack_formulas.obf_ckt_at_frame(d)
            subs = {}
            c2 = []

            if d > 0:
                dip_out = dis_out[d - 1]
                for i in range(len(self.obf_cir.output_wires)):
                    subs[pystm.Symbol(self.obf_cir.output_wires[i] + '_0@{}'.format(d))] = dip_out[i]
                    subs[pystm.Symbol(self.obf_cir.output_wires[i] + '_1@{}'.format(d))] = dip_out[i]

                dip_boolean = dis_boolean[d - 1]
                for i in range(len(self.obf_cir.input_wires)):
                    subs[pystm.Symbol(self.obf_cir.input_wires[i] + '@{}'.format(d))] = dip_boolean[i]

                for i in range(len(self.obf_cir.next_state_wires)):
                    subs[pystm.Symbol(self.obf_cir.next_state_wires[i] + '_0@{}'.format(d - 1))] = pystm.Symbol(self.obf_cir.next_state_wires[i] + '_0_{}@{}'.format(self.iteration, d - 1))
                    subs[pystm.Symbol(self.obf_cir.next_state_wires[i] + '_1@{}'.format(d - 1))] = pystm.Symbol(self.obf_cir.next_state_wires[i] + '_1_{}@{}'.format(self.iteration, d - 1))
                    subs[pystm.Symbol(self.obf_cir.next_state_wires[i] + '_0@{}'.format(d))] = pystm.Symbol(self.obf_cir.next_state_wires[i] + '_0_{}@{}'.format(self.iteration, d))
                    subs[pystm.Symbol(self.obf_cir.next_state_wires[i] + '_1@{}'.format(d))] = pystm.Symbol(self.obf_cir.next_state_wires[i] + '_1_{}@{}'.format(self.iteration, d))
                    subs[pystm.Symbol(self.obf_cir.state_wires[i] + '_0@{}'.format(d))] = pystm.Symbol(self.obf_cir.state_wires[i] + '_0_{}@{}'.format(self.iteration, d))
                    subs[pystm.Symbol(self.obf_cir.state_wires[i] + '_1@{}'.format(d))] = pystm.Symbol(self.obf_cir.state_wires[i] + '_1_{}@{}'.format(self.iteration, d))
            else:
                for i in range(len(self.obf_cir.next_state_wires)):
                    subs[pystm.Symbol(self.obf_cir.next_state_wires[i] + '_0@{}'.format(d))] = pystm.Symbol(self.obf_cir.next_state_wires[i] + '_0_{}@{}'.format(self.iteration, d))
                    subs[pystm.Symbol(self.obf_cir.next_state_wires[i] + '_1@{}'.format(d))] = pystm.Symbol(self.obf_cir.next_state_wires[i] + '_1_{}@{}'.format(self.iteration, d))

            c = pystm.substitute(pystm.And(c0 + c1 + c2), subs)
            self.solver_obf.add_assertion(c)
            self.solver_key.add_assertion(c)
Beispiel #10
0
    def query_oracle(self, dis_formula):
        self.solver_oracle.reset_assertions()
        c0 = self.attack_formulas.oracle_ckt_at_frame(0)
        for i in range(len(c0)):
            self.solver_oracle.add_assertion(c0[i])

        dis_out = []
        for d in range(1, self.unroll_depth + 1):
            c0 = self.attack_formulas.oracle_ckt_at_frame(d)
            for i in range(len(c0)):
                self.solver_oracle.add_assertion(c0[i])

            self.solver_oracle.add_assertion(pystm.And(dis_formula[d - 1]))
            if not self.solver_oracle.is_sat(pystm.TRUE()):
                logging.critical('something is wrong in oracle query')
                exit()
            else:
                dip_out = []
                # for w in self.oracle_cir.output_wires:
                for w in self.obf_cir.output_wires:
                    f = pystm.Symbol(w + '@{}'.format(d))
                    dip_out.append(self.solver_oracle.get_value(f))
                dis_out.append(dip_out)
        logging.info(dis_out)
        return dis_out
    def integrate(self, domain, convex_bounds: List[LinearInequality],
                  polynomial: Polynomial):
        formula = smt.And(*[i.to_smt() for i in convex_bounds])

        if self.bounding_box > 0:
            if self.bounding_box == 1:
                a_matrix = numpy.zeros(
                    (len(convex_bounds), len(domain.real_vars)))
                b_matrix = numpy.zeros((len(convex_bounds), ))
                for i, bound in enumerate(convex_bounds):
                    for j in range(len(domain.real_vars)):
                        a_matrix[i, j] = bound.a(domain.real_vars[j])
                    b_matrix[i] = bound.b()

                lb_ub_bounds = {}
                c = numpy.zeros((len(domain.real_vars), ))
                for j in range(len(domain.real_vars)):
                    c[j] = 1
                    # noinspection PyTypeChecker
                    lb = scipy.optimize.linprog(c, a_matrix, b_matrix).x[j]
                    # noinspection PyTypeChecker
                    ub = scipy.optimize.linprog(-c, a_matrix, b_matrix).x[j]
                    c[j] = 0
                    lb_ub_bounds[domain.real_vars[j]] = (lb, ub)
            elif self.bounding_box == 2:
                samples = uniform(domain,
                                  self.sample_count,
                                  rand_gen=self.rand_gen)
                labels = evaluate(domain, formula, samples)
                samples = samples[labels == 1]

                try:
                    samples.sort(axis=0)
                    std = abs(samples[0:-1, :] - samples[1:, :]).std(axis=0)
                    lbs = samples[0, :] - std
                    ubs = samples[-1, :] + std
                except ValueError:
                    return 0

                lb_ub_bounds = {
                    domain.variables[j]: (lbs[j], ubs[j])
                    for j in range(len(domain.variables))
                }
            else:
                raise ValueError("Illegal bounding box value {}".format(
                    self.bounding_box))
            domain = Domain(domain.variables, domain.var_types, lb_ub_bounds)

        engine = RejectionEngine(domain,
                                 formula,
                                 polynomial.to_smt(),
                                 self.sample_count,
                                 seed=self.seed)
        result = engine.compute_volume()
        if self.bounding_box:
            result = result
        return result
Beispiel #12
0
    def ast_to_smt(self, node):
        """
        :type node: Node
        """
        def convert_children(number=None):
            if number is not None and len(node.children) != number:
                raise Exception(
                    "The number of children ({}) differed from {}".format(
                        len(node.children), number))
            return [self.ast_to_smt(child) for child in node.children]

        if node.name == "ite":
            return smt.Ite(*convert_children(3))
        elif node.name == "~":
            return smt.Not(*convert_children(1))
        elif node.name == "^":
            return smt.Pow(*convert_children(2))
        elif node.name == "&":
            return smt.And(*convert_children())
        elif node.name == "|":
            return smt.Or(*convert_children())
        elif node.name == "*":
            return smt.Times(*convert_children())
        elif node.name == "+":
            return smt.Plus(*convert_children())
        elif node.name == "-":
            return smt.Minus(*convert_children(2))
        elif node.name == "<=":
            return smt.LE(*convert_children(2))
        elif node.name == ">=":
            return smt.GE(*convert_children(2))
        elif node.name == "<":
            return smt.LT(*convert_children(2))
        elif node.name == ">":
            return smt.GT(*convert_children(2))
        elif node.name == "=":
            return smt.Equals(*convert_children(2))
        elif node.name == "const":
            c_type, c_value = [child.name for child in node.children]
            if c_type == "bool":
                return smt.Bool(bool(c_value))
            elif c_type == "real":
                return smt.Real(float(c_value))
            else:
                raise Exception("Unknown constant type {}".format(c_type))
        elif node.name == "var":
            v_type, v_name = [child.name for child in node.children]
            if v_type == "bool":
                v_smt_type = smt.BOOL
            elif v_type == "real":
                v_smt_type = smt.REAL
            else:
                raise Exception("Unknown variable type {}".format(v_type))
            return smt.Symbol(v_name, v_smt_type)
        else:
            raise RuntimeError("Unrecognized node type '{}'".format(node.name))
Beispiel #13
0
def check_balancer_flow(junctions, upstream_densities, downstream_velocities):
    assert len(upstream_densities) == len(downstream_velocities)
    width = len(upstream_densities)
    length = max(x for x, _, _ in junctions)

    formula, belts = balancer_flow_formula(junctions, width, length)

    # Set initial conditions.
    for y, rho in enumerate(upstream_densities):
        formula.append(s.Equals(belts[y][0].rho, s.Real(rho)))
    for y, v in enumerate(downstream_velocities):
        formula.append(s.Equals(belts[y][-1].v, s.Real(v)))

    m = get_model_or_print_ucore(s.And(formula))
    # Print output diagram.
    junctions_by_x = [[] for x in range(length + 1)]
    for (x, y1, y2) in junctions:
        junctions_by_x[x].append((y1, y2))
    ud_width = max(len(str(ud)) for ud in upstream_densities)
    dv_width = max(len(str(dv)) for dv in downstream_velocities)
    rho_width = max(
        len(str(m.get_py_value(belt.rho))) for beltway in belts
        for belt in beltway)
    v_width = max(
        len(str(m.get_py_value(belt.v))) for beltway in belts
        for belt in beltway[1:-1])
    for y, beltway in enumerate(belts):
        print(f'{str(upstream_densities[y]):{ud_width}s}>>>', end=':')
        for x, belt in enumerate(beltway):
            letter_map = {}
            if x < len(beltway) - 1:
                for (y1, y2), letter in zip(junctions_by_x[x + 1],
                                            'abcdefghjkmn'):
                    assert y1 not in letter_map
                    assert y2 not in letter_map
                    letter_map[y1] = letter
                    letter_map[y2] = letter
            belt_status = f'{str(m.get_py_value(belt.rho)):>{rho_width}s}@{str(m.get_py_value(belt.v)):{v_width}s}'
            print(f' >>> {belt_status} >>>', end=f' {letter_map.get(y,"|")}')
        end_flux = m.get_py_value(beltway[-1].flux)
        print(f'> {end_flux}.')

    # The moment of truth...
    theoretical_throughput = min(sum(upstream_densities),
                                 sum(downstream_velocities))
    print(f'Theoretical Q: {theoretical_throughput}')
    actual_throughput = sum(
        m.get_py_value(beltway[-1].flux) for beltway in belts)
    print(f'Actual Q: {actual_throughput}')
    if theoretical_throughput != actual_throughput:
        print(
            f'{float(1-(actual_throughput/theoretical_throughput)):.0%} slowdown :('
        )
    print('∎')
Beispiel #14
0
    def check_example(domain, example_features, dnf_list):
        x_vars = [domain.get_symbol(var) for var in domain.real_vars]
        b_vars = [domain.get_symbol(var) for var in domain.bool_vars]

        formula = smt.Or(
            [smt.And(hyperplane_conjunct) for hyperplane_conjunct in dnf_list])
        substitution = {
            var: example_features[str(var)]
            for var in x_vars + b_vars
        }
        return formula.substitute(substitution).simplify().is_true()
Beispiel #15
0
def get_model_or_print_ucore(formula):
    m = s.get_model(formula)
    if not m:
        print('unsat')
        from pysmt.rewritings import conjunctive_partition
        conj = conjunctive_partition(s.And(formula))
        ucore = s.get_unsat_core(conj)
        print("UNSAT-Core size '%d'" % len(ucore))
        for f in ucore:
            print(f.serialize())
        return
    return m
Beispiel #16
0
 def resolve(self):
     """We're getting read to try out another policy (because the last one failed,
 or because we're on our first iteration). Apply any new constraints we've 
 learned, then find a new solution.
 """
     if self.dirty_variables:
         nogood = sc.And(*self.dirty_variables)
         self.solver.add_assertion(sc.Not(nogood))
     self.dirty_variables = set()
     self.dirty_buffer = set()
     sat = self.solver.solve()
     if not sat:
         raise UnsatException()
Beispiel #17
0
    def solve(self, solver_name=None, get_assignment=False):
        """Solve the SMT problem.

        Return whether the decision problem is satisfiable. If get_assignment
        is set to True, solve() returns an assignment of the variables
        that makes the SMT problem satisfiable (if the problem is
        unsatisfiable, None is returned).

        This assignment is returned as a dictionary with the following entries:

        - differences: an ordered dictionary containing the sequence of
          differences.
        - weight: the weight of the characteristic.
        - op_weights: the weights of each operation with non-deterministic
          propagation.

            >>> from arxpy.bitvector.function import Function
            >>> from arxpy.diffcrypt.difference import XorDiff, DiffVar
            >>> from arxpy.diffcrypt.characteristic import Characteristic
            >>> from arxpy.diffcrypt.smt import SmtProblem
            >>> class MyFunction(Function):
            ...     input_widths = [8, 8, 8]
            ...     output_widths = [8, 8]
            ...     @classmethod
            ...     def eval(cls, x, y, k):
            ...         return (y + k, (y + k) ^ x)
            >>> x, y, k = DiffVar("x", 8), DiffVar("y", 8), DiffVar("k", 8)
            >>> ch = Characteristic(MyFunction, XorDiff, [x, y, k])
            >>> smt_problem = SmtProblem(ch, 0)
            >>> smt_problem.solve()
            True
            >>> smt_problem.solve(get_assignment=True)  # doctest:+NORMALIZE_WHITESPACE
            {'differences': OrderedDict([(x, 0x80), (y, 0x00), (k, 0x80),
            (d0, 0x80), (d1, 0x00)]), 'weight': 0,
            'op_weights': OrderedDict([(w_ky_d0, 0)])}

        """
        sc.reset_env()
        pysmt_formula = sc.And(*[bv2pysmt(a) for a in self.assertions])

        if not get_assignment:
            return sc.is_sat(pysmt_formula, solver_name, logic=logics.QF_BV)
        else:
            model = sc.get_model(pysmt_formula,
                                 solver_name,
                                 logic=logics.QF_BV)

            if model is None:
                return None
            else:
                return self._get_assignment(model)
Beispiel #18
0
def dual_paths(n):
    booleans = []  # ["A{}".format(i) for i in range(n)]
    domain = Domain.make(booleans, ["x{}".format(i) for i in range(n)], real_bounds=(0, 1))
    bool_vars = domain.get_bool_symbols()
    real_vars = domain.get_real_symbols()
    terms = []
    for i in range(n):
        v1, v2 = random.sample(real_vars, 2)
        terms.append(v1 * random.random() <= v2 * random.random())

    paths = []
    for i in range(n):
        paths.append(smt.And(*random.sample(bool_vars + terms, n)))

    return Density(domain, domain.get_bounds() & smt.Or(*paths), smt.Real(1))
Beispiel #19
0
def generate_click_graph(n):
    def t(c):
        return smt.Ite(c, one, zero)

    sim_n, cl_n, b_n, sim_x_n, b_x_n = "sim", "cl", "b", "sim_x", "b_x"
    domain = Domain.make(
        # Boolean
        ["{}_{}".format(sim_n, i) for i in range(n)] +
        ["{}_{}_{}".format(cl_n, i, j) for i in range(n) for j in (0, 1)] +
        ["{}_{}_{}".format(b_n, i, j) for i in range(n) for j in (0, 1)],
        # Real
        ["{}".format(sim_x_n)] +
        ["{}_{}_{}".format(b_x_n, i, j) for i in range(n) for j in (0, 1)],
        real_bounds=(0, 1))
    sim = [domain.get_symbol("{}_{}".format(sim_n, i)) for i in range(n)]
    cl = [[domain.get_symbol("{}_{}_{}".format(cl_n, i, j)) for j in (0, 1)]
          for i in range(n)]
    b = [[domain.get_symbol("{}_{}_{}".format(b_n, i, j)) for j in (0, 1)]
         for i in range(n)]
    sim_x = domain.get_symbol("{}".format(sim_x_n))
    b_x = [[domain.get_symbol("{}_{}_{}".format(b_x_n, i, j)) for j in (0, 1)]
           for i in range(n)]

    support = smt.And([
        smt.Iff(cl[i][0], b[i][0])
        & smt.Iff(cl[i][1], (sim[i] & b[i][0]) | (~sim[i] & b[i][1]))
        for i in range(n)
    ])

    one = smt.Real(1)
    zero = smt.Real(0)
    w_sim_x = t(sim_x >= 0) * t(sim_x <= 1)
    w_sim = [smt.Ite(s_i, sim_x, 1 - sim_x) for s_i in sim]
    w_b_x = [
        t(b_x[i][j] >= 0) * t(b_x[i][j] <= 1) for i in range(n) for j in (0, 1)
    ]
    w_b = [
        smt.Ite(b[i][j], b_x[i][j], 1 - b_x[i][j]) for i in range(n)
        for j in (0, 1)
    ]

    weight = smt.Times(*([w_sim_x] + w_sim + w_b_x + w_b))
    return Density(domain, support, weight)
    def compute_volume(self, add_bounds=True):
        # print(self.weight)
        # print(self.support)
        # print(self.domain)

        if add_bounds:
            return self.with_constraint(
                self.domain.get_bounds()).compute_volume(False)

        # The algebra used for describing the given SMT theory (which hopefully complies)
        # Not to be confused with self.algebra, which is used to actually
        # integrate and solve the SMT theory
        descr_algebra = self.get_weight_algebra()

        # Calculate base support
        base_support = self.support
        if self.find_conflicts:
            base_support = smt.And(*self.collect_conflicts()) & base_support

        labeling_dict, weight_function = self.get_labels_and_weight()

        # piecewise_function contains a dict of weight -> support pairs
        piecewise_function = split_up_function(weight_function, descr_algebra,
                                               get_env())

        if isinstance(self.algebra, PyXaddAlgebra):
            _, _, all_support_literals = extract_and_replace_literals(
                base_support)
            vtree = self.get_vtree(base_support, all_support_literals)
            all_literals = [n.var for n in vtree.all_leaves()]

            for lit in all_literals:
                test = all_support_literals[lit]
                if not isinstance(test, str):
                    self.algebra.pool.bool_test(Decision(test))

        volume = self.compute_volume_from_pieces(base_support,
                                                 piecewise_function,
                                                 labeling_dict)

        return self.algebra.to_float(volume)
Beispiel #21
0
def load(path, file_name, domain_real):
    wmi_problem = {}

    path = os.path.join(*path)
    with open(
            os.path.join(
                os.path.dirname(os.path.dirname(os.path.realpath(__file__))),
                path, file_name)) as f:
        flat = json.load(f)

    domain = {}
    variables = flat.pop("domain")
    var_types = {v["name"]: v["type"] for v in variables}
    variables = list(var_types.keys())

    domain["variables"] = variables
    domain["var_types"] = var_types
    domain["var_domains"] = {
        str(v): domain_real
        for v in domain["var_types"] if domain["var_types"][v] == "real"
    }
    flat["domain"] = domain

    domain = import_domain(flat["domain"])

    query = nested_to_smt(flat["queries"][0]["formula"])
    queries = [query]

    evidence = flat["queries"][0]["evidence"]
    evidence = [
        "(=(var real {}) (const real {}))".format(k, v)
        for k, v in evidence.items()
    ][0]  #only works for one evidence point
    evidence = nested_to_smt(evidence)
    support = nested_to_smt(flat["support"])
    support = smt.And(support, evidence)

    weight = nested_to_smt(flat["weight"])

    return domain, queries, support, weight
Beispiel #22
0
def search_in_hierarchy_lit(data, domain, nodes, halflines):
    clauses = []
    for node in nodes:
        if node.hl_min == node.hl_max:
            clauses += [node.clause]
            halflines -= node.hl_max
            continue
        clause = None
        for h in range(node.hl_min, halflines + 1):
            with smt.Solver() as solver:
                clause = search_in_node(data, domain, node, h)
                if clause is not None:
                    node.hl_max = h
                    node.clause = clause
                    clauses += [clause]
                    halflines -= h
                    saturate(data, domain, node)
                    break;
            node.hl_min += 1
        if clause is None:
            return None
    return smt.And(clauses)
Beispiel #23
0
def search_in_hierarchy(data, domain, nodes, halflines):
    clauses = []
    for node in nodes:
        if node.hl_min == node.hl_max:
            clauses += [node.clause]
            halflines -= node.hl_max
            continue
        idx = [i for i in range(len(data)) if data[i][1]] + list(node.to_gen())
        clause = None
        for h in range(node.hl_min, halflines + 1):
            with smt.Solver() as solver:
                clause = find_iter(data, domain, idx, find_clause, solver, h)
                if clause is not None:
                    node.hl_max = h
                    node.clause = clause
                    clauses += [clause]
                    halflines -= h
                    saturate(data, domain, node)
                    break;
            node.hl_min += 1
        if clause is None:
            return None
    return smt.And(clauses)
Beispiel #24
0
def test_basic(solver_str, T, logic, implicit):
    x = sc.FreshSymbol(T)
    problem = sc.And(x < 2, x > 0)
    x_val = None
    if implicit:
        args = ()
    else:
        args = (logic, )

    if logic not in fe.SWITCH_SOLVERS[solver_str].LOGICS:
        with pytest.raises(RuntimeError):
            with fe.Solver(solver_str, *args) as solver:
                solver.add_assertion(problem)
    else:
        with fe.Solver(solver_str, *args) as solver:
            solver.add_assertion(problem)
            assert solver.solve()
            if T is not st.REAL:
                x_val = solver.get_py_value(x)
                assert x_val == 1
            else:
                x_val = solver.get_value(problem)
        assert x_val is not None
Beispiel #25
0
def find_cnf(data, domain, active_indices, solver, n_c, n_h):
    # Constants
    n_b_original = len(domain.bool_vars)
    n_b = n_b_original * 2
    n_r = len(domain.real_vars)
    n_d = len(data)

    real_features = [[row[v] for v in domain.real_vars] for row, _ in data]
    bool_features = [[row[v] for v in domain.bool_vars] for row, _ in data]
    labels = [row[1] for row in data]

    # Variables
    a_hr = [[
        smt.Symbol("a_hr[{}][{}]".format(h, r), REAL) for r in range(n_r)
    ] for h in range(n_h)]
    b_h = [smt.Symbol("b_h[{}]".format(h), REAL) for h in range(n_h)]
    s_ch = [[smt.Symbol("s_ch[{}][{}]".format(c, h)) for h in range(n_h)]
            for c in range(n_c)]
    s_cb = [[smt.Symbol("s_cb[{}][{}]".format(c, b)) for b in range(n_b)]
            for c in range(n_c)]

    # Aux variables
    s_ih = [[smt.Symbol("s_ih[{}][{}]".format(i, h)) for h in range(n_h)]
            for i in range(n_d)]
    s_ic = [[smt.Symbol("s_ic[{}][{}]".format(i, c)) for c in range(n_c)]
            for i in range(n_d)]

    # Constraints
    for i in active_indices:
        x_r, x_b, label = real_features[i], bool_features[i], labels[i]

        for h in range(n_h):
            sum_coefficients = smt.Plus(
                [a_hr[h][r] * smt.Real(x_r[r]) for r in range(n_r)])
            if label:
                solver.add_assertion(
                    smt.Iff(s_ih[i][h], sum_coefficients + DELTA <= b_h[h]))
            else:
                solver.add_assertion(
                    smt.Iff(s_ih[i][h], sum_coefficients - DELTA <= b_h[h]))

        for c in range(n_c):
            solver.add_assertion(
                smt.Iff(
                    s_ic[i][c],
                    smt.Or([smt.FALSE()] + [(s_ch[c][h] & s_ih[i][h])
                                            for h in range(n_h)] +
                           [s_cb[c][b]
                            for b in range(n_b_original) if x_b[b]] + [
                                s_cb[c][b] for b in range(n_b_original, n_b)
                                if not x_b[b - n_b_original]
                            ])))

        if label:
            solver.add_assertion(smt.And([s_ic[i][c] for c in range(n_c)]))
        else:
            solver.add_assertion(smt.Or([~s_ic[i][c] for c in range(n_c)]))

    if not solver.solve():
        return None
    model = solver.get_model()

    x_vars = [domain.get_symbol(domain.real_vars[r]) for r in range(n_r)]
    half_spaces = [
        smt.Plus([model.get_value(a_hr[h][r]) * x_vars[r]
                  for r in range(n_r)]) <= model.get_value(b_h[h])
        for h in range(n_h)
    ]

    b_vars = [
        domain.get_symbol(domain.bool_vars[b]) for b in range(n_b_original)
    ]
    bool_literals = [b_vars[b] for b in range(n_b_original)]
    bool_literals += [~b_vars[b] for b in range(n_b - n_b_original)]

    conjunctions = [
        [half_spaces[h]
         for h in range(n_h) if model.get_py_value(s_ch[c][h])] + [
             bool_literals[b]
             for b in range(n_b) if model.get_py_value(s_cb[c][b])
         ] for c in range(n_c)
    ]

    return smt.And([smt.Or(conjunction) for conjunction in conjunctions])
Beispiel #26
0
 def walk_and(self, args):
     return smt.And(*self.walk_smt_multiple(args))
 def integrate(self, domain: Domain, convex_bounds: List[LinearInequality],
               polynomial: Polynomial):
     formula = smt.And(*[i.to_smt() for i in convex_bounds])
     return self.engine.copy(domain, formula,
                             polynomial.to_smt()).compute_volume()
Beispiel #28
0
def balancer_flow_formula(junctions, width, length):
    formula = []
    belts = [[
        Belt(s.Symbol(f'b{i}[{x}].rho', t.REAL),
             s.Symbol(f'b{i}[{x}].v', t.REAL)) for x in range(length + 1)
    ] for i in range(width)]
    for beltway in belts:
        for belt in beltway:
            formula.extend(domain(belt))
    if not s.is_sat(s.And(formula)):
        raise Exception('Domain is not SAT :/')

    # Balancing rules.
    junctions_by_x = [[] for x in range(length + 1)]
    for (x, y1, y2) in junctions:
        junctions_by_x[x].append((y1, y2))
        inn = x - 1
        out = x

        input_rho = s.Plus(belts[y1][inn].rho, belts[y2][inn].rho)
        # We want to put half of the input on each output.
        half_input = s.Div(input_rho, s.Real(2))

        # If output velocity is less than the half_input that we would like to
        # assign to it, we've filled it. Velocity is a hard limit, because it's out
        # of influence of this splitter. We'll set the output density to 1 in that
        # case. Aside: The flux is the min of that and the velocity, so if
        # out-velocity is the limiting factor, it won't change the flux calculation
        # to just assign rho_out = v_out.
        #
        # Now, the excess that we couldn't assign has to go somewhere: (1) to the
        # other output belt; if that's full, (2) feed back up the chain by reducing
        # input velocities.
        excess_from_1 = s.Max(s.Real(0), s.Minus(half_input, belts[y1][out].v))
        excess_from_2 = s.Max(s.Real(0), s.Minus(half_input, belts[y2][out].v))

        # This formula is most accurate for assignment > velocity (density will
        # equal 1), but it doesn't change the flux calculation just toset rho to
        # the velocity when velocity limits flow. (So you should be able to replace
        # the Ite by v_out and be OK.)
        formula.append(
            s.Equals(
                belts[y1][out].rho,
                s.Ite(half_input + excess_from_2 > belts[y1][out].v, s.Real(1),
                      half_input + excess_from_2)))
        formula.append(
            s.Equals(
                belts[y2][out].rho,
                s.Ite(half_input + excess_from_1 > belts[y2][out].v, s.Real(1),
                      half_input + excess_from_1)))

        output_v = s.Plus(belts[y1][out].v, belts[y2][out].v)
        half_output = s.Div(output_v, s.Real(2))
        unused_density_from_1 = s.Max(s.Real(0),
                                      s.Minus(half_output, belts[y1][inn].rho))
        unused_density_from_2 = s.Max(s.Real(0),
                                      s.Minus(half_output, belts[y2][inn].rho))

        formula.append(
            s.Equals(
                belts[y1][inn].v,
                s.Ite(half_output + unused_density_from_2 > belts[y1][inn].rho,
                      s.Real(1), half_output + unused_density_from_2)))
        formula.append(
            s.Equals(
                belts[y2][inn].v,
                s.Ite(half_output + unused_density_from_1 > belts[y2][inn].rho,
                      s.Real(1), half_output + unused_density_from_1)))
        # Conservation of flux at each junction.
        input_flux = s.Plus(belts[y1][inn].flux, belts[y2][inn].flux)
        output_flux = s.Plus(belts[y1][out].flux, belts[y2][out].flux)
        formula.append(s.Equals(input_flux, output_flux))

    # Any belts not involved in a junction are pass-throughs. Their successive
    # values must remain equal.
    thru_belts = [
        list(
            set(range(width)) - {y1
                                 for y1, y2 in junctions_by_x[x]} -
            {y2
             for y1, y2 in junctions_by_x[x]}) for x in range(length + 1)
    ]
    for x, thru in enumerate(thru_belts[1:]):
        for y in thru:
            formula.append(s.Equals(belts[y][x].rho, belts[y][x + 1].rho))
            formula.append(s.Equals(belts[y][x].v, belts[y][x + 1].v))

    return formula, belts
Beispiel #29
0
def prove_properties(junctions):
    width = max(max(y1 for _, y1, _ in junctions),
                max(y2 for _, _, y2 in junctions)) + 1
    length = max(x for x, _, _ in junctions)
    formula, belts = balancer_flow_formula(junctions, width, length)

    supply = s.Plus(beltway[0].rho for beltway in belts)
    demand = s.Plus(beltway[-1].v for beltway in belts)
    max_theoretical_throughput = s.Min(supply, demand)
    actual_throughput = s.Plus(beltway[-1].flux for beltway in belts)

    fully_balanced_output = []
    max_flux = s.Max(b[-1].flux for b in belts)
    for i, b1 in enumerate(belts):
        fully_balanced_output.append(
            s.Or(s.Equals(b1[-1].flux, max_flux),
                 s.Equals(b1[-1].flux, b1[-1].v)))
    fully_balanced_output = s.And(fully_balanced_output)

    fully_balanced_input = []
    max_flux = s.Max(b[0].flux for b in belts)
    for i, b1 in enumerate(belts):
        fully_balanced_input.append(
            s.Or(s.Equals(b1[0].flux, max_flux),
                 s.Equals(b1[0].flux, b1[0].rho)))
    fully_balanced_input = s.And(fully_balanced_input)

    with s.Solver() as solver:
        solver.add_assertion(s.And(formula))
        solver.push()
        solver.add_assertion(
            s.Not(s.Equals(max_theoretical_throughput, actual_throughput)))

        if not solver.solve():
            print("It's throughput-unlimited!")
        else:
            print("It's throughput-limited; here's an example:")
            m = solver.get_model()
            inputs = tuple(m.get_py_value(beltway[0].rho) for beltway in belts)
            outputs = tuple(m.get_py_value(beltway[-1].v) for beltway in belts)
            print(f'Input lane densities: ({", ".join(map(str, inputs))})')
            print(f'Output lane velocities: ({", ".join(map(str, outputs))})')
            check_balancer_flow(junctions, inputs, outputs)

        solver.pop()
        solver.push()
        solver.add_assertion(s.Not(fully_balanced_input))

        if not solver.solve():
            print("It's input-balanced!")
        else:
            print("It's input-imbalanced; here's an example:")
            m = solver.get_model()
            inputs = tuple(m.get_py_value(beltway[0].rho) for beltway in belts)
            outputs = tuple(m.get_py_value(beltway[-1].v) for beltway in belts)
            print(f'Input lane densities: ({", ".join(map(str, inputs))})')
            print(f'Output lane velocities: ({", ".join(map(str, outputs))})')
            check_balancer_flow(junctions, inputs, outputs)

        solver.pop()
        solver.push()
        solver.add_assertion(s.Not(fully_balanced_output))
        if solver.solve:
            print("It's output-balanced!")
        else:
            print("It's output-imbalanced; here's an example:")
            m = solver.get_model()
            inputs = tuple(m.get_py_value(beltway[0].rho) for beltway in belts)
            outputs = tuple(m.get_py_value(beltway[-1].v) for beltway in belts)
            print(f'Input lane densities: ({", ".join(map(str, inputs))})')
            print(f'Output lane velocities: ({", ".join(map(str, outputs))})')
            check_balancer_flow(junctions, inputs, outputs)
Beispiel #30
0
def generate_synthetic_data_sampling(data_sets_per_setting, bool_count, real_count, cnf_or_dnf, k, l_per_term, h,
                                     sample_count, max_ratio, seed, prefix="synthetics"):
    def test_ratio(_indices):
        return (1 - max_ratio) * sample_count <= len(_indices) <= max_ratio * sample_count

    data_set_count = 0
    domain = generate_domain(bool_count, real_count)
    while data_set_count < data_sets_per_setting:
        name = get_synthetic_problem_name(prefix, bool_count, real_count, cnf_or_dnf, k, l_per_term, h, sample_count,
                                          seed, max_ratio * 100, data_set_count)
        samples = [get_sample(domain) for _ in range(sample_count)]

        half_spaces = []
        print("Generating half spaces: ", end="")
        if real_count > 0:
            while len(half_spaces) < h:
                half_space = generate_half_space_sample(domain, real_count)
                indices = {i for i in range(sample_count) if smt_test(half_space, samples[i])}
                if True or test_ratio(indices):
                    half_spaces.append((half_space, indices))
                    print("y", end="")
                else:
                    print("x", end="")
        print()

        bool_literals = [(domain.get_symbol(v), {i for i in range(sample_count) if samples[i][v]})
                         for v in domain.bool_vars]

        literal_pool = half_spaces + bool_literals
        literal_pool += [(smt.Not(l), {i for i in range(sample_count)} - indices) for l, indices in literal_pool]
        random.shuffle(literal_pool)

        term_pool = []
        print("Generating terms: ", end="")
        for literals in itertools.combinations(literal_pool, l_per_term):
            term = smt.Or(*[t[0] for t in literals])
            covered = set()
            all_matter = True
            for _, indices in literals:
                prev_size = len(covered)
                covered |= indices
                if (len(covered) - prev_size) / sample_count < 0.05:
                    all_matter = False

            if all_matter:  # & test_ratio(covered):
                term_pool.append((term, covered))
                print("y", end="")
            else:
                print("x", end="")
        print()

        print("Generating formulas: ", end="")
        random.shuffle(term_pool)
        counter = 0
        max_tries = 10000
        for terms in itertools.combinations(term_pool, k):
            if counter >= max_tries:
                print("Restart")
                break
            formula = smt.And(*[t[0] for t in terms])
            covered = {i for i in range(sample_count)}
            all_matter = True
            for _, indices in terms:
                prev_size = len(covered)
                covered &= indices
                if prev_size == len(covered):
                    all_matter = False
            if all_matter & test_ratio(covered):
                print("y({:.2f})".format(len(covered) / sample_count), end="")
                synthetic_problem = SyntheticProblem(problem.Problem(domain, formula, name), "cnf", k, l_per_term, h)
                data_set = synthetic_problem.get_data(sample_count, 1)
                new_sample_positives = [sample for sample in data_set.samples if sample[1]]
                if test_ratio(new_sample_positives):
                    print("c({:.2f})".format(len(new_sample_positives) / sample_count))
                    data_set_count += 1
                    yield data_set
                    break
                else:
                    print("r({:.2f})".format(len(new_sample_positives) / sample_count), end="")
            else:
                print("x", end="")
            print(" ", end="")
            counter += 1
        print()