3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-23 17:15:31 +00:00

wip - alpha support for polymorphism

An initial update to support polymorphism from SMTLIB3 and the API (so far C, Python).

The WIP SMTLIB3 format is assumed to be supporting the following declaration

```
(declare-type-var A)
```
Whenever A is used in a type signature of a function/constant or bound quantified variable, it is taken to mean that all instantiations of A are included in the signature and assertions.
For example, if the function f is declared with signature A -> A, then there is a version of f for all instances of A.
The semantics of polymorphism appears to follow previous proposals: the instances are effectively different functions.
This may clash with some other notions, such as the type signature forall 'a . 'a -> 'a would be inhabited by a unique function (the identity), while this is not enforced in this version (and hopefully never because it is more busy work).

The C API has the function 'Z3_mk_type_variable' to create a type variable and applying functions modulo polymorphic type signatures is possible.
The kind Z3_TYPE_VAR is added to sort discriminators.

This version is considered as early alpha. It passes a first rudimentary unit test involving quantified axioms, declare-fun, define-fun, and define-fun-rec.
This commit is contained in:
Nikolaj Bjorner 2023-07-12 18:09:02 -07:00
parent d6f2c23627
commit 939bf1c725
16 changed files with 987 additions and 42 deletions

View file

@ -29,6 +29,7 @@ Revision History:
#include "ast/ast_ll_pp.h"
#include "ast/ast_smt_pp.h"
#include "ast/ast_smt2_pp.h"
#include "ast/polymorphism_util.h"
#include "ast/rewriter/th_rewriter.h"
#include "ast/rewriter/var_subst.h"
#include "ast/rewriter/expr_safe_replace.h"
@ -88,6 +89,16 @@ extern "C" {
Z3_CATCH_RETURN(nullptr);
}
Z3_sort Z3_API Z3_mk_type_variable(Z3_context c, Z3_symbol name) {
Z3_TRY;
LOG_Z3_mk_type_variable(c, name);
RESET_ERROR_CODE();
sort* ty = mk_c(c)->m().mk_type_var(to_symbol(name));
mk_c(c)->save_ast_trail(ty);
RETURN_Z3(of_sort(ty));
Z3_CATCH_RETURN(nullptr);
}
bool Z3_API Z3_is_eq_ast(Z3_context c, Z3_ast s1, Z3_ast s2) {
RESET_ERROR_CODE();
return s1 == s2;
@ -180,7 +191,20 @@ extern "C" {
arg_list.push_back(to_expr(args[i]));
}
func_decl* _d = reinterpret_cast<func_decl*>(d);
app* a = mk_c(c)->m().mk_app(_d, num_args, arg_list.data());
ast_manager& m = mk_c(c)->m();
if (_d->is_polymorphic()) {
polymorphism::util u(m);
polymorphism::substitution sub(m);
ptr_buffer<sort> domain;
for (unsigned i = 0; i < num_args; ++i) {
if (!sub.match(_d->get_domain(i), arg_list[i]->get_sort()))
SET_ERROR_CODE(Z3_INVALID_ARG, "failed to match argument of polymorphic function");
domain.push_back(arg_list[i]->get_sort());
}
sort_ref range = sub(_d->get_range());
_d = m.instantiate_polymorphic(_d, num_args, domain.data(), range);
}
app* a = m.mk_app(_d, num_args, arg_list.data());
mk_c(c)->save_ast_trail(a);
check_sorts(c, a);
RETURN_Z3(of_ast(a));
@ -728,6 +752,9 @@ extern "C" {
else if (fid == mk_c(c)->get_char_fid() && k == CHAR_SORT) {
return Z3_CHAR_SORT;
}
else if (fid == poly_family_id) {
return Z3_TYPE_VAR;
}
else {
return Z3_UNKNOWN_SORT;
}

View file

@ -683,6 +683,8 @@ def _to_sort_ref(s, ctx):
return SeqSortRef(s, ctx)
elif k == Z3_CHAR_SORT:
return CharSortRef(s, ctx)
elif k == Z3_TYPE_VAR:
return TypeVarRef(s, ctx)
return SortRef(s, ctx)
@ -708,6 +710,26 @@ def DeclareSort(name, ctx=None):
ctx = _get_ctx(ctx)
return SortRef(Z3_mk_uninterpreted_sort(ctx.ref(), to_symbol(name, ctx)), ctx)
class TypeVarRef(SortRef):
"""Type variable reference"""
def subsort(self, other):
return True
def cast(self, val):
return val
def DeclareTypeVar(name, ctx=None):
"""Create a new type variable named `name`.
If `ctx=None`, then the new sort is declared in the global Z3Py context.
"""
ctx = _get_ctx(ctx)
return TypeVarRef(Z3_mk_type_variable(ctx.ref(), to_symbol(name, ctx)), ctx)
#########################################
#
# Function Declarations

View file

@ -151,6 +151,7 @@ typedef enum
Z3_SEQ_SORT,
Z3_RE_SORT,
Z3_CHAR_SORT,
Z3_TYPE_VAR,
Z3_UNKNOWN_SORT = 1000
} Z3_sort_kind;
@ -1883,6 +1884,17 @@ extern "C" {
*/
Z3_sort Z3_API Z3_mk_uninterpreted_sort(Z3_context c, Z3_symbol s);
/**
\brief Create a type variable.
Functions using type variables can be applied to instantiations that match the signature
of the function. Assertions using type variables correspond to assertions over all possible
instantiations.
def_API('Z3_mk_type_variable', SORT, (_in(CONTEXT), _in(SYMBOL)))
*/
Z3_sort Z3_API Z3_mk_type_variable(Z3_context c, Z3_symbol s);
/**
\brief Create the Boolean type.