Beispiel #1
0
def _run(default_models, is_moore, anon_inputs, anon_outputs,
         sync_automaton: Automaton, global_automatae_pairs, bounds,
         solver_creater: Z3SolverFactory, logic, logger) -> Bool:
    _log_automatae(logger, global_automatae_pairs, sync_automaton)

    if default_models:
        logger.info('model is given: checking it..')

        underlying_solver = solver_creater.create('_check')

        model_checker = par_model_searcher.ParModelSearcher()
        models = model_checker.check(
            logic, is_moore, global_automatae_pairs, sync_automaton,
            anon_inputs, anon_outputs, underlying_solver,
            BaseNames(SCHED_ID_PREFIX, ACTIVE_NAME, SENDS_NAME,
                      SENDS_PREV_NAME, HAS_TOK_NAME), default_models[0])
        underlying_solver.die()
        if models:
            logger.info('the model passed checking!')
            return models

        logger.info(
            'the model did not pass the check - searching another one..')

    underlying_solver = solver_creater.create()
    model_searcher = par_model_searcher.ParModelSearcher()
    models = model_searcher.search(
        logic, is_moore, global_automatae_pairs, sync_automaton, anon_inputs,
        anon_outputs, bounds, underlying_solver,
        BaseNames(SCHED_ID_PREFIX, ACTIVE_NAME, SENDS_NAME, SENDS_PREV_NAME,
                  HAS_TOK_NAME))

    underlying_solver.die()

    return models
Beispiel #2
0
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
Beispiel #3
0
def _run(default_models,
         is_moore,
         anon_inputs, anon_outputs,
         sync_automaton:Automaton, global_automatae_pairs,
         bounds,
         solver_creater:Z3SolverFactory,
         logic,
         logger) -> Bool:
    _log_automatae(logger, global_automatae_pairs, sync_automaton)

    if default_models:
        logger.info('model is given: checking it..')

        underlying_solver = solver_creater.create('_check')

        model_checker = par_model_searcher.ParModelSearcher()
        models = model_checker.check(logic,
                                     is_moore,
                                     global_automatae_pairs,
                                     sync_automaton,
                                     anon_inputs, anon_outputs,
                                     underlying_solver,
                                     BaseNames(SCHED_ID_PREFIX, ACTIVE_NAME, SENDS_NAME, SENDS_PREV_NAME, HAS_TOK_NAME),
                                     default_models[0])
        underlying_solver.die()
        if models:
            logger.info('the model passed checking!')
            return models

        logger.info('the model did not pass the check - searching another one..')

    underlying_solver = solver_creater.create()
    model_searcher = par_model_searcher.ParModelSearcher()
    models = model_searcher.search(logic,
                                   is_moore,
                                   global_automatae_pairs,
                                   sync_automaton,
                                   anon_inputs, anon_outputs,
                                   bounds,
                                   underlying_solver,
                                   BaseNames(SCHED_ID_PREFIX, ACTIVE_NAME, SENDS_NAME, SENDS_PREV_NAME,
                                             HAS_TOK_NAME))

    underlying_solver.die()

    return models
Beispiel #4
0
def check_real(spec: Spec, min_size, max_size, ltl_to_atm: LTLToAutomaton,
               solver_factory: Z3SolverFactory,
               use_direct_encoding: bool) -> LTS or None:
    shared_aht, dstFormPropMgr = SharedAHT(), DstFormulaPropMgr()

    # normalize formula (negations appear only in front of basic propositions)
    spec.formula = NNFNormalizer().dispatch(spec.formula)
    logging.info("CTL* formula size: %i", expr_size(spec.formula))

    if use_direct_encoding:
        top_formula, atm_by_p, UCWs = automize_ctl(spec.formula, ltl_to_atm)
        logging.info("Total number of states in sub-automata: %i",
                     sum([len(a.nodes) for a in atm_by_p.values()]))
        for p, atm in atm_by_p.items():
            logging.debug(str(p) + ', atm: \n' + automaton_to_dot.to_dot(atm))
        encoder = CTLEncoderDirect(
            top_formula, atm_by_p, UCWs, build_tau_desc(spec.inputs),
            spec.inputs,
            dict((o, build_output_desc(o, True, spec.inputs))
                 for o in spec.outputs), range(max_size))
    else:
        aht_automaton = ctl2aht.ctl2aht(spec, ltl_to_atm, shared_aht,
                                        dstFormPropMgr)

        aht_nodes, aht_transitions = get_reachable_from(
            aht_automaton.init_node, shared_aht.transitions, dstFormPropMgr)
        logging.info('The AHT automaton size (nodes/transitions) is: %i/%i' %
                     (len(aht_nodes), len(aht_transitions)))
        if not aht_transitions:
            logging.info('AHT is empty => the spec is unrealizable!')
            return None

        if logging.getLogger().isEnabledFor(
                logging.DEBUG):  # aht2dot takes long time
            logging.debug('AHT automaton (dot) is...\n')
            logging.debug(
                aht2dot.convert(aht_automaton, shared_aht, dstFormPropMgr))

        encoder = CTLEncoderViaAHT(
            aht_automaton, aht_transitions, dstFormPropMgr,
            build_tau_desc(spec.inputs), spec.inputs,
            dict((o, build_output_desc(o, True, spec.inputs))
                 for o in spec.outputs), range(max_size))

    model = model_searcher.search(min_size, max_size, encoder,
                                  solver_factory.create())
    return model
