# Domains, Uninterpreted Functions, and Axioms

`domain`

blocks are used to create user-defined types and uninterpreted functions.
A domain has a name which can be used as a type in HeyVL code.
The domain block contains a list of `func`

s and `axiom`

s defined on this domain.

Every domain type supports the binary operators `==`

and `!=`

.
All other operations must be encoded using functions and axioms.

`axiom`

declarations behave like `assume`

statements and can quickly make verification unsound.
E.g. `axiom unsound ?(false)`

behaves like `assume ?(false)`

, making everything verify.
See below for a longer example.

Note that axioms with quantifiers quickly introduce *incompleteness* of Caesar, making it unable to prove or disprove verification.
Read the documentation section on SMT Theories and Incompleteness for more information.

## Example: Exponentials of ½

HeyVL does not support exponentiation expressions natively.
But we can define an uninterpreted function `ohfive_exp`

and add axioms that specify its result.
`ohfive_exp(n)`

should evaluate to `(½)ⁿ`

, so we add two axioms that define this exponential recursively.

`ohfive_exp_base`

states that `ohfive_exp(0) == 1`

and `ohfive_exp_step`

ensures that `ohfive_exp(exponent + 1) == 0.5 * ohfive_exp(exponent)`

holds.
This is sufficient to axiomatize our exponential function.

`domain Exponentials {`

func ohfive_exp(exponent: UInt): EUReal

axiom ohfive_exp_base ohfive_exp(0) == 1

axiom ohfive_exp_step forall exponent: UInt. ohfive_exp(exponent + 1) == 0.5 * ohfive_exp(exponent)

}

Note that this domain declaration creates a new type `Exponentials`

, but we do not use it.

We can check that `ohfive_exp(3)`

evaluates to `0.125`

by declaring a procedure with pre-condition `true`

and post-condition `ohfive_exp(3) == 0.125`

.
This procedure verifies:

`proc ohfive_3() -> ()`

pre ?(true)

post ?(ohfive_exp(3) == 0.125)

{}

**Do not forget the empty block of statements {} at the end!**
If you omit it, Caesar will not attempt to verify the procedure and thus will not check the specification.

## Pure Functions

You can also declare *pure* or *interpreted* functions.
These are defined by a single expression that computes the result of the function.

The following function declaration has a such a definition (`= x + 1`

):

`func plus_one(x: UInt): UInt = x + 1`

This syntax is just syntactic sugar for a function declaration with an additional axiom, i.e.

`func plus_one(x: UInt): UInt`

axiom plus_one_def forall x: UInt. plus_one(x) == x + 1

## Unsoundness From Axioms

Axioms are a dangerous feature because they can make verification unsound.

An easy example is this one:

`domain Unsound {`

axiom unsound false

}

proc wrong() -> ()

pre ?(true)

post ?(true)

{

assert ?(false)

}

The axiom `unsound`

always evaluates to `false`

.
But for verification, Caesar assumes the axioms hold for all program states.
In other words, Caesar only verifies the program states in which the axioms evaluate to `true`

.
Thus, Caesar does not verify any program state and the procedure `wrong`

incorrectly verifies!