diff --git a/src/api/go/finiteset.go b/src/api/go/finiteset.go new file mode 100644 index 000000000..ffecef8c4 --- /dev/null +++ b/src/api/go/finiteset.go @@ -0,0 +1,78 @@ +package z3 + +/* +#include "z3.h" +*/ +import "C" + +// Finite set operations + +// MkFiniteSetSort creates a finite set sort with the given element sort. +func (c *Context) MkFiniteSetSort(elemSort *Sort) *Sort { + return newSort(c, C.Z3_mk_finite_set_sort(c.ptr, elemSort.ptr)) +} + +// IsFiniteSetSort returns true if the given sort is a finite set sort. +func (c *Context) IsFiniteSetSort(s *Sort) bool { + return bool(C.Z3_is_finite_set_sort(c.ptr, s.ptr)) +} + +// GetFiniteSetSortBasis returns the element sort of a finite set sort. +func (c *Context) GetFiniteSetSortBasis(s *Sort) *Sort { + return newSort(c, C.Z3_get_finite_set_sort_basis(c.ptr, s.ptr)) +} + +// MkFiniteSetEmpty creates an empty finite set of the given sort. +func (c *Context) MkFiniteSetEmpty(setSort *Sort) *Expr { + return newExpr(c, C.Z3_mk_finite_set_empty(c.ptr, setSort.ptr)) +} + +// MkFiniteSetSingleton creates a singleton finite set containing the given element. +func (c *Context) MkFiniteSetSingleton(elem *Expr) *Expr { + return newExpr(c, C.Z3_mk_finite_set_singleton(c.ptr, elem.ptr)) +} + +// MkFiniteSetUnion creates the union of two finite sets. +func (c *Context) MkFiniteSetUnion(s1, s2 *Expr) *Expr { + return newExpr(c, C.Z3_mk_finite_set_union(c.ptr, s1.ptr, s2.ptr)) +} + +// MkFiniteSetIntersect creates the intersection of two finite sets. +func (c *Context) MkFiniteSetIntersect(s1, s2 *Expr) *Expr { + return newExpr(c, C.Z3_mk_finite_set_intersect(c.ptr, s1.ptr, s2.ptr)) +} + +// MkFiniteSetDifference creates the set difference of two finite sets (s1 \ s2). +func (c *Context) MkFiniteSetDifference(s1, s2 *Expr) *Expr { + return newExpr(c, C.Z3_mk_finite_set_difference(c.ptr, s1.ptr, s2.ptr)) +} + +// MkFiniteSetMember creates a membership predicate: elem ∈ set. +func (c *Context) MkFiniteSetMember(elem, set *Expr) *Expr { + return newExpr(c, C.Z3_mk_finite_set_member(c.ptr, elem.ptr, set.ptr)) +} + +// MkFiniteSetSize creates an expression for the cardinality of a finite set. +func (c *Context) MkFiniteSetSize(set *Expr) *Expr { + return newExpr(c, C.Z3_mk_finite_set_size(c.ptr, set.ptr)) +} + +// MkFiniteSetSubset creates a subset predicate: s1 ⊆ s2. +func (c *Context) MkFiniteSetSubset(s1, s2 *Expr) *Expr { + return newExpr(c, C.Z3_mk_finite_set_subset(c.ptr, s1.ptr, s2.ptr)) +} + +// MkFiniteSetMap applies a function to all elements of a finite set. +func (c *Context) MkFiniteSetMap(f, set *Expr) *Expr { + return newExpr(c, C.Z3_mk_finite_set_map(c.ptr, f.ptr, set.ptr)) +} + +// MkFiniteSetFilter filters a finite set using a predicate function. +func (c *Context) MkFiniteSetFilter(f, set *Expr) *Expr { + return newExpr(c, C.Z3_mk_finite_set_filter(c.ptr, f.ptr, set.ptr)) +} + +// MkFiniteSetRange creates a finite set of integers in the range [low, high]. +func (c *Context) MkFiniteSetRange(low, high *Expr) *Expr { + return newExpr(c, C.Z3_mk_finite_set_range(c.ptr, low.ptr, high.ptr)) +} diff --git a/src/api/js/src/high-level/high-level.ts b/src/api/js/src/high-level/high-level.ts index 144c6f567..bed9313bb 100644 --- a/src/api/js/src/high-level/high-level.ts +++ b/src/api/js/src/high-level/high-level.ts @@ -123,6 +123,9 @@ import { DatatypeSort, DatatypeExpr, DatatypeCreation, + FiniteSet, + FiniteSetSort, + FiniteSetCreation, } from './types'; import { allSatisfy, assert, assertExhaustive } from './utils'; @@ -305,6 +308,9 @@ export function createApi(Z3: Z3Core): Z3HighLevel { case Z3_sort_kind.Z3_ARRAY_SORT: return new ArraySortImpl(ast); default: + if (Z3.is_finite_set_sort(contextPtr, ast)) { + return new FiniteSetSortImpl(ast); + } return new SortImpl(ast); } } @@ -350,6 +356,9 @@ export function createApi(Z3: Z3Core): Z3HighLevel { case Z3_sort_kind.Z3_ARRAY_SORT: return new ArrayImpl(ast); default: + if (Z3.is_finite_set_sort(contextPtr, Z3.get_sort(contextPtr, ast))) { + return new FiniteSetImpl(ast); + } return new ExprImpl(ast); } } @@ -638,6 +647,18 @@ export function createApi(Z3: Z3Core): Z3HighLevel { return isSeq(obj) && obj.isString(); } + function isFiniteSetSort(obj: unknown): obj is FiniteSetSort { + const r = obj instanceof FiniteSetSortImpl; + r && _assertContext(obj); + return r; + } + + function isFiniteSet(obj: unknown): obj is FiniteSet { + const r = obj instanceof FiniteSetImpl; + r && _assertContext(obj); + return r; + } + function isProbe(obj: unknown): obj is Probe { const r = obj instanceof ProbeImpl; r && _assertContext(obj); @@ -1104,6 +1125,32 @@ export function createApi(Z3: Z3Core): Z3HighLevel { }, }; + const FiniteSet = { + sort>(elemSort: ElemSort): FiniteSetSort { + return new FiniteSetSortImpl(check(Z3.mk_finite_set_sort(contextPtr, elemSort.ptr))); + }, + const>(name: string, elemSort: ElemSort): FiniteSet { + return new FiniteSetImpl( + check(Z3.mk_const(contextPtr, _toSymbol(name), FiniteSet.sort(elemSort).ptr)), + ); + }, + consts>(names: string | string[], elemSort: ElemSort): FiniteSet[] { + if (typeof names === 'string') { + names = names.split(' '); + } + return names.map(name => FiniteSet.const(name, elemSort)); + }, + empty>(sort: ElemSort): FiniteSet { + return new FiniteSetImpl(check(Z3.mk_finite_set_empty(contextPtr, FiniteSet.sort(sort).ptr))); + }, + singleton>(elem: Expr): FiniteSet { + return new FiniteSetImpl(check(Z3.mk_finite_set_singleton(contextPtr, elem.ast))); + }, + range(low: Expr, high: Expr): FiniteSet> { + return new FiniteSetImpl(check(Z3.mk_finite_set_range(contextPtr, low.ast, high.ast))); + }, + }; + const Datatype = Object.assign( (name: string): DatatypeImpl => { return new DatatypeImpl(ctx, name); @@ -4310,6 +4357,65 @@ export function createApi(Z3: Z3Core): Z3HighLevel { } } + //////////////////////////// + // Finite Sets + //////////////////////////// + + class FiniteSetSortImpl = Sort> + extends SortImpl + implements FiniteSetSort + { + declare readonly __typename: 'FiniteSetSort'; + + elemSort(): ElemSort { + return _toSort(check(Z3.get_finite_set_sort_basis(contextPtr, this.ptr))) as ElemSort; + } + + cast(other: Expr): Expr { + _assertContext(other); + return other; + } + } + + class FiniteSetImpl = Sort> + extends ExprImpl> + implements FiniteSet + { + declare readonly __typename: 'FiniteSet'; + + union(other: FiniteSet): FiniteSet { + return new FiniteSetImpl(check(Z3.mk_finite_set_union(contextPtr, this.ast, other.ast))); + } + + intersect(other: FiniteSet): FiniteSet { + return new FiniteSetImpl(check(Z3.mk_finite_set_intersect(contextPtr, this.ast, other.ast))); + } + + diff(other: FiniteSet): FiniteSet { + return new FiniteSetImpl(check(Z3.mk_finite_set_difference(contextPtr, this.ast, other.ast))); + } + + contains(elem: Expr): Bool { + return new BoolImpl(check(Z3.mk_finite_set_member(contextPtr, elem.ast, this.ast))); + } + + size(): Expr { + return new ExprImpl(check(Z3.mk_finite_set_size(contextPtr, this.ast))); + } + + subsetOf(other: FiniteSet): Bool { + return new BoolImpl(check(Z3.mk_finite_set_subset(contextPtr, this.ast, other.ast))); + } + + map(f: Expr): FiniteSet> { + return new FiniteSetImpl(check(Z3.mk_finite_set_map(contextPtr, f.ast, this.ast))); + } + + filter(f: Expr): FiniteSet { + return new FiniteSetImpl(check(Z3.mk_finite_set_filter(contextPtr, f.ast, this.ast))); + } + } + //////////////////////////// // Datatypes //////////////////////////// @@ -4902,6 +5008,8 @@ export function createApi(Z3: Z3Core): Z3HighLevel { isSeq, isStringSort, isString, + isFiniteSetSort, + isFiniteSet, isArraySort, isArray, isConstArray, @@ -4932,6 +5040,7 @@ export function createApi(Z3: Z3Core): Z3HighLevel { Re, Array, Set, + FiniteSet, Datatype, //////////////// diff --git a/src/api/js/src/high-level/types.ts b/src/api/js/src/high-level/types.ts index 2db0da591..e2cd9a856 100644 --- a/src/api/js/src/high-level/types.ts +++ b/src/api/js/src/high-level/types.ts @@ -52,7 +52,8 @@ export type AnyExpr = | FPNum | FPRM | Seq - | Re; + | Re + | FiniteSet; /** @hidden */ export type AnyAst = AnyExpr | AnySort | FuncDecl; @@ -330,6 +331,12 @@ export interface Context { /** @category Functions */ isString(obj: unknown): obj is Seq; + /** @category Functions */ + isFiniteSetSort(obj: unknown): obj is FiniteSetSort; + + /** @category Functions */ + isFiniteSet(obj: unknown): obj is FiniteSet; + /** @category Functions */ isProbe(obj: unknown): obj is Probe; @@ -468,6 +475,8 @@ export interface Context { /** @category Expressions */ readonly Set: SMTSetCreation; /** @category Expressions */ + readonly FiniteSet: FiniteSetCreation; + /** @category Expressions */ readonly Datatype: DatatypeCreation; //////////////// @@ -1706,7 +1715,8 @@ export interface Sort extends Ast { | FPSort['__typename'] | FPRMSort['__typename'] | SeqSort['__typename'] - | ReSort['__typename']; + | ReSort['__typename'] + | FiniteSetSort['__typename']; kind(): Z3_sort_kind; @@ -1835,7 +1845,8 @@ export interface Expr = AnySo | Seq['__typename'] | Re['__typename'] | SMTArray['__typename'] - | DatatypeExpr['__typename']; + | DatatypeExpr['__typename'] + | FiniteSet['__typename']; get sort(): S; @@ -2739,6 +2750,60 @@ export interface SMTSet, Name>): Bool; subsetOf(b: SMTSet): Bool; } +////////////////////////////////////////// +// +// Finite Sets +// +////////////////////////////////////////// + +/** + * Represents a finite set sort + * + * @typeParam ElemSort The sort of elements in the finite set + * @category Finite Sets + */ +export interface FiniteSetSort = Sort> + extends Sort { + readonly __typename: 'FiniteSetSort'; + /** Returns the element sort of this finite set sort */ + elemSort(): ElemSort; +} + +/** @category Finite Sets */ +export interface FiniteSetCreation { + sort>(elemSort: ElemSort): FiniteSetSort; + + const>(name: string, elemSort: ElemSort): FiniteSet; + + consts>(names: string | string[], elemSort: ElemSort): FiniteSet[]; + + empty>(sort: ElemSort): FiniteSet; + + singleton>(elem: Expr): FiniteSet; + + range(low: Expr, high: Expr): FiniteSet>; +} + +/** + * Represents a finite set expression + * + * @typeParam ElemSort The sort of elements in the finite set + * @category Finite Sets + */ +export interface FiniteSet = Sort> + extends Expr, Z3_ast> { + readonly __typename: 'FiniteSet'; + + union(other: FiniteSet): FiniteSet; + intersect(other: FiniteSet): FiniteSet; + diff(other: FiniteSet): FiniteSet; + contains(elem: Expr): Bool; + size(): Expr; + subsetOf(other: FiniteSet): Bool; + map(f: Expr): FiniteSet>; + filter(f: Expr): FiniteSet; +} + ////////////////////////////////////////// // // Datatypes diff --git a/src/api/ml/z3.ml b/src/api/ml/z3.ml index 42c8fdd45..af170808e 100644 --- a/src/api/ml/z3.ml +++ b/src/api/ml/z3.ml @@ -1311,6 +1311,24 @@ struct let mk_char_is_digit = Z3native.mk_char_is_digit end +module FiniteSet = +struct + let mk_sort = Z3native.mk_finite_set_sort + let is_finite_set_sort = Z3native.is_finite_set_sort + let get_sort_basis = Z3native.get_finite_set_sort_basis + let mk_empty = Z3native.mk_finite_set_empty + let mk_singleton = Z3native.mk_finite_set_singleton + let mk_union = Z3native.mk_finite_set_union + let mk_intersect = Z3native.mk_finite_set_intersect + let mk_difference = Z3native.mk_finite_set_difference + let mk_member = Z3native.mk_finite_set_member + let mk_size = Z3native.mk_finite_set_size + let mk_subset = Z3native.mk_finite_set_subset + let mk_map = Z3native.mk_finite_set_map + let mk_filter = Z3native.mk_finite_set_filter + let mk_range = Z3native.mk_finite_set_range +end + module FloatingPoint = struct module RoundingMode = diff --git a/src/api/ml/z3.mli b/src/api/ml/z3.mli index 4efbb074f..11aec782e 100644 --- a/src/api/ml/z3.mli +++ b/src/api/ml/z3.mli @@ -2058,6 +2058,53 @@ sig end +(** Finite Sets *) +module FiniteSet : +sig + (** Create a finite set sort with the given element sort. *) + val mk_sort : context -> Sort.sort -> Sort.sort + + (** Test if a sort is a finite set sort. *) + val is_finite_set_sort : context -> Sort.sort -> bool + + (** Get the element sort of a finite set sort. *) + val get_sort_basis : context -> Sort.sort -> Sort.sort + + (** Create an empty finite set of the given sort. *) + val mk_empty : context -> Sort.sort -> Expr.expr + + (** Create a singleton finite set containing the given element. *) + val mk_singleton : context -> Expr.expr -> Expr.expr + + (** Create the union of two finite sets. *) + val mk_union : context -> Expr.expr -> Expr.expr -> Expr.expr + + (** Create the intersection of two finite sets. *) + val mk_intersect : context -> Expr.expr -> Expr.expr -> Expr.expr + + (** Create the set difference of two finite sets (s1 \ s2). *) + val mk_difference : context -> Expr.expr -> Expr.expr -> Expr.expr + + (** Create a membership predicate: elem ∈ set. *) + val mk_member : context -> Expr.expr -> Expr.expr -> Expr.expr + + (** Create an expression for the cardinality of a finite set. *) + val mk_size : context -> Expr.expr -> Expr.expr + + (** Create a subset predicate: s1 ⊆ s2. *) + val mk_subset : context -> Expr.expr -> Expr.expr -> Expr.expr + + (** Apply a function to all elements of a finite set. *) + val mk_map : context -> Expr.expr -> Expr.expr -> Expr.expr + + (** Filter a finite set using a predicate function. *) + val mk_filter : context -> Expr.expr -> Expr.expr -> Expr.expr + + (** Create a finite set of integers in the range [low, high]. *) + val mk_range : context -> Expr.expr -> Expr.expr -> Expr.expr + +end + (** Floating-Point Arithmetic *) module FloatingPoint : sig