Exemplo n.º 1
0
def transform_fg_universe(finite_model, lambdafunc, annctx):
    """
    Applies the given function lambdafunc to all elements of the foreground universe present in finite_model. All 
    vocabulary entries must be tracked by annctx.  
    :param finite_model: dict {string -> dict {tuple of any -> any}}  
    :param lambdafunc: function  
    :param annctx: naturalproofs.AnnotatedContext.AnnotatedContext  
    :return: dict {string -> dict {tuple of any -> any}}  
    """
    vocab_keys = finite_model.keys()
    for vocab_key in vocab_keys:
        vocab_decl = get_decl_from_name(vocab_key, annctx)
        arity = vocab_decl.arity()
        uct_signature = get_uct_signature(vocab_decl, annctx)
        if all(sig not in {fgsort, fgsetsort} for sig in uct_signature):
            # No foreground sort elements anywhere. No transformation required
            continue
        new_vocab_key_dict = dict()
        args = finite_model[vocab_key].keys()
        for arg in args:
            new_arg = tuple(
                _transform_value(arg[i], uct_signature[i], lambdafunc)
                for i in range(arity))
            new_out = _transform_value(finite_model[vocab_key][arg],
                                       uct_signature[-1], lambdafunc)
            new_vocab_key_dict[new_arg] = new_out
        finite_model[vocab_key] = new_vocab_key_dict
    return finite_model
Exemplo n.º 2
0
def collect_fg_universe(finite_model, annctx):
    """
    Returns all elements of the foreground universe present in finite_model. All vocabulary entries must be tracked by 
    annctx.  
    :param finite_model: dict {string -> dict {tuple of any -> any}}  
    :param annctx: naturalproofs.AnnotatedContext.AnnotatedContext  
    :return: set of any  
    """
    fg_elem_set = set()
    vocab_keys = finite_model.keys()
    for vocab_key in vocab_keys:
        vocab_decl = get_decl_from_name(vocab_key, annctx)
        arity = vocab_decl.arity()
        uct_signature = get_uct_signature(vocab_decl, annctx)
        if all(sig not in {fgsort, fgsetsort} for sig in uct_signature):
            # No foreground sort elements anywhere. No collection required
            continue
        args = finite_model[vocab_key].keys()
        for arg in args:
            for i in range(arity):
                fg_elem_set = fg_elem_set | _collect_value(
                    arg[i], uct_signature[i])
                fg_elem_set = fg_elem_set | _collect_value(
                    finite_model[vocab_key][arg], uct_signature[-1])
    return fg_elem_set
Exemplo n.º 3
0
def modelToSolver(model, vocab, sol, annctx):
    for fct in vocab:
        arity = fct.arity()
        if arity == 0:
            # TODO: handle constant symbols
            # constant symbol
            continue
        else:
            fct_name = fct.name()
            uct_signature = get_uct_signature(fct, annctx)
            for input_arg in model[fct_name].keys():
                output_value = model[fct_name][input_arg]
                if isinstance(output_value, set):
                    output_value_converted = recover_value(output_value, uct_signature[-1])
                else:
                    output_value_converted = output_value

                if isinstance(input_arg, tuple):
                    # arg must be unpacked as *arg before constructing the Z3 term
                    sol.add(fct(*input_arg) == output_value_converted)
                else:
                    sol.add(fct(input_arg) == output_value_converted)
