def expr_count_of(self, char): """Counts char in string, returns expression. Returns a z3 expression representing the number of times char appears in the string. """ return (z3.Sum([z3.If(bv == ord(char), 1, 0) for bv in self.bitvecs]))
def applications_to_solver(applications): # try building applications one by one solver = z3.Solver() solver_list = [] for application in applications: l, m, r = application.split(' ') l_c = z3.Sum( [z3.Int(elem) for elem in l.split('+')] ) try: r_c = float(r) r_c_lb = r_c - 1 r_c_ub = r_c + 1 except: r_c = z3.Int(r) # all of type elem_1 <= elem_2 if m == '<=': solver.add(l_c <= r_c) solver_list.append(l_c <= r_c) # all of type elem == int elif m == '==': # NOTE: works only if we allow a margin of error -- is this coming from the conversion from mean to sum? solver.add(l_c >= r_c_lb) solver.add(l_c <= r_c_ub) solver_list.append(l_c >= r_c_lb) solver_list.append(l_c <= r_c_ub) # solver.add(l_c == r_c) # solver_list.append(l_c == r_c) # all of type elem >= 0 elif m == '>=': solver.add(l_c >= r_c) solver_list.append(l_c >= r_c) return(solver, solver_list)
def main(nanobots): solver = z3.Optimize() bx = z3.Int("x") by = z3.Int("y") bz = z3.Int("z") d = z3.Int("d") bots = [] for i, bot in enumerate(nanobots): print("adding bot {} to z3".format(i)) b = z3.Int("b{:04}".format(i)) solver.add(b == z3.If(manhattan_distance((bx, by, bz), (bot.x, bot.y, bot.z)) <= bot.radius, 1, 0)) bots.append(b) print("adding constraints") solver.add(d == manhattan_distance((bx, by, bz), (0, 0, 0))) solver.maximize(z3.Sum(*bots)) solver.minimize(d) print("solving...") print(solver.check()) model = solver.model() print("answer:") print(model[d])
def getNearestFeasible(self, coord): # get the variables corresponding to the axis names for i in self.axis_names: locals()[i] = Globals.z3variables[i] # Convert into parameters rpp = self.search.coordToPerfParams(coord) for i, name in enumerate(self.axis_names): if not self.z3IsNumeric(i): rpp[name] = Globals.z3types[name].index(rpp[name]) # create a new scope self.optim.push() # Get a possible point that minimizes the 1-norm distance to this random point # forget the booleans l = [] for name in self.axis_names: if not z3.is_bool(locals()[name]): l.append(self.z3abs(locals()[name] - rpp[name])) definition = z3.Sum(l) self.optim.minimize(definition) # For some reason, it does not work with a list comprehension. # self.optim.minimize( z3.Sum( [ self.z3abs( locals()[name] - rpp[name] )for name in self.axis_names if not z3.is_bool( locals()[name] ) ] ) ) if z3.unsat == self.optim.check(): return None model = self.optim.model() # restore the state (exit the scope) self.optim.pop() return self.z3ToPoint(model)
def Sum(*args: BitVec) -> BitVec: """Create sum expression. :return: """ raw = z3.Sum([a.raw for a in args]) annotations = [] # type: Annotations bitvecfuncs = [] for bv in args: annotations += bv.annotations if isinstance(bv, BitVecFunc): bitvecfuncs.append(bv) if len(bitvecfuncs) >= 2: return BitVecFunc(raw=raw, func_name=None, input_=None, annotations=annotations) elif len(bitvecfuncs) == 1: return BitVecFunc( raw=raw, func_name=bitvecfuncs[0].func_name, input_=bitvecfuncs[0].input_, annotations=annotations, ) return BitVec(raw, annotations)
def _link_affine(self, phi, include_bterm=True): assert isinstance(phi, amnet.Affine) or \ isinstance(phi, amnet.Linear) m, n = phi.w.shape assert m >= 1 and n >= 1 # extract children yvar = self.var_of(phi) xvar = self.var_of(phi.x) assert (len(yvar) == m) and (len(xvar) == n) # go row-by-row of w for i in range(m): rowi = phi.w[i, :] assert len(rowi) == n rowsum = z3.Sum( [wij * xj for wij, xj in izip(rowi, xvar) if wij != 0]) if include_bterm: assert isinstance(phi, amnet.Affine), \ 'Warning: tried to encode bterm in non-Affine' self.solver.add(yvar[i] == (rowsum + phi.b[i])) else: self.solver.add(yvar[i] == rowsum)
def solve(grid): """ . . . .1.1. . .3. """ s = z3.Solver() # Construct atoms to represent the dots Dot = z3.Datatype("Dot") for d in grid.dots(): Dot.declare("dot_{}".format(d)) Dot = Dot.create() dot_atom = {d: getattr(Dot, "dot_{}".format(d)) for d in grid.dots()} # Booleans for each of the points dot = {d: z3.Bool("dot-{}".format(d)) for d in grid.dots()} # Booleans for each of the connectors line = {l: z3.Bool("line-{}".format(l)) for l in grid.lines()} # For each point: if it is on, it must have precisely two adjoining lines activated # If it's off, then there are zero adjoining lines activated bool_to_int = z3.Function("bool_to_int", z3.BoolSort(), z3.IntSort()) s.add(bool_to_int(True) == 1) s.add(bool_to_int(True) != 0) s.add(bool_to_int(False) == 0) s.add(bool_to_int(False) != 1) for d in grid.dots(): # Get all lines coming out of this dot ls = [line[l] for l in d.lines()] sm = z3.Sum(*(bool_to_int(l) for l in ls)) s.add(z3.Implies(dot[d], sm == 2)) s.add(z3.Implies(z3.Not(dot[d]), sm == 0)) # For each line: if it is activated, then the points at both ends are activated for l in line: d1, d2 = l.ends() s.add(z3.Implies(line[l], z3.And(dot[d1], dot[d2]))) # "Is connected to" relationship connected = z3.Function("connected", Dot, Dot, z3.BoolSort()) # For each line: # The Dot at each end is connected to the other iff the line is activated for d1 in grid.dots(): for d2 in grid.dots(): a = dot_atom[d1] b = dot_atom[d2] if (l := grid.line(d1, d2)) is None: # These dots are never connected s.add(connected(a, b) != True) else: s.add(z3.Implies(line[l], connected(a, b))) s.add(z3.Implies(z3.Not(line[l]), z3.Not(connected(a, b))))
def incidence_sums(petrinet, variables, subnet_transitions="all", reverse=False): if subnet_transitions == "all": subnet_transitions = set(range(petrinet.num_transitions)) sums = [] for p in range(petrinet.num_places()): nonzero = petrinet.transitions_set({p}, reverse) incidence_row = [(petrinet.get_post(p, t) - petrinet.get_pre(p, t), variables[t]) for t in nonzero if t in subnet_transitions] sum_elements = [ expression(coeff, var) for coeff, var in incidence_row if coeff != 0 ] curr_sum = z3.Sum( sum_elements) if len(sum_elements) > 0 else z3.IntVal(0) sums.append(curr_sum) return sums
def add_cage_constraints(self, cage): cage_sum = int(cage[:2]) cage_vars = [] for r, c in zip(cage[2::2], cage[3::2]): cage_vars.append(self._grid[int(r) - 1][int(c) - 1]) self._solver.add(z3.Distinct(cage_vars)) self._solver.add(z3.Sum(cage_vars) == cage_sum)
def add_killer_cage(s, cage_coords, cage_sum): '''Add a single killer sudoku cage. Takes a list of (row, col) coordinates and the sum ''' cagecells = [X[i][j] for i, j in cage_coords] # Digits dont repeat within cages s.add(z3.Distinct(cagecells)) s.add(z3.Sum(cagecells) == cage_sum)
def do_POPCOUNT(op, stack, state): b, = pop_values(stack, state) n = b.size() bits = [z3.Extract(i, i, b) for i in range(n)] bvs = [z3.Concat(z3.BitVecVal(0, n - 1), b) for b in bits] nb = z3.Sum(*bvs) stack.append(z3.simplify(nb))
def Sum(*args: BitVec) -> BitVec: """Create sum expression. :return: """ nraw = z3.Sum([a.raw for a in args]) annotations = [] # type: Annotations for bv in args: annotations += bv.annotations return BitVec(nraw, annotations)
def _bin_packing_constraints(manifest, storage, color, volume): constraint = [] # heuristic = [] limits = [z3.And(0 <= v, v <= s['volume_left']) for v, s in zip(volume, storage)] for i, stor in enumerate(storage): summation = z3.Sum([z3.If(col == i, vol, 0) for col, vol in zip(color, volume)]) constraint.append(summation <= stor['volume_left']) # heuristic.append( z3.Sum([z3.If(z3.Or(summation==0, summation==stor['volume_left']), 1, 0)]) ) return limits + constraint # , z3.Sum(heuristic)
def setup_line(self, x0, y0, dx, dy, sum): if sum == 0: return vs = [] x, y = x0 + dx, y0 + dy while (x, y) in self.cells: vs.append(self.cells[x, y]) x += dx y += dy self.solver.add(z3.Distinct(vs)) self.solver.add(z3.Sum(vs) == sum)
def make_hash_equation(pj: int, var_b: Tuple[int], b1: int): domain_bit_count = int(ceil(log2(pj))) bc = int(ceil(log2(pj + 1))) slices = get_slices(domain_bit_count) return z3.URem( z3.Sum([ z3.ZeroExt(bc - s.size(), s) * z3.BitVecVal(var_b[i], bc) for i, s in enumerate(slices) ]) + z3.BitVecVal(b1, bc), z3.BitVecVal(pj, bc)) == z3.BitVecVal(0, bc)
def agreesAtLeastNTimes(inputOutputList, expressionValues, gene, aVars, rVars, n): both = [ totalAgreement(inputOutputList[p], gene, aVars, rVars, expressionValues, p) for p in range(len(inputOutputList)) ] encodings = [both[i][0] for i in range(len(both))] scoreValues = [both[i][1] for i in range(len(both))] return z3.And(z3.And(encodings), z3.Sum(scoreValues) >= n)
def largest_clique(self, timeout=120): if z3 is None: raise ImportError() solver = z3.Optimize() solver.set("timeout", timeout) vars = {} # rev = {} start = time.clock() m = z3.Int(name="cliquesize") for v in self.nodes_iter(): vars[v] = z3.Int(name="node{0}".format(v)) # rev[vars[v]] = v solver.add(vars[v] <= 1) solver.add(vars[v] >= 0) solver.add(z3.Sum([vars[v] for v in self.nodes_iter()]) >= m) # solver.add(z3.Or([vars[v] == 1 for v in self.nodes_iter()])) adj = self.adj for u in self.nodes_iter(): for v in self.nodes_iter(): if u < v and u not in adj[v]: solver.add(z3.Or(vars[u] == 0, vars[v] == 0)) if timeout != 0 and time.clock() - start >= timeout: return None r = None try: r = solver.maximize(m) solver.check() except z3.Z3Exception as e: logging.error(e.message) if r is None: return None res = solver.lower(r) # assert(str(res) != 'epsilon' and str(res) != 'unsat' and isinstance(res, z3.IntNumRef) and res.as_long() >= 1) if str(res) == 'epsilon' or str(res) == 'unsat': logging.error(res) elif not isinstance(res, z3.IntNumRef): logging.error("not an int") elif res.as_long() < 1: logging.error("clique result < 1") else: cl = [ k for (k, v) in vars.items() if solver.model()[v].as_long() == 1 ] if len(cl) != res.as_long(): logging.error("{0} vs. {1}".format(len(cl), res.as_long())) # assert(len(cl) == res.as_long()) return None # print cl return cl return None
def solve_part_2(nanobots): s = z3.Optimize() x = z3.Int('x') y = z3.Int('y') z = z3.Int('z') d = z3.Int('d') dists = [z3.Int(i) for i in range(len(nanobots))] for i, bot in enumerate(nanobots): dists[i] = z3.If(dist2(bot['pos'], (x, y, z)) <= bot['r'], 1, 0) s.maximize(z3.Sum(*dists)) s.add(d == dist2((x, y, z), (0, 0, 0))) s.minimize(d) s.check() return s.model()[d]
def _solve( solver: z3.Optimize, channels: List[Channel], devices: List[Device] ) -> Tuple[Problem, z3.Model]: problem = _problem(solver, freqs=[c.frequency for c in channels], devices=devices) if solver.check() != z3.sat: # TODO: consider getting an unsat core raise ValueError(f"No valid assignment possible, add more devices") # find the minimal number of devices that cover all frequencies # it is faster to do this iteratively than to offload these to # smt constraints. do this in reverse so we end up assigning # the lowest numbered devices for r in problem.ranges[::-1]: # to control the device placements adjust the order they're eliminated from # the solution. for example, this will prefer devices that have a smaller # minimum sample rate over devices with a larger one: # for r, _ in zip(problem.ranges, problem.devices), key=lambda x: -x[1].min_sample_rate solver.push() solver.add(r == 0) if solver.check() != z3.sat: solver.pop() break devices_required = z3.Sum([z3.If(r > 0, 1, 0) for r in problem.ranges]) # minimize the sum of frequency ranges solver.minimize(z3.Sum(*problem.ranges)) # and the frequency, just to produce deterministic results solver.minimize(z3.Sum(*problem.lower_freq)) assert solver.check() == z3.sat model = solver.model() print(f"Devices required: {model.eval(devices_required)}", file=sys.stderr) return problem, model
def generate_constraints(capacity, sizes, endpoints, caches): print('Generate constraints...') print('SERVE_SUM') SERVE_SUM = SERVE == z3.Sum([ find_max(e.L.items(), v, e.L_D) * ratio for e, _ in ((e, print('.', end='', flush=True)) for e in endpoints) for v, ratio in e.requests.items() ]) print() print('CAPACITY') CAPACITY = [ z3.Sum([z3.If(has_video(v, c), sizes[v], 0) for v in videos]) == capacity for c, videos in caches.items() ] VIDEO = z3.Int('VIDEO') print('IMP') IMP = [ z3.ForAll([VIDEO], z3.Implies(has_video(VIDEO, c), z3.Or([VIDEO == v for v in videos]))) for c, videos in caches.items() ] return [CAPACITY, SERVE_SUM, IMP]
def find_sum_combo_with_z3(numbers, n, target=2020): solver = z3.Solver() symvars = [z3.Int(f'sv_{i}') for i in range(n)] solver.add(z3.Sum(symvars) == target) solver.add(z3.Distinct(symvars)) for sv in symvars: solver.add(z3.Or([sv == number for number in numbers])) if str(solver.check()) == 'sat': print(f'Model = {solver.model()}') return mult(solver.model()[sv].as_long() for sv in symvars) else: print('No solution') return -1
def prepare_solver(instance: Instance) -> Tuple[z3.Solver, Dict[int, str]]: solver = z3.Solver() variables = [] ingredient_indices: Dict[str, int] = {} ingredient_names: Dict[int, str] = {} num_of_meals = len(MEAL_NAMES) # create a list of variables for each ingredient for ingredient_id in range(len(instance.ingredients)): meal_vars = [] name = instance.ingredients[ingredient_id].name ingredient_indices[name] = ingredient_id ingredient_names[ingredient_id] = name for meal_id in range(num_of_meals): var_name = make_variable_name(meal_id, ingredient_id) var = z3.Int(var_name) solver.add(var >= 0) meal_vars.append(z3.ToReal(var)) variables.append(meal_vars) # add constraints for food conflicts for food1, food2 in instance.conflicts: food1_id = ingredient_indices[food1] food2_id = ingredient_indices[food2] food1_vars = variables[food1_id] food2_vars = variables[food2_id] for var1, var2 in zip(food1_vars, food2_vars): solver.add(z3.Or(var1 == 0, var2 == 0)) # add constraints for total amount of substances macro_sums = {} for macro in instance.macros: macro_sums[macro] = 0.0 for ingredient_vars, ingredient in zip(variables, instance.ingredients): ingredient_sum = z3.Sum(ingredient_vars) for macro in instance.macros: macro_sums[macro] += ingredient_sum * ingredient.macros[macro] for target in instance.targets: macro_sum = macro_sums[target.macro] solver.add(macro_sum >= target.min) solver.add(macro_sum <= target.max) # ensure that meals are not empty num_of_ingredients = len(variables) for meal_id in range(num_of_meals): meal_conditions = [] for ingredient_id in range(num_of_ingredients): meal_conditions.append(variables[ingredient_id][meal_id] > 0) solver.add(z3.Or(meal_conditions)) return solver, ingredient_names
def __init__(self, variable_names: Sequence[str], qualities: Sequence[float]): assert len(variable_names) == len(qualities) # Improve optimizer performance by sorting qualities decreasingly; adapt order of variable names accordingly: qualities, variable_names = zip( *sorted(zip(qualities, variable_names), key=lambda x: -x[0])) self.qualities = qualities self.variables = [expr.Variable(name=x) for x in variable_names] self.constraints = [] self.optimizer = z3.Optimize() # Direct multiplication between bool var and real quality returns wrong type (BoolRef) if quality is 1, # so we use "If" instead (multiplication is transformed to such an expression anyway): objective = z3.Sum([ z3.If(var.get_z3(), q, 0) for (q, var) in zip(qualities, self.get_variables()) ]) self.objective = self.optimizer.maximize(objective) self.optimizer.push() # restore point for state without constraints
def objective_function(self): """ Objective function is a weighted combination of gate errors and decoherence errors """ import z3 self.fidelity_terms = [self.gate_fidelity[gate] for gate in self.gate_fidelity] self.coherence_terms = [] for q in self.qubit_lifetime: val = -self.qubit_lifetime[q] / min(self.bp_t1_time[q], self.bp_t2_time[q]) self.coherence_terms.append(val) all_terms = [] for item in self.fidelity_terms: all_terms.append(self.weight_factor * item) for item in self.coherence_terms: all_terms.append((1 - self.weight_factor) * item) self.opt.maximize(z3.Sum(all_terms))
def orderG(G, offset): solver = z3.Solver() solver.set('timeout', 1000) # Timeout in one minute V, E = G.nodes, G.edges # Assignment: uniquely give vertical positions ([0, 1, ..., N-1]) to the vertices in G. Positions = [z3.Int('v' + n) for n in V] # positions assignment = dict(zip(V, Assignment)) # vertex -> position solver.add(z3.Distinct(Positions)) # Uniqueness condition on Positions for pos in Positions: solver.add(position >= 0) # Two range constraints on Positions solver.add(position < len(V)) # Objective function CumLengths: A weighted sum of the edge lengths WeightedLengths = [] for n1, n2 in E: pos1, pos2 = assignment[n1], assignment[n2] weight = E[n1, n2]['connections'] WeightedLengths.append(weight * Abs(pos1 - pos2)) Objective = z3.Sum(*WeightedLengths) # Objective formula # Optimization length_contraint = sys.maxsize current_best = dict(zip(Positions, range(len(Positions)))) # Default assignment history = [current_best.evaluate(Objective).as_long()] while True: solver.add(Objective < length_constraint) result = solver.check() if result != z3.sat: break current_best = solver.model() length_constraint = current_best.evaluate( Objective).as_long() # Tighter constraint history.append(length_constraint) Solution = [(v, current_best[v].as_long() + offset) for v in Assignment] print(f'Solution: {Solution}') print(f'Is optimum: {result == z3.unsat}') print(f'Optimum CumLength: {length_constraint}') print('Reduction history:', *history) return Solution
def encode_network(weights, biases, z3_input): """ Returns a z3 expression representing the output of the dnn when applied to the input represented by the list of z3 RealSort constants `z3_input`. The dnn is characterised by the given array of weights and biases, where `weights` is a list of weight matrices for each non-input layer, and `biases` is a list of corresponding bias vectors. The matrices are represented as lists of lists in a column first manner, vecorts as lists. Returns a list of z3 expressions representing the output. """ # z3 consts for values of each layer z3_nodes = [z3_input] for w, b in zip(weights, biases): z3_nodes.append([ z3.Sum([w[j][i] * z3_nodes[-1][j] for j in range(len(w[i]))]) + b[i] for i in range(len(b)) ]) z3_nodes[-1] = [z3.If(z >= 0, z, 0) for z in z3_nodes[-1]] return z3_nodes[-1]
def _coalesing_constraints(manifest, storage, color, volume): constraint = [] # heuristic = z3.Int('coalesing_heuristic') chemical_dict = {} for s in storage: for c in s['chemicals']: name = c['chemical'] if not name in chemical_dict: chemical_dict[name] = 0 chemical_dict[name] += c['total_volume'] - c['current_volume'] for key, value in chemical_dict.items(): # value=0 means no coalesing, therefore no need to have a constraint. if value != 0: summation = z3.Sum([m['volume'] - v for m, v in zip(manifest, volume) if m['chemical'] == key]) constraint.append(summation <= value) # heuristic = heuristic + summation return constraint # , heuristic
def _optimize(self): """ The current implementation of the optimization is based on minimizing the number of selected cpvs, by asking the SAT solver to minimize that number. """ optimize = z3.Optimize() cpvs = set() packages = set() # add the constraint for k, v in self._loaded_map.items(): if (v[0] is dep_solver.kind.cpv): p = self._repo.get_package(k) cpvs.add(k) packages.add(p) optimize.add(self._z3_translator.visit(p.get_spc())) else: optimize.add(self._z3_translator.visit(self._repo.get_cp(k))) # define the optimization criteria optimize.minimize( z3.Sum( tuple( z3.If(self._z3_translator.visit(cpv), 1, 0) for cpv in cpvs))) # forbid to use non loaded packages simplify = gzl.substitutionVisitor({}).visit for p in packages: to_disable = p._dep_package.difference(cpvs) if (len(to_disable) is not 0): optimize.add( self._z3_translator.visit( simplify(gzl.Not(gzl.Or(*to_disable))))) cpvs.update(to_disable) # get the model optimize.check() self._solution = optimize.model() self._solution = { str(var) for var in self._z3_translator._var_map.values() if (self._solution[var]) }
def solve_weights_problem(N): solver = z3.Solver() weights = [z3.Int("w" + str(i)) for i in range(N)] for i in range(N): # Weights positive solver.add(weights[i] > 0) for j in range(i + 1, N): # Weights not equal solver.add(weights[i] != weights[j]) # Sum of these is equal to the sum of some other subset others = weights[:i] + weights[i + 1:j] + weights[j + 1:] sums = [z3.Sum(otherset) for otherset in powerset(others)] solver.add(z3.Or([weights[i] + weights[j] == sum for sum in sums])) # Solve the constraints. ## Uncomment to print assertions # print(f"Constraints: {solver.assertions()}") result = str(solver.check()) print(f"Result: {result}") if result == 'sat': print(f"Model: {solver.model()}") return result
def incidence_sums(petrinet, variables, subnet_transitions='all', reverse=False): pre_matrix, post_matrix = petrinet num_places, num_transitions = pre_matrix.shape if subnet_transitions == 'all': subnet_transitions = set(range(num_transitions)) if reverse: pre_matrix, post_matrix = post_matrix, pre_matrix sums = [] for p in range(num_places): if config.representation_mode == config.DENSE: nonzero = np.union1d(pre_matrix[p].getA1().nonzero()[0], post_matrix[p].getA1().nonzero()[0]) elif config.representation_mode == config.SPARSE: nonzero = np.union1d( pre_matrix.getrow(p).nonzero()[1], post_matrix.getrow(p).nonzero()[1]) incidence_row = [(post_matrix[p, t] - pre_matrix[p, t], variables[t]) for t in nonzero if t in subnet_transitions] sum_elements = [ _expression(coeff, var) for coeff, var in incidence_row if coeff != 0 ] curr_sum = z3.Sum( sum_elements) if len(sum_elements) > 0 else z3.IntVal(0) sums.append(curr_sum) return sums