def check_unreal( ltl_text, part_text, is_moore, ltl3ba: LTL3BA, solver_factory: Z3SolverFactory, min_size, max_size, ltl3ba_timeout_sec=None, opt_level=0, ) -> LTS: """ :raise: subprocess.TimeoutException :arg opt_level: Note that opt_level > 0 may introduce unsoundness (returns unrealizable while it is) """ timer = Timer() outputs, inputs, expr = parse_acacia_and_build_expr(ltl_text, part_text, ltl3ba, opt_level) timer.sec_restart() automaton = ltl3ba.convert(expr, timeout=ltl3ba_timeout_sec) # note no negation logging.info("(unreal) automaton size is: %i" % len(automaton.nodes)) logging.debug("(unreal) automaton (dot) is:\n" + automaton2dot.to_dot(automaton)) logging.debug("(unreal) automaton translation took (sec): %i" % timer.sec_restart()) encoder = create_encoder(inputs, outputs, not is_moore, automaton, solver_factory.create()) model = model_searcher.search(min_size, max_size, encoder) logging.debug("(unreal) model_searcher.search took (sec): %i" % timer.sec_restart()) return model
def check_real(ltl_text: str, part_text: str, is_moore: bool, ltl_to_atm: LTLToAutomaton, min_k: int, max_k: int, opt_level: int) -> str or None: spec = parse_acacia_and_build_expr(ltl_text, part_text, ltl_to_atm, opt_level) assert BAD_OUT_NAME not in (spec.inputs | spec.outputs), 'name collision' return _check_real(spec, is_moore, ltl_to_atm, min_k, max_k)
def check_real(ltl_text, part_text, is_moore, ltl_to_atm: LTLToAutomaton, solver: SolverInterface, max_k: int, min_size, max_size, opt_level=0) -> LTS: """ When opt_level>0, introduce incompleteness (but it is sound: if returns REAL, then REAL) When max_k>0, reduce UCW to k-UCW. """ timer = Timer() spec = parse_acacia_and_build_expr(ltl_text, part_text, ltl_to_atm, opt_level) logging.info("LTL formula size: %i", expr_size(spec.formula)) timer.sec_restart() automaton = ltl_to_atm.convert(~spec.formula) logging.info('automaton size is: %i' % len(automaton.nodes)) logging.debug('automaton (dot) is:\n' + automaton_to_dot.to_dot(automaton)) logging.debug('automaton translation took (sec): %i' % timer.sec_restart()) tau_desc = build_tau_desc(spec.inputs) desc_by_output = dict( (o, build_output_desc(o, is_moore, spec.inputs)) for o in spec.outputs) if max_k == 0: logging.info("using CoBuchiEncoder") encoder = CoBuchiEncoder(automaton, tau_desc, spec.inputs, desc_by_output, range(max_size)) model = model_searcher.search(min_size, max_size, encoder, solver) else: coreach_automaton = k_reduce(automaton, max_k) # with open('/tmp/orig.dot', 'w') as f: # f.write(automaton_to_dot.to_dot(automaton)) # with open('/tmp/red.dot', 'w') as f: # f.write(automaton_to_dot.to_dot(coreach_automaton)) # exit() logging.info("using CoReachEncoder") logging.info('co-reachability automaton size is: %i' % len(coreach_automaton.nodes)) logging.debug('co-reachability automaton (dot) is:\n' + automaton_to_dot.to_dot(coreach_automaton)) encoder = CoreachEncoder(coreach_automaton, tau_desc, spec.inputs, desc_by_output, range(max_size), max_k) model = model_k_searcher.search(min_size, max_size, max_k, encoder, solver) logging.info('searching a model took (sec): %i' % timer.sec_restart()) return model
def check_unreal(ltl_text, part_text, is_moore, ltl_to_atm: LTLToAutomaton, solver: SolverInterface, max_k: int, min_size, max_size, opt_level=0) -> LTS: """ Note that opt_level > 0 may introduce unsoundness (returns unrealizable while it is). """ timer = Timer() spec = parse_acacia_and_build_expr(ltl_text, part_text, ltl_to_atm, opt_level) logging.info("LTL formula size: %i", expr_size(spec.formula)) timer.sec_restart() automaton = ltl_to_atm.convert(spec.formula) logging.info('(unreal) automaton size is: %i' % len(automaton.nodes)) logging.debug('(unreal) automaton (dot) is:\n' + automaton_to_dot.to_dot(automaton)) logging.debug('(unreal) automaton translation took (sec): %i' % timer.sec_restart()) # note: inputs/outputs and machine type are reversed tau_desc = build_tau_desc(spec.outputs) desc_by_output = dict((i, build_output_desc(i, not is_moore, spec.outputs)) for i in spec.inputs) if max_k == 0: encoder = CoBuchiEncoder(automaton, tau_desc, spec.outputs, desc_by_output, range(max_size)) model = model_searcher.search(min_size, max_size, encoder, solver) else: coreach_automaton = k_reduce(automaton, max_k) logging.info("(unreal) using CoReachEncoder") logging.info('(unreal) co-reachability automaton size is: %i' % len(coreach_automaton.nodes)) logging.debug('(unreal) co-reachability automaton (dot) is:\n' + automaton_to_dot.to_dot(coreach_automaton)) encoder = CoreachEncoder(coreach_automaton, tau_desc, spec.outputs, desc_by_output, range(max_size), max_k) model = model_k_searcher.search(min_size, max_size, max_k, encoder, solver) logging.debug('(unreal) model_searcher.search took (sec): %i' % timer.sec_restart()) return model
def check_real( ltl_text, part_text, is_moore, ltl3ba, solver_factory: Z3SolverFactory, min_size, max_size, opt_level=2 ) -> LTS: """ :param opt_level: values > 0 introduce incompleteness (but it is sound: if returns REAL, then REAL) """ timer = Timer() inputs, outputs, expr = parse_acacia_and_build_expr(ltl_text, part_text, ltl3ba, opt_level) timer.sec_restart() automaton = ltl3ba.convert(~expr) logging.info("(real) automaton size is: %i" % len(automaton.nodes)) logging.debug("(real) automaton (dot) is:\n" + automaton2dot.to_dot(automaton)) logging.debug("(real) automaton translation took (sec): %i" % timer.sec_restart()) encoder = create_encoder(inputs, outputs, is_moore, automaton, solver_factory.create()) model = model_searcher.search(min_size, max_size, encoder) logging.debug("(real) model_searcher.search took (sec): %i" % timer.sec_restart()) return model
def main(): parser = argparse.ArgumentParser( description= 'Translate LTL spec (TLSF or Acacia format) into AIGER via k-Live automata.', formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument('spec', metavar='spec', type=str, help='input spec (in Wring or TLSF format)') parser.add_argument( '--k', '-k', default=8, required=False, type=int, help='max number of visits to a bad state (within one SCC)') gr = parser.add_mutually_exclusive_group() gr.add_argument('--spot', action='store_true', default=True, dest='spot', help='use SPOT for translating LTL->BA') gr.add_argument('--ltl3ba', action='store_false', default=False, dest='spot', help='use LTL3BA for translating LTL->BA') parser.add_argument('--mealy', action='store_true', default=False, dest='acacia_mealy', help='(for Acacia only) force Mealy machines') parser.add_argument( '--noopt', action='store_true', default=False, dest='noopt', help= 'Do not strengthen the specification (using the separation into safety-liveness)' ) parser.add_argument('--out', '-o', required=False, type=str, help='output AIGER file') parser.add_argument('-v', '--verbose', action='count', default=0) args = parser.parse_args() setup_logging(args.verbose) print(args) ltl_to_automaton = (translator_via_ltl3ba.LTLToAtmViaLTL3BA, translator_via_spot.LTLToAtmViaSpot )[args.spot]() # type: LTLToAutomaton ltl_text, part_text, is_moore = convert_tlsf_or_acacia_to_acacia( args.spec, not args.acacia_mealy) spec = parse_acacia_and_build_expr(ltl_text, part_text, ltl_to_automaton, 0 if args.noopt else 2) ucw_automaton = ltl_to_automaton.convert(spec.formula) aiger_str = convert_spec_to_aiger(spec.inputs, spec.outputs, ucw_automaton, args.k, 'bad') if args.out: with open(args.out, 'w') as f: f.write(aiger_str) else: print(aiger_str)