class Z3::FuncDecl

Overview

A function symbol - what SMT-LIB's declare-fun declares, and what a model hands back when it has decided what a function does.

Applying one with #[] gives an expression of the declared range sort, which is only known at runtime, so the result is an AnyExpr - a union - and has to be narrowed before anything at all can be done with it, #== included:

f = Z3.function("f", Z3::IntSort, Z3::IntSort)
x = f[3].as(Z3::IntExpr)
solver.assert x == 10

This is the tax on there being no common Z3::Expr base class yet - see _TODO.md.

Defined in:

z3/func_decl.cr

Constructors

Class Method Summary

Instance Method Summary

Constructor Detail

def self.declare(name : String, sorts : Array(AnySort)) : FuncDecl #

Last sort is the range, the ones before it are the domain, the same order SMT-LIB's declare-fun uses


[View source]
def self.declare_fresh(prefix : String, sorts : Array(AnySort)) : FuncDecl #

[View source]
def self.declare_rec(name : String, sorts : Array(AnySort)) : FuncDecl #

[View source]
def self.new(decl : LibZ3::FuncDecl) #

[View source]

Class Method Detail

def self.recursive_decl_kind : UInt32 #

Z3's answer for #recursive? is the decl kind Z3_OP_RECURSIVE, whose numeric value sits at the far end of an enum which grows between releases - so rather than writing the number down, we make one recursive declaration and ask Z3 what kind it came out as. Leaving it undefined is safe: nothing applies it, so no solver ever has to unfold it and no model mentions it.


[View source]

Instance Method Detail

def ==(other : FuncDecl) #

Z3 hash-conses declarations, so two decls of the same name and signature are one and the same pointer. Unlike an expression there's nothing for #== to build - a declaration is not a value - so this answers the question directly, and a FuncDecl works as a Hash key.


[View source]
def [](*args) : AnyExpr #

Applies the function. Arguments are cast into the declared domain sorts, so f[3] works wherever f[IntSort[3]] does.


[View source]
def arity #

[View source]
def call(*args) : AnyExpr #

[View source]
def define(&) : self #

Gives a recursive declaration its body - the define-fun-rec half of Z3.rec_function. The block gets one fresh variable per domain sort, as an Array because the arity is only known at runtime, and returns the body - which may call this very function:

fact = Z3.rec_function("fact", Z3::IntSort, Z3::IntSort)
fact.define do |args|
  n = args[0].as(Z3::IntExpr)
  (n <= 0).ite(1, n * fact[n - 1].as(Z3::IntExpr))
end

The Ruby gem takes the body as a block on Z3.RecFunction too. Here it's always this second step, because Crystal has no way to pass a variable number of block arguments and mutual recursion needs the two-step form anyway.

Only a declaration made by Z3.rec_function can be defined; Z3 says so itself for any other, which is a better error than anything we could check for here.


[View source]
def domain(i : Int) : AnySort #

[View source]
def hash(hasher) #
Description copied from class Reference

See Object#hash(hasher)


[View source]
def inspect(io) #

[View source]
def name : String #

[View source]
def range : AnySort #

[View source]
def recursive? #

Whether this was declared by Z3.rec_function, which is worth asking because Z3 hands those back in places nothing else shows up - see Model#funcs.


[View source]
def to_s(io) #

[View source]
def to_unsafe : LibZ3::FuncDecl #

[View source]