def _bitvector_to_bdd(aut): """Return `Automaton` with BDD formulas. @type aut: `Automaton` """ players = dict(aut.players) table = aut.vars bits = bv.bit_table(table, table) # index both, to allow for unquantified parameters ubits = set(b for b, d in bits.items() if d['owner'] == 'env') ebits = set(b for b, d in bits.items() if d['owner'] == 'sys') b = _pick_var_order(bits, ubits) b = _add_primed_bits(b) bdd = aut.bdd # define levels only if no existing vars if bdd.vars: for var in b: bdd.add_var(var) else: for level, var in enumerate(b): bdd.add_var(var, level) # bundle as: a = Automaton() a.vars = copy.deepcopy(table) a.players = players a.bdd = bdd # slugsin -> BDD # add long attributes first, # to improve effectiveness of reordering. # better if each attr is one formula. from_sections = _make_section_map(aut) to_sections = _make_section_map(a) lengths = {k: _section_len(v) for k, v in from_sections.items()} sort = sorted(from_sections, key=lengths.__getitem__, reverse=True) for section in sort: p = from_sections[section] q = to_sections[section] _to_bdd(p, q, bdd) # vars player_vars = {k for k, d in table.items() if d['owner'] in players} if not player_vars: print('Warning: no player variables.') return a bits = bv.bit_table(player_vars, table) prime, partition = _partition_vars(bits, ubits, ebits) a.uvars = partition['uvars'] a.upvars = partition['upvars'] a.evars = partition['evars'] a.epvars = partition['epvars'] a.ubvars = set(a.uvars).union(a.upvars) a.ebvars = set(a.evars).union(a.epvars) a.uevars = set(a.uvars).union(a.evars) a.uepvars = set(a.upvars).union(a.epvars) # priming a.prime = prime a.unprime = {v: k for k, v in prime.items()} return a
def _refine_vars(fol_vars, table): """Return bits that represent the `fol_vars`.""" if fol_vars: bits = bv.bit_table(fol_vars, table) else: # `bit_table` raises `AssertionError` for # empty `fol_vars` bits = set() return bits
def pick_iter(self, u, care_vars=None): """Generator of first-order satisfying assignments.""" if care_vars is None: care_bits = None elif care_vars: care_bits = bv.bit_table(care_vars, self.vars) else: care_bits = set() for bit_assignment in self.bdd.pick_iter(u, care_vars=care_bits): for d in enum._bitfields_to_int_iter(bit_assignment, self.vars): yield d
def add_vars(self, dvars): r"""Refine variables in `dvars`. The variables in `dvars` should have type hints. A Boolean-valued variable remains so. An integer-valued variable is assumed to take the value resulting as a function of some (fresh) Boolean-valued variables. Sometimes these variables are called "bits". The function is based on two's complement, see `omega.logic.bitvector` for details. In other words, type hints are used to pick a refinement of integers by finitely many bits. A sufficient number of bits is selected, and operations assume this as type invariant, *not* the exact type hint given. For example, an integer `x` with type hint `x \in 0..2` will be refined using 2 Boolean-valued variables `x_0` and `x_1`. All operations and quantification will assume that `x \in 0..3`. Mind the extra value (3) allowed, compared to the hint (0..2). Attention: - Fine-grained type predicates (`n..m` with `n` and `m` other than powers of 2) are not managed here. - Priming is not reasoned about here. Priming is cared for by other modules. The method `add_vars` adds to `vars[var]` the keys: - `"bitnames"`: `list` - `"signed"`: `True` if signed integer - `"width"`: `len(bitnames)` """ assert dvars, dvars self._avoid_redeclaration(dvars) vrs = {k: v for k, v in dvars.items() if k not in self.vars} if not vrs: return t = bv.bitblast_table(vrs) self.vars.update(t) bits = bv.bit_table(t, t) for bit in bits: self.bdd.add_var(bit)
def pick_iter(self, u, care_vars=None): """Generator of first-order satisfying assignments.""" if care_vars is None: care_bits = None elif care_vars: care_bits = bv.bit_table(care_vars, self.vars) else: care_bits = set() for bit_assignment in self.bdd.pick_iter( u, care_vars=care_bits): for d in enum._bitfields_to_int_iter( bit_assignment, self.vars): yield d
def pick_iter(self, u, care_vars=None): """Generator of first-order satisfying assignments.""" if care_vars is None: care_bits = None elif care_vars: care_bits = bv.bit_table(care_vars, self.vars) else: care_bits = set() vrs = self.support(u) if care_vars: vrs.update(care_vars) for bit_assignment in self.bdd.pick_iter(u, care_vars=care_bits): for d in enum._bitfields_to_int_iter(bit_assignment, self.vars): assert set(d).issubset(vrs), (d, vrs, bit_assignment) yield d
def exist(self, qvars, u): """Existentially quantify `qvars` in `u`.""" if len(qvars) == 0: return u qbits = bv.bit_table(qvars, self.vars) return self.bdd.exist(qbits, u)
def _bitvector_to_bdd(aut): """Return `Automaton` with BDD formulas. @type aut: `Automaton` """ players = dict(aut.players) table = aut.vars bits = bv.bit_table(table, table) # index both, to allow for unquantified parameters ubits = set(b for b, d in bits.items() if d['owner'] == 'env') ebits = set(b for b, d in bits.items() if d['owner'] == 'sys') b = _pick_var_order(bits, ubits) b = _add_primed_bits(b) bdd = aut.bdd # define levels only if no existing vars if bdd.vars: for var in b: bdd.add_var(var) else: for level, var in enumerate(b): bdd.add_var(var, level) # bundle as: a = Automaton() a.vars = copy.deepcopy(table) a.players = players a.bdd = bdd # slugsin -> BDD # add long attributes first, # to improve effectiveness of reordering. # better if each attr is one formula. from_sections = _make_section_map(aut) to_sections = _make_section_map(a) lengths = { k: _section_len(v) for k, v in from_sections.items()} sort = sorted( from_sections, key=lengths.__getitem__, reverse=True) for section in sort: p = from_sections[section] q = to_sections[section] _to_bdd(p, q, bdd) # vars player_vars = {k for k, d in table.items() if d['owner'] in players} if not player_vars: print('Warning: no player variables.') return a bits = bv.bit_table(player_vars, table) prime, partition = _partition_vars(bits, ubits, ebits) a.uvars = partition['uvars'] a.upvars = partition['upvars'] a.evars = partition['evars'] a.epvars = partition['epvars'] a.ubvars = set(a.uvars).union(a.upvars) a.ebvars = set(a.evars).union(a.epvars) a.uevars = set(a.uvars).union(a.evars) a.uepvars = set(a.upvars).union(a.epvars) # priming a.prime = prime a.unprime = {v: k for k, v in prime.items()} return a