def _init_from_ts(initial_nodes, nodevar, dvars, ignore_initial=False): """Return initial condition.""" if ignore_initial: return list() if not initial_nodes: raise Exception('Transition system without initial states.') return [stx.disj(_assign(nodevar, u, dvars) for u in initial_nodes)]
def at_least_one_queen_per_row(n): """Return formula as `str`.""" c = list() for i in range(n): xijs = [_var_str(i, j) for j in range(n)] s = disj(xijs) c.append(s) return conj(c)
def _init_from_ts( initial_nodes, nodevar, dvars, ignore_initial=False): """Return initial condition.""" if ignore_initial: return list() if not initial_nodes: raise Exception('Transition system without initial states.') return [stx.disj(_assign(nodevar, u, dvars) for u in initial_nodes)]
def dumps_cover( cover, f, care, fol, latex=False, show_dom=False, show_limits=False, comment=True): """Return disjunction of orthotopes in `cover`, one per line. @param latex: use `pf.sty` commands @param show_dom: if `care` implies type hints, then conjoin type hints (`fol.vars[var]['dom']`) @param show_limits: conjoin limits of bitfield values @param comment: if `True`, then list support of `f`, `cover` @rtype: `str` """ prm = lat.setup_aux_vars(f, care, fol) c = list() if show_limits: r = tyh._list_limits(prm.x_vars, fol.vars) c.extend(r) show_dom = show_dom and _care_implies_type_hints(f, care, fol) if show_dom: r = tyh._list_type_hints(prm.x_vars, fol.vars) c.extend(r) else: log.info( 'type hints omitted') r = lat.list_expr( cover, prm, fol, use_dom=show_dom, latex=latex) s = stx.vertical_op(r, op='or', latex=latex, spacing=2) c.append(s) if care != fol.true: c.append('care expression') s = stx.vertical_op(c, op='and', latex=latex) f_vars = fol.support(f) care_vars = fol.support(care) s_comment = ( '(* `f` depends on: {f_vars} *)\n' '(* `care` depends on: {care_vars} *)\n' '(* The minimal cover is: *)').format( f_vars=_comma_sorted(f_vars), care_vars=_comma_sorted(care_vars)) if comment: s = '{comment}\n{s}'.format(comment=s_comment, s=s) # could add option to find minimal cover for care too # postcondition r = lat.list_expr( cover, prm, fol, use_dom=show_dom) r = stx.disj(r) g = fol.add_expr(r) # ensure that `g` equals `f` inside `care` # `g` can be arbitrary outside of `care` assert (g & care) == (f & care), r return s
def mutex(v): """Return formula for at most one variable `True`. @param v: iterable of variables as `str` """ v = set(v) c = list() for x in v: rest = disj(y for y in v if y != x) s = '{x} -> !({rest})'.format(x=x, rest=rest) c.append(s) return conj(c)
def dumps_cover( cover, f, care, fol, latex=False, show_dom=False, show_limits=False): """Return disjunction of orthotopes in `cover`, one per line. @param latex: use `pf.sty` commands @param show_dom: if `care` implies type hints, then conjoin type hints (`fol.vars[var]['dom']`) @param show_limits: conjoin limits of bitfield values @rtype: `str` """ prm = lat.setup_aux_vars(f, care, fol) c = list() if show_limits: r = tyh._list_limits(prm.x_vars, fol.vars) c.extend(r) show_dom = show_dom and _care_implies_type_hints(f, care, fol) if show_dom: r = tyh._list_type_hints(prm.x_vars, fol.vars) c.extend(r) else: log.info( 'type hints omitted (care does not imply them)') r = lat.list_expr( cover, prm, fol, use_dom=show_dom, latex=latex) s = stx.vertical_op(r, op='or', latex=latex) c.append(s) n_expr = len(r) if care != fol.true: c.append('care expression') s = stx.vertical_op(c, op='and', latex=latex) f_vars = fol.support(f) care_vars = fol.support(care) s = ( '(* `f` depends on: {f_vars} *)\n' '(* `care` depends on: {care_vars} *)\n' '(* The minimal cover is: *)\n{s}').format( f_vars=_comma_sorted(f_vars), care_vars=_comma_sorted(care_vars), s=s) # could add option to find minimal cover for care too # postcondition r = lat.list_expr( cover, prm, fol, use_dom=show_dom) r = stx.disj(r) g = fol.add_expr(r) # ensure that `g` equals `f` inside `care` # `g` can be arbitrary outside of `care` assert (g & care) == (f & care), r return s
def robots_example(fol): """Return cooperative winning set from ACC'16 example.""" c = [ '(x = 0) /\ (y = 4)', '(x = 0) /\ (y = 5)', '(x = 0) /\ (y = 2)', '(x = 0) /\ (y = 3)', '(x = 0) /\ (y = 6)', '(x = 0) /\ (y = 7)', '(x = 1) /\ (y = 0)', '(x = 1) /\ (y = 2)', '(x = 1) /\ (y = 4)', '(x = 1) /\ (y = 6)', '(x = 1) /\ (y = 5)', '(x = 1) /\ (y = 3)', '(x = 1) /\ (y = 7)', '(x = 2) /\ (y = 0)', '(x = 2) /\ (y = 1)', '(x = 2) /\ (y = 6)', '(x = 2) /\ (y = 7)', '(x = 3) /\ (y = 0)', '(x = 3) /\ (y = 2)', '(x = 3) /\ (y = 6)', '(x = 3) /\ (y = 1)', '(x = 3) /\ (y = 7)', '(x = 4) /\ (y = 0)', '(x = 4) /\ (y = 1)', '(x = 4) /\ (y = 2)', '(x = 4) /\ (y = 3)', '(x = 4) /\ (y = 6)', '(x = 4) /\ (y = 7)', '(x = 5) /\ (y = 0)', '(x = 5) /\ (y = 2)', '(x = 5) /\ (y = 4)', '(x = 5) /\ (y = 6)', '(x = 5) /\ (y = 1)', '(x = 5) /\ (y = 3)', '(x = 5) /\ (y = 7)' ] s = stx.disj(c) u = fol.add_expr(s) return u
def test_orthotopes_using_robots_example(): aut, prm = setup_aut(15, 15) p_vars = prm.p_vars # this predicate is constructed by `contract_maker` # for the robots example in ACC 2016 f = robots_example(aut) prm.p_leq_q = lat.subseteq(prm._varmap, aut) prm.p_eq_q = lat.eq(prm._varmap, aut) u = lat.prime_implicants(f, prm, aut) support = aut.support(u) assert support == set(p_vars), (support, p_vars) n_primes = aut.count(u) k = aut.count(u) assert n_primes == k, (n_primes, k) log.info('{n} prime implicants'.format(n=n_primes)) u = lat.essential_orthotopes(f, prm, aut) support = aut.support(u) assert support == set(p_vars), (support, p_vars) n_essential = aut.count(u) k = aut.count(u) assert n_essential == k, (n_essential, k) log.info('{n} essential prime implicants'.format(n=n_essential)) assert n_essential == 7, n_essential # result: all primes are essential in this example # care = aut.true s = cov.dumps_cover(u, f, care, aut) log.info(s) log.info('BDD has {n} nodes'.format(n=len(aut.bdd))) # confirm that essential orthotopes cover exactly `f` c = lat.list_expr(u, prm, aut, simple=True) s = stx.disj(c) log.info(s) z = aut.add_expr(s) z = aut.exist(['a_x', 'b_x', 'a_y', 'b_y'], z) assert aut.support(z) == aut.support(f) assert z == f if plt is not None: _plot_orthotopes_for_robots_example(u, f, prm._px, xvars, aut) # pprint.pprint(aut.bdd.statistics()) # pprint.pprint(aut.bdd.vars) log.info('{n} nodes in manager'.format(n=len(aut.bdd)))
def implicants_intersect(prm, fol): """Return `ab \cap uv # \emptyset`. Equivalent to \E x: /\ x \in concretization(ab) /\ x \in concretization(uv) The representation of orthotopes as products of intervals allows for a direct construction that avoids quantification over `x`. """ # disjoint intervals in at least one dimension s = stx.disj(''' ({b} < {u}) \/ ({v} < {a}) '''.format(a=a, b=b, u=u, v=v) for (a, b), (u, v) in prm._varmap.items()) r = fol.add_expr(s) return ~r
def implicants_intersect(prm, fol): """Return `ab \cap uv # \emptyset`. Equivalent to \E x: /\ x \in concretization(ab) /\ x \in concretization(uv) The representation of orthotopes as products of intervals allows for a direct construction that avoids quantification over `x`. """ # disjoint intervals in at least one dimension s = stx.disj(''' ({b} < {u}) \/ ({v} < {a}) '''.format(a=a, b=b, u=u, v=v) for (a, b), (u, v) in prm._varmap.items()) r = fol.add_expr(s) return ~ r
def robots_example(fol): """Return cooperative winning set from ACC'16 example.""" c = [ '(x = 0) /\ (y = 4)', '(x = 0) /\ (y = 5)', '(x = 0) /\ (y = 2)', '(x = 0) /\ (y = 3)', '(x = 0) /\ (y = 6)', '(x = 0) /\ (y = 7)', '(x = 1) /\ (y = 0)', '(x = 1) /\ (y = 2)', '(x = 1) /\ (y = 4)', '(x = 1) /\ (y = 6)', '(x = 1) /\ (y = 5)', '(x = 1) /\ (y = 3)', '(x = 1) /\ (y = 7)', '(x = 2) /\ (y = 0)', '(x = 2) /\ (y = 1)', '(x = 2) /\ (y = 6)', '(x = 2) /\ (y = 7)', '(x = 3) /\ (y = 0)', '(x = 3) /\ (y = 2)', '(x = 3) /\ (y = 6)', '(x = 3) /\ (y = 1)', '(x = 3) /\ (y = 7)', '(x = 4) /\ (y = 0)', '(x = 4) /\ (y = 1)', '(x = 4) /\ (y = 2)', '(x = 4) /\ (y = 3)', '(x = 4) /\ (y = 6)', '(x = 4) /\ (y = 7)', '(x = 5) /\ (y = 0)', '(x = 5) /\ (y = 2)', '(x = 5) /\ (y = 4)', '(x = 5) /\ (y = 6)', '(x = 5) /\ (y = 1)', '(x = 5) /\ (y = 3)', '(x = 5) /\ (y = 7)'] s = stx.disj(c) u = fol.add_expr(s) return u
def _sys_trans(g, nodevar, dvars): """Convert transition relation to safety formula.""" logger.debug('modeling sys transitions in logic') sys_trans = list() for u in g: pre = _assign(nodevar, u, dvars) # no successors ? if not g.succ.get(u): logger.debug('node: {u} is deadend !'.format(u=u)) sys_trans.append('({pre}) => False'.format(pre=pre)) continue post = list() for u, v, d in g.edges(u, data=True): t = dict(d) t[stx.prime(nodevar)] = v r = _to_action(t, dvars) post.append(r) c = '({pre}) => ({post})'.format(pre=pre, post=stx.disj(post)) sys_trans.append(c) s = stx.conj(sys_trans, sep='\n') return s
def _env_trans(g, nodevar, dvars, self_loops): """Convert environment transitions to safety formula. @type g: `networkx.MultiDigraph` @param nodevar: name of variable representing current node @type nodevar: `str` @type dvars: `dict` """ env_trans = list() for u in g: pre = _assign(nodevar, u, dvars) # no successors ? if not g.succ.get(u): env_trans.append('{pre} => False'.format(pre=pre)) if not self_loops: warnings.warn( 'Environment dead-end found.\n' 'If sys can force env to dead-end,\n' 'then GR(1) assumption becomes False,\n' 'and spec trivially True.') continue post = list() sys = list() for u, v, d in g.out_edges(u, data=True): # action t = dict(d) t[stx.prime(nodevar)] = v r = _to_action(t, dvars) post.append(r) # what sys vars ? t = {k: v for k, v in d.items() if k not in g.env_vars} r = _to_action(t, dvars) sys.append(r) # avoid sys winning env by blocking all edges # post.append(stx.conj_neg(sys)) env_trans.append('({pre}) => ({post})'.format( pre=pre, post=stx.disj(post))) s = stx.conj(env_trans, sep='\n') return s
def _env_trans(g, nodevar, dvars, self_loops): """Convert environment transitions to safety formula. @type g: `networkx.MultiDigraph` @param nodevar: name of variable representing current node @type nodevar: `str` @type dvars: `dict` """ env_trans = list() for u in g: pre = _assign(nodevar, u, dvars) # no successors ? if not g.succ.get(u): env_trans.append('{pre} => False'.format(pre=pre)) if not self_loops: warnings.warn('Environment dead-end found.\n' 'If sys can force env to dead-end,\n' 'then GR(1) assumption becomes False,\n' 'and spec trivially True.') continue post = list() sys = list() for u, v, d in g.out_edges(u, data=True): # action t = dict(d) t[stx.prime(nodevar)] = v r = _to_action(t, dvars) post.append(r) # what sys vars ? t = {k: v for k, v in d.items() if k not in g.env_vars} r = _to_action(t, dvars) sys.append(r) # avoid sys winning env by blocking all edges # post.append(stx.conj_neg(sys)) env_trans.append('({pre}) => ({post})'.format(pre=pre, post=stx.disj(post))) s = stx.conj(env_trans, sep='\n') return s
def _env_trans_from_sys_ts(g, nodevar, dvars): """Return safety assumption to prevent env from blocking sys.""" denv = {k: v for k, v in dvars.items() if k in g.env_vars} env_trans = list() for u in g: # no successor states ? if not g.succ.get(u): continue # collect possible next env actions c = set() for u, w, d in g.edges(u, data=True): t = _to_action(d, denv) if not t: continue c.add(t) # no next env actions ? if not c: continue post = stx.disj(c) pre = _assign(nodevar, u, dvars) env_trans.append('(({pre}) => ({post}))'.format(pre=pre, post=post)) s = stx.conj(env_trans, sep='\n') return s
def _env_trans_from_sys_ts(g, nodevar, dvars): """Return safety assumption to prevent env from blocking sys.""" denv = {k: v for k, v in dvars.items() if k in g.env_vars} env_trans = list() for u in g: # no successor states ? if not g.succ.get(u): continue # collect possible next env actions c = set() for u, w, d in g.edges(u, data=True): t = _to_action(d, denv) if not t: continue c.add(t) # no next env actions ? if not c: continue post = stx.disj(c) pre = _assign(nodevar, u, dvars) env_trans.append('(({pre}) => ({post}))'.format( pre=pre, post=post)) s = stx.conj(env_trans, sep='\n') return s