Beispiel #5
0
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
Beispiel #6
0
    parser.add_argument('--maxsize', metavar='maxsize', type=int, default=4, required=False,
                        help='stop at this size')

    parser.add_argument('-v', '--verbose', action='count', default=0)

    args = parser.parse_args()
    assert args.minsize <= args.maxsize

    logger = setup_logging(args.verbose)
    logger.info(args)

    with tempfile.NamedTemporaryFile(dir='./') as smt_file:
        smt_files_prefix = smt_file.name

    ltl_to_automaton = translator_via_spot.LTLToAtmViaSpot()

    solver_factory = Z3SolverFactory(smt_files_prefix,
                                     Z3_PATH,  # we don't really need this
                                     False,
                                     True,
                                     True)

    elli.check_real(readfile(args.spec),
                    readfile(args.spec.replace('.ltl', '.part')),
                    args.moore,
                    ltl_to_automaton, solver_factory.create(),
                    0,
                    args.minsize, args.maxsize)
    solver_factory.down_solvers()
    exit(0)
Beispiel #7
0
def main():
    parser = argparse.ArgumentParser(
        description='Bounded Synthesis Tool',
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)

    parser.add_argument('spec',
                        metavar='spec',
                        type=str,
                        help='the specification file (Acacia or TLSF format)')

    gr = parser.add_mutually_exclusive_group()
    gr.add_argument('--moore',
                    action='store_true',
                    default=True,
                    dest='moore',
                    help='system is Moore (ignored for TLSF)')
    gr.add_argument('--mealy',
                    action='store_false',
                    default=False,
                    dest='moore',
                    help='system is Mealy (ignored for TLSF)')

    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(
        '--maxK',
        type=int,
        default=0,
        help="reduce liveness to co-reachability (safety)."
        "This sets the upper bound on the number of 'bad' visits."
        "We iterate over increasing k (exact value of k is set heuristically)."
        "(k=0 means no reduction)")

    gr = parser.add_mutually_exclusive_group()
    gr.add_argument(
        '--bound',
        metavar='bound',
        type=int,
        default=32,
        required=False,
        help=
        'upper bound on the size of the model (for unreal this specifies size of env model)'
    )
    gr.add_argument(
        '--size',
        metavar='size',
        type=int,
        default=0,
        required=False,
        help=
        'search the model of this size (for unreal this specifies size of env model)'
    )

    parser.add_argument('--incr',
                        action='store_true',
                        required=False,
                        default=False,
                        help='use incremental solving')
    parser.add_argument('--tmp',
                        action='store_true',
                        required=False,
                        default=False,
                        help='keep temporary smt2 files')
    parser.add_argument('--dot',
                        metavar='dot',
                        type=str,
                        required=False,
                        help='write the output into a dot graph file')
    parser.add_argument('--log',
                        metavar='log',
                        type=str,
                        required=False,
                        default=None,
                        help='name of the log file')
    parser.add_argument(
        '--unreal',
        action='store_true',
        required=False,
        help='simple check of unrealizability: '
        'invert the spec, system type, (in/out)puts, '
        'and synthesize the model for env '
        '(note that the inverted spec will NOT be strengthened)')
    parser.add_argument('-v', '--verbose', action='count', default=0)

    args = parser.parse_args()

    setup_logging(args.verbose, args.log)
    logging.info(args)

    if args.incr and args.tmp:
        logging.warning(
            "--tmp --incr: incremental queries do not produce smt2 files, "
            "so I won't save any temporal files.")

    with tempfile.NamedTemporaryFile(dir='./') as smt_file:
        smt_files_prefix = smt_file.name

    ltl_to_automaton = (translator_via_ltl3ba.LTLToAtmViaLTL3BA,
                        translator_via_spot.LTLToAtmViaSpot)[args.spot]()
    solver_factory = Z3SolverFactory(smt_files_prefix, Z3_PATH, args.incr,
                                     False, not args.tmp)

    if args.size == 0:
        min_size, max_size = 1, args.bound
    else:
        min_size, max_size = args.size, args.size

    ltl_text, part_text, is_moore = convert_tlsf_or_acacia_to_acacia(
        args.spec, args.moore)

    if args.unreal:
        model = check_unreal(ltl_text, part_text, is_moore, ltl_to_automaton,
                             solver_factory.create(), args.maxK, min_size,
                             max_size)
    else:
        model = check_real(ltl_text, part_text, is_moore, ltl_to_automaton,
                           solver_factory.create(), args.maxK, min_size,
                           max_size)

    if not model:
        logging.info('model NOT FOUND')
    else:
        logging.info('FOUND model for {who} of size {size}'.format(
            who=('sys', 'env')[args.unreal], size=len(model.states)))

    if model:
        dot_model_str = lts_to_dot(model, ARG_MODEL_STATE,
                                   (not is_moore) ^ args.unreal)
        if args.dot:
            with open(args.dot, 'w') as out:
                out.write(dot_model_str)
                logging.info('{model_type} model is written to {file}'.format(
                    model_type=['Mealy', 'Moore'][is_moore], file=out.name))
        else:
            logging.info(dot_model_str)

    solver_factory.down_solvers()

    return UNKNOWN_RC if model is None else (REALIZABLE_RC,
                                             UNREALIZABLE_RC)[args.unreal]