Exemplo n.º 4
0
    def __init__(self,
                 smtmodel,
                 terms,
                 vocabulary=None,
                 annctx=default_annctx):
        """
        Finite model creation.  
        Foreground universe of extracted model corresponds to terms with subterm-closure. If vocabulary is not 
        specified, the entire vocabulary tracked in annctx is used.  
        :param smtmodel: z3.ModelRef  
        :param terms: set of z3.ExprRef  
        :param vocabulary: set of z3.ExprRef  
        :param annctx: naturalproofs.AnnotatedContext.AnnotatedContext  

        This function also defines the format of finite models.  
        Given a vocabulary of functions f1, f2, ..fm, of arity a1, a2, ...am, the model is as follows:  
        model :: dict {'fk' : dict_fk}  
        where 'fk' is some representation of the function fk, and  
        dict_fk :: dict {(e1, e2,... ek) : fk(e1, e2, ...ek)}  
        where (e1, e2, ...ek) is a tuple such that e1, e2,.. etc are concrete values in python that are 
        dependent on the domain and range sorts of fk.  
        In particular if the arity k is 0, then dict_fk will be of the following form:  
        dict_fk :: dict {() : fk()}  

        These models are meant to be partial models, and in general it will not be possible to evaluate an arbitrary
        formula on such a model, just those that are quantifier-free with foreground terms in the set of terms used 
        to extract the finite model.  
        """
        model = dict()
        # TODO: VERY IMPORTANT: hack to include those terms that are directly given as integers or integer expressions
        elems = {smtmodel.eval(term, model_completion=True) for term in terms}
        # TODO: the assumption is that uninterpreted functions have arguments only from the foreground sort. Must handle
        #  cases where uninterpreted functions have arguments in other domains, primarily integers.
        # Subterm-close the given terms assuming one-way functions
        # get_foreground_terms already performs subterm closure
        subterm_closure = get_foreground_terms(terms, annctx=annctx)
        elems = elems | {
            smtmodel.eval(term, model_completion=True)
            for term in subterm_closure
        }
        if vocabulary is None:
            vocabulary = get_vocabulary(annctx)
        for func in vocabulary:
            arity = func.arity()
            *input_signature, output_sort = get_uct_signature(func, annctx)
            # Only supporting uninterpreted functions with input arguments all from the foreground sort
            if not all(sig == fgsort for sig in input_signature):
                raise ValueError(
                    'Function with input(s) not from the foreground sort. Unsupported.'
                )
            func_key_repr = model_key_repr(func)
            # Distinguish common cases for faster execution
            if arity == 0:
                model[func_key_repr] = {
                    ():
                    _extract_value(
                        smtmodel.eval(func(), model_completion=True),
                        output_sort)
                }
            elif arity == 1:
                model[func_key_repr] = {
                    (_extract_value(elem, fgsort), ): _extract_value(
                        smtmodel.eval(func(elem), model_completion=True),
                        output_sort)
                    for elem in elems
                }
            else:
                func_dict = dict()
                args = itertools.product(elems, repeat=arity)
                for arg in args:
                    arg_value = tuple(
                        _extract_value(component, fgsort) for component in arg)
                    func_dict[arg_value] = _extract_value(
                        smtmodel.eval(func(*arg), model_completion=True),
                        output_sort)
                model[func_key_repr] = func_dict

        # Object attributes
        self.finitemodel = model
        self.smtmodel = smtmodel
        self.vocabulary = vocabulary
        self.annctx = annctx
        self.offset = 0
        self.fg_universe = collect_fg_universe(self.finitemodel, self.annctx)
        # Logging attributes
        self.extraction_terms = subterm_closure
        # Caching attributes
        self.recompute_offset = True
Exemplo n.º 5
0
def gen_lfp_model(size, annctx, invalid_formula=None):
    """
    Generate a finite model of the theory given by annctx of specified size where the valuation 
    of recursive definitions respects LFP semantics. Returns None if model with specified conditions does not exist.  
    Optional argument invalid_formula is a bound formula that must be falsified by the returned model.  
    :param size: int  
    :param annctx: naturalproofs.AnnotatedContext.AnnotatedContext  
    :param invalid_formula: pair (tuple of z3.ExprRef, z3.BoolRef)  
    :return: pair (z3.ModelRef, set)  
    """
    # Establish underlying universe
    universe = {z3.IntVal(i) for i in range(size)}
    constraints = []

    vocabulary = get_vocabulary(annctx=annctx)
    # Closure for vocabluary that is over the foreground sort
    # If signature guidelines follow naturalproofs.uct then range can only be fgsort if the domain args are all fgsort
    foreground_vocabluary = {
        funcdecl
        for funcdecl in vocabulary
        if all(srt == fgsort
               for srt in get_uct_signature(funcdecl, annctx=annctx))
    }
    for funcdecl in foreground_vocabluary:
        argslist = itertools.product(universe, repeat=funcdecl.arity())
        constraints.append(
            And([
                Or([funcdecl(*args) == elem for elem in universe])
                for args in argslist
            ]))

    # Recursive definitions and ranks
    recdefs = get_recursive_definition(None, alldefs=True, annctx=annctx)
    recdef_unfoldings = make_recdef_unfoldings(recdefs)
    untagged_unfoldings = set(recdef_unfoldings.values())
    rank_formulas = {
        recdef.name(): rank_defs_dict.get(recdef.name(), None)
        for recdef, _, _ in recdefs
    }
    if all(value is None for value in rank_formulas.values()):
        raise Exception(
            'Rank definitions must be given at least for the underlying datastructure definition. '
            'This should be one among: {}'.format(', '.join(
                key for key, value in rank_formulas.items() if value is None)))
    # Axioms
    axioms = get_all_axioms(annctx=annctx)
    structural_constraints = untagged_unfoldings | set(
        rankdef
        for rankdef in rank_formulas.values() if rankdef is not None) | axioms
    constraints.extend(instantiate(structural_constraints, universe))

    # Bound formula to negate
    if invalid_formula is not None:
        formal_vars, body = invalid_formula
        constraints.append(
            Or([
                Not(apply_bound_formula(invalid_formula, args))
                for args in itertools.product(universe,
                                              repeat=len(formal_vars))
            ]))

    z3.set_param('smt.random_seed', 0)
    z3.set_param('sat.random_seed', 0)
    sol = z3.Solver()
    sol.add(constraints)
    if sol.check() == z3.sat:
        lfp_model = sol.model()
        # Project model onto the numbers corresponding to the foreground universe
        finite_lfp_model = FiniteModel(lfp_model, universe, annctx=annctx)
        return finite_lfp_model, universe
    else:
        return None, None