UNPKG

dtk-z3-solver-deno-v2

Version:

This directory contains JavaScript code to automatically derive TypeScript bindings for the C API, which are published on npm as [z3-solver](https://www.npmjs.com/package/z3-solver).

1,220 lines (1,219 loc) 96.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createApi = createApi; // TODO(ritave): Add typing for Context Options // https://github.com/Z3Prover/z3/pull/6048#discussion_r883391669 // TODO(ritave): Add an error handler // TODO(ritave): Add support for building faster floats without support for Safari // TODO(ritave): Use Z3_DECLARE_CLOSURE macro to generate code https://github.com/Z3Prover/z3/pull/6048#discussion_r884155462 // TODO(ritave): Add pretty printing // TODO(ritave): Make Z3 multi-threaded // TODO(ritave): If a test times out, jest kills it, and the global state of Z3 is left in an unexpected state. // This occurs specifically during longer check(). Afterwards, all next tests will fail to run // thinking the previous call was not finished. Find a way to stop execution and clean up the global state const async_mutex_1 = require("async-mutex"); const low_level_1 = require("../low-level"); const types_1 = require("./types"); const utils_1 = require("./utils"); const FALLBACK_PRECISION = 17; const asyncMutex = new async_mutex_1.Mutex(); function isCoercibleRational(obj) { // prettier-ignore const r = ((obj !== null && (typeof obj === 'object' || typeof obj === 'function')) && (obj.numerator !== null && (typeof obj.numerator === 'number' || typeof obj.numerator === 'bigint')) && (obj.denominator !== null && (typeof obj.denominator === 'number' || typeof obj.denominator === 'bigint'))); r && (0, utils_1.assert)((typeof obj.numerator !== 'number' || Number.isSafeInteger(obj.numerator)) && (typeof obj.denominator !== 'number' || Number.isSafeInteger(obj.denominator)), 'Fraction numerator and denominator must be integers'); return r; } function createApi(Z3) { // TODO(ritave): Create a custom linting rule that checks if the provided callbacks to cleanup // Don't capture `this` const cleanup = new FinalizationRegistry(callback => callback()); function enableTrace(tag) { Z3.enable_trace(tag); } function disableTrace(tag) { Z3.disable_trace(tag); } function getVersion() { return Z3.get_version(); } function getVersionString() { const { major, minor, build_number } = Z3.get_version(); return `${major}.${minor}.${build_number}`; } function getFullVersion() { return Z3.get_full_version(); } function openLog(filename) { return Z3.open_log(filename); } function appendLog(s) { Z3.append_log(s); } function setParam(key, value) { if (typeof key === 'string') { Z3.global_param_set(key, value.toString()); } else { (0, utils_1.assert)(value === undefined, "Can't provide a Record and second parameter to set_param at the same time"); Object.entries(key).forEach(([key, value]) => setParam(key, value)); } } function resetParams() { Z3.global_param_reset_all(); } function getParam(name) { return Z3.global_param_get(name); } function createContext(name, options) { const cfg = Z3.mk_config(); if (options != null) { Object.entries(options).forEach(([key, value]) => check(Z3.set_param_value(cfg, key, value.toString()))); } const contextPtr = Z3.mk_context_rc(cfg); Z3.set_ast_print_mode(contextPtr, low_level_1.Z3_ast_print_mode.Z3_PRINT_SMTLIB2_COMPLIANT); Z3.del_config(cfg); function _assertContext(...ctxs) { ctxs.forEach(other => (0, utils_1.assert)('ctx' in other ? ctx === other.ctx : ctx === other, 'Context mismatch')); } function _assertPtr(ptr) { if (ptr == null) throw new TypeError('Expected non-null pointer'); } // call this after every nontrivial call to the underlying API function throwIfError() { if (Z3.get_error_code(contextPtr) !== low_level_1.Z3_error_code.Z3_OK) { throw new Error(Z3.get_error_msg(ctx.ptr, Z3.get_error_code(ctx.ptr))); } } function check(val) { throwIfError(); return val; } ///////////// // Private // ///////////// function _toSymbol(s) { if (typeof s === 'number') { return check(Z3.mk_int_symbol(contextPtr, s)); } else { return check(Z3.mk_string_symbol(contextPtr, s)); } } function _fromSymbol(sym) { const kind = check(Z3.get_symbol_kind(contextPtr, sym)); switch (kind) { case low_level_1.Z3_symbol_kind.Z3_INT_SYMBOL: return Z3.get_symbol_int(contextPtr, sym); case low_level_1.Z3_symbol_kind.Z3_STRING_SYMBOL: return Z3.get_symbol_string(contextPtr, sym); default: (0, utils_1.assertExhaustive)(kind); } } function _toParams(key, value) { const params = Z3.mk_params(contextPtr); Z3.params_inc_ref(contextPtr, params); // If value is a boolean if (typeof value === 'boolean') { Z3.params_set_bool(contextPtr, params, _toSymbol(key), value); } else if (typeof value === 'number') { // If value is a uint if (Number.isInteger(value)) { check(Z3.params_set_uint(contextPtr, params, _toSymbol(key), value)); } else { // If value is a double check(Z3.params_set_double(contextPtr, params, _toSymbol(key), value)); } } else if (typeof value === 'string') { check(Z3.params_set_symbol(contextPtr, params, _toSymbol(key), _toSymbol(value))); } return params; } function _toAst(ast) { switch (check(Z3.get_ast_kind(contextPtr, ast))) { case low_level_1.Z3_ast_kind.Z3_SORT_AST: return _toSort(ast); case low_level_1.Z3_ast_kind.Z3_FUNC_DECL_AST: return new FuncDeclImpl(ast); default: return _toExpr(ast); } } function _toSort(ast) { switch (check(Z3.get_sort_kind(contextPtr, ast))) { case low_level_1.Z3_sort_kind.Z3_BOOL_SORT: return new BoolSortImpl(ast); case low_level_1.Z3_sort_kind.Z3_INT_SORT: case low_level_1.Z3_sort_kind.Z3_REAL_SORT: return new ArithSortImpl(ast); case low_level_1.Z3_sort_kind.Z3_BV_SORT: return new BitVecSortImpl(ast); case low_level_1.Z3_sort_kind.Z3_ARRAY_SORT: return new ArraySortImpl(ast); default: return new SortImpl(ast); } } function _toExpr(ast) { const kind = check(Z3.get_ast_kind(contextPtr, ast)); if (kind === low_level_1.Z3_ast_kind.Z3_QUANTIFIER_AST) { if (Z3.is_lambda(contextPtr, ast)) { return new LambdaImpl(ast); } return new NonLambdaQuantifierImpl(ast); } const sortKind = check(Z3.get_sort_kind(contextPtr, Z3.get_sort(contextPtr, ast))); switch (sortKind) { case low_level_1.Z3_sort_kind.Z3_BOOL_SORT: return new BoolImpl(ast); case low_level_1.Z3_sort_kind.Z3_INT_SORT: if (kind === low_level_1.Z3_ast_kind.Z3_NUMERAL_AST) { return new IntNumImpl(ast); } return new ArithImpl(ast); case low_level_1.Z3_sort_kind.Z3_REAL_SORT: if (kind === low_level_1.Z3_ast_kind.Z3_NUMERAL_AST) { return new RatNumImpl(ast); } return new ArithImpl(ast); case low_level_1.Z3_sort_kind.Z3_BV_SORT: if (kind === low_level_1.Z3_ast_kind.Z3_NUMERAL_AST) { return new BitVecNumImpl(ast); } return new BitVecImpl(ast); case low_level_1.Z3_sort_kind.Z3_ARRAY_SORT: return new ArrayImpl(ast); default: return new ExprImpl(ast); } } function _flattenArgs(args) { const result = []; for (const arg of args) { if (isAstVector(arg)) { result.push(...arg.values()); } else { result.push(arg); } } return result; } function _toProbe(p) { if (isProbe(p)) { return p; } return new ProbeImpl(p); } function _probeNary(f, args) { (0, utils_1.assert)(args.length > 0, 'At least one argument expected'); let r = _toProbe(args[0]); for (let i = 1; i < args.length; i++) { r = new ProbeImpl(check(f(contextPtr, r.ptr, _toProbe(args[i]).ptr))); } return r; } /////////////// // Functions // /////////////// function interrupt() { check(Z3.interrupt(contextPtr)); } function isModel(obj) { const r = obj instanceof ModelImpl; r && _assertContext(obj); return r; } function isAst(obj) { const r = obj instanceof AstImpl; r && _assertContext(obj); return r; } function isSort(obj) { const r = obj instanceof SortImpl; r && _assertContext(obj); return r; } function isFuncDecl(obj) { const r = obj instanceof FuncDeclImpl; r && _assertContext(obj); return r; } function isFuncInterp(obj) { const r = obj instanceof FuncInterpImpl; r && _assertContext(obj); return r; } function isApp(obj) { if (!isExpr(obj)) { return false; } const kind = check(Z3.get_ast_kind(contextPtr, obj.ast)); return kind === low_level_1.Z3_ast_kind.Z3_NUMERAL_AST || kind === low_level_1.Z3_ast_kind.Z3_APP_AST; } function isConst(obj) { return isExpr(obj) && isApp(obj) && obj.numArgs() === 0; } function isExpr(obj) { const r = obj instanceof ExprImpl; r && _assertContext(obj); return r; } function isVar(obj) { return isExpr(obj) && check(Z3.get_ast_kind(contextPtr, obj.ast)) === low_level_1.Z3_ast_kind.Z3_VAR_AST; } function isAppOf(obj, kind) { return isExpr(obj) && isApp(obj) && obj.decl().kind() === kind; } function isBool(obj) { const r = obj instanceof ExprImpl && obj.sort.kind() === low_level_1.Z3_sort_kind.Z3_BOOL_SORT; r && _assertContext(obj); return r; } function isTrue(obj) { return isAppOf(obj, low_level_1.Z3_decl_kind.Z3_OP_TRUE); } function isFalse(obj) { return isAppOf(obj, low_level_1.Z3_decl_kind.Z3_OP_FALSE); } function isAnd(obj) { return isAppOf(obj, low_level_1.Z3_decl_kind.Z3_OP_AND); } function isOr(obj) { return isAppOf(obj, low_level_1.Z3_decl_kind.Z3_OP_OR); } function isImplies(obj) { return isAppOf(obj, low_level_1.Z3_decl_kind.Z3_OP_IMPLIES); } function isNot(obj) { return isAppOf(obj, low_level_1.Z3_decl_kind.Z3_OP_NOT); } function isEq(obj) { return isAppOf(obj, low_level_1.Z3_decl_kind.Z3_OP_EQ); } function isDistinct(obj) { return isAppOf(obj, low_level_1.Z3_decl_kind.Z3_OP_DISTINCT); } function isQuantifier(obj) { const r = obj instanceof QuantifierImpl; r && _assertContext(obj); return r; } function isArith(obj) { const r = obj instanceof ArithImpl; r && _assertContext(obj); return r; } function isArithSort(obj) { const r = obj instanceof ArithSortImpl; r && _assertContext(obj); return r; } function isInt(obj) { return isArith(obj) && isIntSort(obj.sort); } function isIntVal(obj) { const r = obj instanceof IntNumImpl; r && _assertContext(obj); return r; } function isIntSort(obj) { return isSort(obj) && obj.kind() === low_level_1.Z3_sort_kind.Z3_INT_SORT; } function isReal(obj) { return isArith(obj) && isRealSort(obj.sort); } function isRealVal(obj) { const r = obj instanceof RatNumImpl; r && _assertContext(obj); return r; } function isRealSort(obj) { return isSort(obj) && obj.kind() === low_level_1.Z3_sort_kind.Z3_REAL_SORT; } function isBitVecSort(obj) { const r = obj instanceof BitVecSortImpl; r && _assertContext(obj); return r; } function isBitVec(obj) { const r = obj instanceof BitVecImpl; r && _assertContext(obj); return r; } function isBitVecVal(obj) { const r = obj instanceof BitVecNumImpl; r && _assertContext(obj); return r; } function isArraySort(obj) { const r = obj instanceof ArraySortImpl; r && _assertContext(obj); return r; } function isArray(obj) { const r = obj instanceof ArrayImpl; r && _assertContext(obj); return r; } function isConstArray(obj) { return isAppOf(obj, low_level_1.Z3_decl_kind.Z3_OP_CONST_ARRAY); } function isProbe(obj) { const r = obj instanceof ProbeImpl; r && _assertContext(obj); return r; } function isTactic(obj) { const r = obj instanceof TacticImpl; r && _assertContext(obj); return r; } //extended function isGoal(obj) { const r = obj instanceof GoalImpl; r && _assertContext(obj); return r; } //extended function isApplyResult(obj) { const r = obj instanceof ApplyResultImpl; r && _assertContext(obj); return r; } function isAstVector(obj) { const r = obj instanceof AstVectorImpl; r && _assertContext(obj); return r; } function eqIdentity(a, b) { return a.eqIdentity(b); } function getVarIndex(obj) { (0, utils_1.assert)(isVar(obj), 'Z3 bound variable expected'); return Z3.get_index_value(contextPtr, obj.ast); } function from(value) { if (typeof value === 'boolean') { return Bool.val(value); } else if (typeof value === 'number') { if (!Number.isFinite(value)) { throw new Error(`cannot represent infinity/NaN (got ${value})`); } if (Math.floor(value) === value) { return Int.val(value); } return Real.val(value); } else if (isCoercibleRational(value)) { return Real.val(value); } else if (typeof value === 'bigint') { return Int.val(value); } else if (isExpr(value)) { return value; } (0, utils_1.assert)(false); } async function solve(...assertions) { const solver = new ctx.Solver(); solver.add(...assertions); const result = await solver.check(); if (result === 'sat') { return solver.model(); } return result; } function solveSync(...assertions) { const solver = new ctx.Solver(); solver.add(...assertions); const result = solver.checkSync(); if (result === 'sat') { return solver.model(); } return result; } /////////////////////////////// // expression simplification // /////////////////////////////// async function simplify(e) { const result = await Z3.simplify(contextPtr, e.ast); return _toExpr(check(result)); } function simplifySync(e) { const result = Z3.simplify(contextPtr, e.ast); return _toExpr(check(result)); } ///////////// // Objects // ///////////// const Sort = { declare: (name) => new SortImpl(Z3.mk_uninterpreted_sort(contextPtr, _toSymbol(name))), // extension enumSort: (name, constantNames) => new EnumSortImpl(name, constantNames), }; const Function = { declare: (name, ...signature) => { const arity = signature.length - 1; const rng = signature[arity]; _assertContext(rng); const dom = []; for (let i = 0; i < arity; i++) { _assertContext(signature[i]); dom.push(signature[i].ptr); } return new FuncDeclImpl(Z3.mk_func_decl(contextPtr, _toSymbol(name), dom, rng.ptr)); }, fresh: (...signature) => { const arity = signature.length - 1; const rng = signature[arity]; _assertContext(rng); const dom = []; for (let i = 0; i < arity; i++) { _assertContext(signature[i]); dom.push(signature[i].ptr); } return new FuncDeclImpl(Z3.mk_fresh_func_decl(contextPtr, 'f', dom, rng.ptr)); }, }; const RecFunc = { declare: (name, ...signature) => { const arity = signature.length - 1; const rng = signature[arity]; _assertContext(rng); const dom = []; for (let i = 0; i < arity; i++) { _assertContext(signature[i]); dom.push(signature[i].ptr); } return new FuncDeclImpl(Z3.mk_rec_func_decl(contextPtr, _toSymbol(name), dom, rng.ptr)); }, addDefinition: (f, args, body) => { _assertContext(f, ...args, body); check(Z3.add_rec_def(contextPtr, f.ptr, args.map(arg => arg.ast), body.ast)); }, }; const Bool = { sort: () => new BoolSortImpl(Z3.mk_bool_sort(contextPtr)), const: (name) => new BoolImpl(Z3.mk_const(contextPtr, _toSymbol(name), Bool.sort().ptr)), consts: (names) => { if (typeof names === 'string') { names = names.split(' '); } return names.map(name => Bool.const(name)); }, vector: (prefix, count) => { const result = []; for (let i = 0; i < count; i++) { result.push(Bool.const(`${prefix}__${i}`)); } return result; }, fresh: (prefix = 'b') => new BoolImpl(Z3.mk_fresh_const(contextPtr, prefix, Bool.sort().ptr)), val: (value) => { if (value) { return new BoolImpl(Z3.mk_true(contextPtr)); } return new BoolImpl(Z3.mk_false(contextPtr)); }, }; const Int = { sort: () => new ArithSortImpl(Z3.mk_int_sort(contextPtr)), const: (name) => new ArithImpl(Z3.mk_const(contextPtr, _toSymbol(name), Int.sort().ptr)), consts: (names) => { if (typeof names === 'string') { names = names.split(' '); } return names.map(name => Int.const(name)); }, vector: (prefix, count) => { const result = []; for (let i = 0; i < count; i++) { result.push(Int.const(`${prefix}__${i}`)); } return result; }, fresh: (prefix = 'x') => new ArithImpl(Z3.mk_fresh_const(contextPtr, prefix, Int.sort().ptr)), val: (value) => { (0, utils_1.assert)(typeof value === 'bigint' || typeof value === 'string' || Number.isSafeInteger(value)); return new IntNumImpl(check(Z3.mk_numeral(contextPtr, value.toString(), Int.sort().ptr))); }, }; const Real = { sort: () => new ArithSortImpl(Z3.mk_real_sort(contextPtr)), const: (name) => new ArithImpl(check(Z3.mk_const(contextPtr, _toSymbol(name), Real.sort().ptr))), consts: (names) => { if (typeof names === 'string') { names = names.split(' '); } return names.map(name => Real.const(name)); }, vector: (prefix, count) => { const result = []; for (let i = 0; i < count; i++) { result.push(Real.const(`${prefix}__${i}`)); } return result; }, fresh: (prefix = 'b') => new ArithImpl(Z3.mk_fresh_const(contextPtr, prefix, Real.sort().ptr)), val: (value) => { if (isCoercibleRational(value)) { value = `${value.numerator}/${value.denominator}`; } return new RatNumImpl(Z3.mk_numeral(contextPtr, value.toString(), Real.sort().ptr)); }, }; const BitVec = { sort(bits) { (0, utils_1.assert)(Number.isSafeInteger(bits), 'number of bits must be an integer'); return new BitVecSortImpl(Z3.mk_bv_sort(contextPtr, bits)); }, const(name, bits) { return new BitVecImpl(check(Z3.mk_const(contextPtr, _toSymbol(name), isBitVecSort(bits) ? bits.ptr : BitVec.sort(bits).ptr))); }, consts(names, bits) { if (typeof names === 'string') { names = names.split(' '); } return names.map(name => BitVec.const(name, bits)); }, val(value, bits) { if (value === true) { return BitVec.val(1, bits); } else if (value === false) { return BitVec.val(0, bits); } return new BitVecNumImpl(check(Z3.mk_numeral(contextPtr, value.toString(), isBitVecSort(bits) ? bits.ptr : BitVec.sort(bits).ptr))); }, }; const Array = { sort(...sig) { const arity = sig.length - 1; const r = sig[arity]; const d = sig[0]; if (arity === 1) { return new ArraySortImpl(Z3.mk_array_sort(contextPtr, d.ptr, r.ptr)); } const dom = sig.slice(0, arity); return new ArraySortImpl(Z3.mk_array_sort_n(contextPtr, dom.map(s => s.ptr), r.ptr)); }, const(name, ...sig) { return new ArrayImpl(check(Z3.mk_const(contextPtr, _toSymbol(name), Array.sort(...sig).ptr))); }, consts(names, ...sig) { if (typeof names === 'string') { names = names.split(' '); } return names.map(name => Array.const(name, ...sig)); }, K(domain, value) { return new ArrayImpl(check(Z3.mk_const_array(contextPtr, domain.ptr, value.ptr))); }, }; const Set = { // reference: https://z3prover.github.io/api/html/namespacez3py.html#a545f894afeb24caa1b88b7f2a324ee7e sort(sort) { return Array.sort(sort, Bool.sort()); }, const(name, sort) { return new SetImpl(check(Z3.mk_const(contextPtr, _toSymbol(name), Array.sort(sort, Bool.sort()).ptr))); }, consts(names, sort) { if (typeof names === 'string') { names = names.split(' '); } return names.map(name => Set.const(name, sort)); }, empty(sort) { return EmptySet(sort); }, val(values, sort) { var result = EmptySet(sort); for (const value of values) { result = SetAdd(result, value); } return result; } }; function If(condition, onTrue, onFalse) { if (isProbe(condition) && isTactic(onTrue) && isTactic(onFalse)) { return Cond(condition, onTrue, onFalse); } (0, utils_1.assert)(!isProbe(condition) && !isTactic(onTrue) && !isTactic(onFalse), 'Mixed expressions and goals'); if (typeof condition === 'boolean') { condition = Bool.val(condition); } onTrue = from(onTrue); onFalse = from(onFalse); return _toExpr(check(Z3.mk_ite(contextPtr, condition.ptr, onTrue.ast, onFalse.ast))); } function Distinct(...exprs) { (0, utils_1.assert)(exprs.length > 0, "Can't make Distinct ouf of nothing"); return new BoolImpl(check(Z3.mk_distinct(contextPtr, exprs.map(expr => { expr = from(expr); _assertContext(expr); return expr.ast; })))); } function Const(name, sort) { _assertContext(sort); return _toExpr(check(Z3.mk_const(contextPtr, _toSymbol(name), sort.ptr))); } function Consts(names, sort) { _assertContext(sort); if (typeof names === 'string') { names = names.split(' '); } return names.map(name => Const(name, sort)); } function FreshConst(sort, prefix = 'c') { _assertContext(sort); return _toExpr(Z3.mk_fresh_const(sort.ctx.ptr, prefix, sort.ptr)); } function Var(idx, sort) { _assertContext(sort); return _toExpr(Z3.mk_bound(sort.ctx.ptr, idx, sort.ptr)); } function Implies(a, b) { a = from(a); b = from(b); _assertContext(a, b); return new BoolImpl(check(Z3.mk_implies(contextPtr, a.ptr, b.ptr))); } function Iff(a, b) { a = from(a); b = from(b); _assertContext(a, b); return new BoolImpl(check(Z3.mk_iff(contextPtr, a.ptr, b.ptr))); } function Eq(a, b) { a = from(a); b = from(b); _assertContext(a, b); return a.eq(b); } function Xor(a, b) { a = from(a); b = from(b); _assertContext(a, b); return new BoolImpl(check(Z3.mk_xor(contextPtr, a.ptr, b.ptr))); } function Not(a) { if (typeof a === 'boolean') { a = from(a); } _assertContext(a); if (isProbe(a)) { return new ProbeImpl(check(Z3.probe_not(contextPtr, a.ptr))); } return new BoolImpl(check(Z3.mk_not(contextPtr, a.ptr))); } function And(...args) { if (args.length == 1 && args[0] instanceof ctx.AstVector) { args = [...args[0].values()]; (0, utils_1.assert)((0, utils_1.allSatisfy)(args, isBool) ?? true, 'AstVector containing not bools'); } const allProbes = (0, utils_1.allSatisfy)(args, isProbe) ?? false; if (allProbes) { return _probeNary(Z3.probe_and, args); } else { const castArgs = args.map(from); _assertContext(...castArgs); return new BoolImpl(check(Z3.mk_and(contextPtr, castArgs.map(arg => arg.ptr)))); } } function Or(...args) { if (args.length == 1 && args[0] instanceof ctx.AstVector) { args = [...args[0].values()]; (0, utils_1.assert)((0, utils_1.allSatisfy)(args, isBool) ?? true, 'AstVector containing not bools'); } const allProbes = (0, utils_1.allSatisfy)(args, isProbe) ?? false; if (allProbes) { return _probeNary(Z3.probe_or, args); } else { const castArgs = args.map(from); _assertContext(...castArgs); return new BoolImpl(check(Z3.mk_or(contextPtr, castArgs.map(arg => arg.ptr)))); } } function PbEq(args, coeffs, k) { _assertContext(...args); if (args.length !== coeffs.length) { throw new Error('Number of arguments and coefficients must match'); } return new BoolImpl(check(Z3.mk_pbeq(contextPtr, args.map(arg => arg.ast), coeffs, k))); } function PbGe(args, coeffs, k) { _assertContext(...args); if (args.length !== coeffs.length) { throw new Error('Number of arguments and coefficients must match'); } return new BoolImpl(check(Z3.mk_pbge(contextPtr, args.map(arg => arg.ast), coeffs, k))); } function PbLe(args, coeffs, k) { _assertContext(...args); if (args.length !== coeffs.length) { throw new Error('Number of arguments and coefficients must match'); } return new BoolImpl(check(Z3.mk_pble(contextPtr, args.map(arg => arg.ast), coeffs, k))); } function ForAll(quantifiers, body, weight = 1) { // Verify all quantifiers are constants if (!(0, utils_1.allSatisfy)(quantifiers, isConst)) { throw new Error('Quantifier variables must be constants'); } return new NonLambdaQuantifierImpl(check(Z3.mk_quantifier_const_ex(contextPtr, true, weight, _toSymbol(''), _toSymbol(''), quantifiers.map(q => q.ptr), // The earlier check verifies these are all apps [], [], body.ptr))); } function Exists(quantifiers, body, weight = 1) { // Verify all quantifiers are constants if (!(0, utils_1.allSatisfy)(quantifiers, isConst)) { throw new Error('Quantifier variables must be constants'); } return new NonLambdaQuantifierImpl(check(Z3.mk_quantifier_const_ex(contextPtr, false, weight, _toSymbol(''), _toSymbol(''), quantifiers.map(q => q.ptr), // The earlier check verifies these are all apps [], [], body.ptr))); } function Lambda(quantifiers, expr) { // TODO(walden): For some reason LambdaImpl<DomainSort, RangeSort> leads to type issues // and Typescript won't build. I'm not sure why since the types seem to all match // up. For now, we just use any for the domain sort // Verify all quantifiers are constants if (!(0, utils_1.allSatisfy)(quantifiers, isConst)) { throw new Error('Quantifier variables must be constants'); } return new LambdaImpl(check(Z3.mk_lambda_const(contextPtr, quantifiers.map(q => q.ptr), expr.ptr))); } function ToReal(expr) { expr = from(expr); _assertContext(expr); (0, utils_1.assert)(isInt(expr), 'Int expression expected'); return new ArithImpl(check(Z3.mk_int2real(contextPtr, expr.ast))); } function ToInt(expr) { if (!isExpr(expr)) { expr = Real.val(expr); } _assertContext(expr); (0, utils_1.assert)(isReal(expr), 'Real expression expected'); return new ArithImpl(check(Z3.mk_real2int(contextPtr, expr.ast))); } function IsInt(expr) { if (!isExpr(expr)) { expr = Real.val(expr); } _assertContext(expr); (0, utils_1.assert)(isReal(expr), 'Real expression expected'); return new BoolImpl(check(Z3.mk_is_int(contextPtr, expr.ast))); } function Sqrt(a) { if (!isExpr(a)) { a = Real.val(a); } return a.pow('1/2'); } function Cbrt(a) { if (!isExpr(a)) { a = Real.val(a); } return a.pow('1/3'); } function BV2Int(a, isSigned) { _assertContext(a); return new ArithImpl(check(Z3.mk_bv2int(contextPtr, a.ast, isSigned))); } function Int2BV(a, bits) { if (isArith(a)) { (0, utils_1.assert)(isInt(a), 'parameter must be an integer'); } else { (0, utils_1.assert)(typeof a !== 'number' || Number.isSafeInteger(a), 'parameter must not have decimal places'); a = Int.val(a); } return new BitVecImpl(check(Z3.mk_int2bv(contextPtr, bits, a.ast))); } function Concat(...bitvecs) { _assertContext(...bitvecs); return bitvecs.reduce((prev, curr) => new BitVecImpl(check(Z3.mk_concat(contextPtr, prev.ast, curr.ast)))); } function Cond(probe, onTrue, onFalse) { _assertContext(probe, onTrue, onFalse); return new TacticImpl(check(Z3.tactic_cond(contextPtr, probe.ptr, onTrue.ptr, onFalse.ptr))); } function LT(a, b) { return new BoolImpl(check(Z3.mk_lt(contextPtr, a.ast, a.sort.cast(b).ast))); } function GT(a, b) { return new BoolImpl(check(Z3.mk_gt(contextPtr, a.ast, a.sort.cast(b).ast))); } function LE(a, b) { return new BoolImpl(check(Z3.mk_le(contextPtr, a.ast, a.sort.cast(b).ast))); } function GE(a, b) { return new BoolImpl(check(Z3.mk_ge(contextPtr, a.ast, a.sort.cast(b).ast))); } function ULT(a, b) { return new BoolImpl(check(Z3.mk_bvult(contextPtr, a.ast, a.sort.cast(b).ast))); } function UGT(a, b) { return new BoolImpl(check(Z3.mk_bvugt(contextPtr, a.ast, a.sort.cast(b).ast))); } function ULE(a, b) { return new BoolImpl(check(Z3.mk_bvule(contextPtr, a.ast, a.sort.cast(b).ast))); } function UGE(a, b) { return new BoolImpl(check(Z3.mk_bvuge(contextPtr, a.ast, a.sort.cast(b).ast))); } function SLT(a, b) { return new BoolImpl(check(Z3.mk_bvslt(contextPtr, a.ast, a.sort.cast(b).ast))); } function SGT(a, b) { return new BoolImpl(check(Z3.mk_bvsgt(contextPtr, a.ast, a.sort.cast(b).ast))); } function SLE(a, b) { return new BoolImpl(check(Z3.mk_bvsle(contextPtr, a.ast, a.sort.cast(b).ast))); } function SGE(a, b) { return new BoolImpl(check(Z3.mk_bvsge(contextPtr, a.ast, a.sort.cast(b).ast))); } function Extract(hi, lo, val) { return new BitVecImpl(check(Z3.mk_extract(contextPtr, hi, lo, val.ast))); } function Select(array, ...indices) { const args = indices.map((arg, i) => array.domain_n(i).cast(arg)); if (args.length === 1) { return _toExpr(check(Z3.mk_select(contextPtr, array.ast, args[0].ast))); } const _args = args.map(arg => arg.ast); return _toExpr(check(Z3.mk_select_n(contextPtr, array.ast, _args))); } function Store(array, ...indicesAndValue) { const args = indicesAndValue.map((arg, i) => { if (i === indicesAndValue.length - 1) { return array.range().cast(arg); } return array.domain_n(i).cast(arg); }); if (args.length <= 1) { throw new Error('Array store requires both index and value arguments'); } if (args.length === 2) { return _toExpr(check(Z3.mk_store(contextPtr, array.ast, args[0].ast, args[1].ast))); } const _idxs = args.slice(0, args.length - 1).map(arg => arg.ast); return _toExpr(check(Z3.mk_store_n(contextPtr, array.ast, _idxs, args[args.length - 1].ast))); } function SetUnion(...args) { return new SetImpl(check(Z3.mk_set_union(contextPtr, args.map(arg => arg.ast)))); } function SetIntersect(...args) { return new SetImpl(check(Z3.mk_set_intersect(contextPtr, args.map(arg => arg.ast)))); } function SetDifference(a, b) { return new SetImpl(check(Z3.mk_set_difference(contextPtr, a.ast, b.ast))); } function SetHasSize(set, size) { const a = typeof size === 'object' ? Int.sort().cast(size) : Int.sort().cast(size); return new BoolImpl(check(Z3.mk_set_has_size(contextPtr, set.ast, a.ast))); } function SetAdd(set, elem) { const arg = set.elemSort().cast(elem); return new SetImpl(check(Z3.mk_set_add(contextPtr, set.ast, arg.ast))); } function SetDel(set, elem) { const arg = set.elemSort().cast(elem); return new SetImpl(check(Z3.mk_set_del(contextPtr, set.ast, arg.ast))); } function SetComplement(set) { return new SetImpl(check(Z3.mk_set_complement(contextPtr, set.ast))); } function EmptySet(sort) { return new SetImpl(check(Z3.mk_empty_set(contextPtr, sort.ptr))); } function FullSet(sort) { return new SetImpl(check(Z3.mk_full_set(contextPtr, sort.ptr))); } function isMember(elem, set) { const arg = set.elemSort().cast(elem); return new BoolImpl(check(Z3.mk_set_member(contextPtr, arg.ast, set.ast))); } function isSubset(a, b) { return new BoolImpl(check(Z3.mk_set_subset(contextPtr, a.ast, b.ast))); } class AstImpl { constructor(ptr) { this.ptr = ptr; this.ctx = ctx; const myAst = this.ast; Z3.inc_ref(contextPtr, myAst); cleanup.register(this, () => Z3.dec_ref(contextPtr, myAst), this); } get ast() { return this.ptr; } id() { return Z3.get_ast_id(contextPtr, this.ast); } eqIdentity(other) { _assertContext(other); return check(Z3.is_eq_ast(contextPtr, this.ast, other.ast)); } neqIdentity(other) { _assertContext(other); return !this.eqIdentity(other); } sexpr() { return Z3.ast_to_string(contextPtr, this.ast); } hash() { return Z3.get_ast_hash(contextPtr, this.ast); } toString() { return this.sexpr(); } } class SolverImpl { get ptr() { _assertPtr(this._ptr); return this._ptr; } constructor(ptr = Z3.mk_solver(contextPtr)) { this.ctx = ctx; let myPtr; if (typeof ptr === 'string') { myPtr = check(Z3.mk_solver_for_logic(contextPtr, _toSymbol(ptr))); } else { myPtr = ptr; } this._ptr = myPtr; Z3.solver_inc_ref(contextPtr, myPtr); cleanup.register(this, () => Z3.solver_dec_ref(contextPtr, myPtr), this); } set(key, value) { Z3.solver_set_params(contextPtr, this.ptr, _toParams(key, value)); } push() { Z3.solver_push(contextPtr, this.ptr); } pop(num = 1) { Z3.solver_pop(contextPtr, this.ptr, num); } numScopes() { return Z3.solver_get_num_scopes(contextPtr, this.ptr); } reset() { Z3.solver_reset(contextPtr, this.ptr); } add(...exprs) { _flattenArgs(exprs).forEach(expr => { _assertContext(expr); check(Z3.solver_assert(contextPtr, this.ptr, expr.ast)); }); } addAndTrack(expr, constant) { if (typeof constant === 'string') { constant = Bool.const(constant); } (0, utils_1.assert)(isConst(constant), 'Provided expression that is not a constant to addAndTrack'); check(Z3.solver_assert_and_track(contextPtr, this.ptr, expr.ast, constant.ast)); } assertions() { return new AstVectorImpl(check(Z3.solver_get_assertions(contextPtr, this.ptr))); } async check(...exprs) { const assumptions = _flattenArgs(exprs).map(expr => { _assertContext(expr); return expr.ast; }); const result = await asyncMutex.runExclusive(() => check(Z3.solver_check_assumptions(contextPtr, this.ptr, assumptions))); switch (result) { case low_level_1.Z3_lbool.Z3_L_FALSE: return 'unsat'; case low_level_1.Z3_lbool.Z3_L_TRUE: return 'sat'; case low_level_1.Z3_lbool.Z3_L_UNDEF: return 'unknown'; default: (0, utils_1.assertExhaustive)(result); } } checkSync(...exprs) { const assumptions = _flattenArgs(exprs).map(expr => { _assertContext(expr); return expr.ast; }); const result = check(Z3.solver_check_assumptions(contextPtr, this.ptr, assumptions)); switch (result) { case low_level_1.Z3_lbool.Z3_L_FALSE: return 'unsat'; case low_level_1.Z3_lbool.Z3_L_TRUE: return 'sat'; case low_level_1.Z3_lbool.Z3_L_UNDEF: return 'unknown'; default: (0, utils_1.assertExhaustive)(result); } } model() { return new ModelImpl(check(Z3.solver_get_model(contextPtr, this.ptr))); } // extension unsatCore() { return new AstVectorImpl(check(Z3.solver_get_unsat_core(contextPtr, this.ptr))); } toString() { return check(Z3.solver_to_string(contextPtr, this.ptr)); } fromString(s) { Z3.solver_from_string(contextPtr, this.ptr, s); throwIfError(); } release() { Z3.solver_dec_ref(contextPtr, this.ptr); // Mark the ptr as null to prevent double free this._ptr = null; cleanup.unregister(this); } } class OptimizeImpl { get ptr() { _assertPtr(this._ptr); return this._ptr; } constructor(ptr = Z3.mk_optimize(contextPtr)) { this.ctx = ctx; let myPtr; myPtr = ptr; this._ptr = myPtr; Z3.optimize_inc_ref(contextPtr, myPtr); cleanup.register(this, () => Z3.optimize_dec_ref(contextPtr, myPtr), this); } set(key, value) { Z3.optimize_set_params(contextPtr, this.ptr, _toParams(key, value)); } push() { Z3.optimize_push(contextPtr, this.ptr); } pop() { Z3.optimize_pop(contextPtr, this.ptr); } add(...exprs) { _flattenArgs(exprs).forEach(expr => { _assertContext(expr); check(Z3.optimize_assert(contextPtr, this.ptr, expr.ast)); }); } addSoft(expr, weight, id = '') { if (isCoercibleRational(weight)) { weight = `${weight.numerator}/${weight.denominator}`; } check(Z3.optimize_assert_soft(contextPtr, this.ptr, expr.ast, weight.toString(), _toSymbol(id))); } addAndTrack(expr, constant) { if (typeof constant === 'string') { constant = Bool.const(constant); } (0, utils_1.assert)(isConst(constant), 'Provided expression that is not a constant to addAndTrack'); check(Z3.optimize_assert_and_track(contextPtr, this.ptr, expr.ast, constant.ast)); } assertions() { return new AstVectorImpl(check(Z3.optimize_get_assertions(contextPtr, this.ptr))); } maximize(expr) { check(Z3.optimize_maximize(contextPtr, this.ptr, expr.ast)); } minimize(expr) { check(Z3.optimize_minimize(contextPtr, this.ptr, expr.ast)); } async check(...exprs) { const assumptions = _flattenArgs(exprs).map(expr => { _assertContext(expr); return expr.ast; }); const result = await asyncMutex.runExclusive(() => check(Z3.optimize_check(contextPtr, this.ptr, assumptions))); switch (result) { case low_level_1.Z3_lbool.Z3_L_FALSE: return 'unsat'; case low_level_1.Z3_lbool.Z3_L_TRUE: return 'sat'; case low_level_1.Z3_lbool.Z3_L_UNDEF: return 'unknown'; default: (0, utils_1.assertExhaustive)(result); } } checkSync(...exprs) { const assumptions = _flattenArgs(exprs).map(expr => { _assertContext(expr); return expr.ast; }); const result = check(Z3.optimize_check(contextPtr, this.ptr, assumptions)); switch (result) { case low_level_1.Z3_lbool.Z3_L_FALSE: return 'unsat'; case low_level_1.Z3_lbool.Z3_L_TRUE: return 'sat'; case low_level_1.Z3_lbool.Z3_L_UNDEF: return 'unknown'; default: (0, utils_1.assertExhaustive)(result); } } model() { return new ModelImpl(check(Z3.optimize_get_model(contextPtr, this.ptr))); } toString() { return check(Z3.optimize_to_string(contextPtr, this.ptr)); } fromString(s) { Z3.optimize_from_string(contextPtr, this.ptr, s); throwIfError(); } release() { Z3.optimize_dec_ref(contextPtr, this.ptr); this._ptr = null; cleanup.unregister(this); } } class ModelImpl { get ptr() { _assertPtr(this._ptr); return this._ptr; } constructor(ptr = Z3.mk_model(contextPtr)) { this.ctx = ctx; this._ptr = ptr; Z3.model_inc_ref(contextPtr, ptr); cleanup.register(this, () => Z3.model_dec_ref(contextPtr, ptr), this); } length() { return Z3.model_get_num_consts(contextPtr, this.ptr) + Z3.model_get_num_funcs(contextPtr, this.ptr); } [Symbol.iterator]() { return this.values(); } *entries() { const length = this.length(); for (let i = 0; i < length; i++) { yield [i, this.get(i)]; } } *keys() { for (const [key] of this.entries()) { yield key;