Beispiel #8
0
def main():
    """ :return: 1 if model is found, 0 otherwise """
    parser = argparse.ArgumentParser(
        description='Bounded Synthesizer for CTL*',
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)

    parser.add_argument('spec',
                        metavar='spec',
                        type=str,
                        help='the specification file (in python format)')

    group = parser.add_mutually_exclusive_group()
    group.add_argument(
        '--bound',
        metavar='bound',
        type=int,
        default=128,
        required=False,
        help=
        'upper bound on the size of the model (for unreal this specifies size of env model)'
    )
    group.add_argument(
        '--size',
        metavar='size',
        type=int,
        default=0,
        required=False,
        help=
        'search the model of this size (for unreal this specifies size of env model)'
    )

    group = parser.add_mutually_exclusive_group()
    group.add_argument('--direct',
                       action='store_true',
                       default=True,
                       dest='direct',
                       help='use direct encoding')
    group.add_argument('--aht',
                       action='store_false',
                       default=False,
                       dest='direct',
                       help='encode via AHT')

    parser.add_argument('--incr',
                        action='store_true',
                        required=False,
                        default=False,
                        help='use incremental solving')
    parser.add_argument('--tmp',
                        action='store_true',
                        required=False,
                        default=False,
                        help='keep temporary smt2 files')
    parser.add_argument('--dot',
                        metavar='dot',
                        type=str,
                        required=False,
                        help='write the output into a dot graph file')
    parser.add_argument('--aiger',
                        metavar='aiger',
                        type=str,
                        required=False,
                        help='write the output into an AIGER format')
    parser.add_argument('--log',
                        metavar='log',
                        type=str,
                        required=False,
                        default=None,
                        help='name of the log file')
    parser.add_argument('-v', '--verbose', action='count', default=0)

    args = parser.parse_args()

    setup_logging(args.verbose, args.log)
    logging.info(args)

    if args.incr and args.tmp:
        logging.warning(
            "--tmp --incr: incremental queries do not produce smt2 files, "
            "so I won't save any temporal files.")

    with tempfile.NamedTemporaryFile(dir='./') as smt_file:
        smt_files_prefix = smt_file.name

    ltl_to_atm = translator_via_spot.LTLToAtmViaSpot()
    solver_factory = Z3SolverFactory(smt_files_prefix, Z3_PATH, args.incr,
                                     False, not args.tmp)

    if args.size == 0:
        min_size, max_size = 1, args.bound
    else:
        min_size, max_size = args.size, args.size

    spec = parse_python_spec(args.spec)
    model = check_real(spec, min_size, max_size, ltl_to_atm, solver_factory,
                       args.direct)

    logging.info('{status} model for {who}'.format(
        status=('FOUND', 'NOT FOUND')[model is None], who='sys'))
    if model:
        dot_model_str = lts_to_dot(model, ARG_MODEL_STATE, False)

        if args.dot:
            with open(args.dot, 'w') as out:
                out.write(dot_model_str)
                logging.info(
                    'Moore model is written to {file}'.format(file=out.name))
        else:
            logging.info(dot_model_str)

        if args.aiger:
            with open(args.aiger, 'w') as aiger_out:
                aiger_out.write(lts_to_aiger(model))

    solver_factory.down_solvers()

    return UNKNOWN if model is None else REALIZABLE