1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
|
#!/usr/bin/env python
###############################################################################
# Top contributors (to current version):
# Aina Niemetz, Makai Mann, Mathias Preiner
#
# This file is part of the cvc5 project.
#
# Copyright (c) 2009-2025 by the authors listed in the file AUTHORS
# in the top-level source directory and their institutional affiliations.
# All rights reserved. See the file COPYING in the top-level source
# directory for licensing information.
# #############################################################################
#
# A simple demonstration of the solving capabilities of the cvc5
# floating point solver through the Python API contributed by Eva
# Darulova. This requires building cvc5 with symfpu.
##
import cvc5
from cvc5 import Kind, RoundingMode
if __name__ == "__main__":
tm = cvc5.TermManager()
slv = cvc5.Solver(tm)
slv.setOption("produce-models", "true")
slv.setLogic("QF_FP")
# single 32-bit precision
fp32 = tm.mkFloatingPointSort(8, 24)
# rounding mode
rm = tm.mkRoundingMode(RoundingMode.ROUND_NEAREST_TIES_TO_EVEN)
# create a few single-precision variables
a = tm.mkConst(fp32, 'a')
b = tm.mkConst(fp32, 'b')
c = tm.mkConst(fp32, 'c')
d = tm.mkConst(fp32, 'd')
e = tm.mkConst(fp32, 'e')
print("Show that fused multiplication and addition `(fp.fma RM a b c)`")
print("is different from `(fp.add RM (fp.mul a b) c)`:")
slv.push()
fma = tm.mkTerm(Kind.FLOATINGPOINT_FMA, rm, a, b, c)
mul = tm.mkTerm(Kind.FLOATINGPOINT_MULT, rm, a, b)
add = tm.mkTerm(Kind.FLOATINGPOINT_ADD, rm, mul, c)
slv.assertFormula(tm.mkTerm(Kind.DISTINCT, fma, add))
print("Expect SAT.")
print("cvc5:", slv.checkSat())
print(f'Value of `a`: {slv.getValue(a)}')
print(f'Value of `b`: {slv.getValue(b)}')
print(f'Value of `c`: {slv.getValue(c)}')
print(f'Value of `(fp.fma RNE a b c)`: {slv.getValue(fma)}')
print(f'Value of `(fp.add RNE (fp.mul a b) c)`: {slv.getValue(add)}')
print();
slv.pop();
print("Show that floating-point addition is not associative:")
print("(a + (b + c)) != ((a + b) + c)")
slv.push()
slv.assertFormula(tm.mkTerm(
Kind.DISTINCT,
tm.mkTerm(Kind.FLOATINGPOINT_ADD,
rm, a, tm.mkTerm(Kind.FLOATINGPOINT_ADD, rm, b, c)),
tm.mkTerm(Kind.FLOATINGPOINT_ADD,
rm, tm.mkTerm(Kind.FLOATINGPOINT_ADD, rm, a, b), c)))
print("Expect SAT.")
print("cvc5:", slv.checkSat())
print(f'Value of `a`: {slv.getValue(a)}')
print(f'Value of `b`: {slv.getValue(b)}')
print(f'Value of `c`: {slv.getValue(c)}')
print()
print("Now, restrict `a` to be either NaN or positive infinity:")
nan = tm.mkFloatingPointNaN(8, 24)
inf = tm.mkFloatingPointPosInf(8, 24)
slv.assertFormula(tm.mkTerm(
Kind.OR, tm.mkTerm(Kind.EQUAL, a, inf), tm.mkTerm(Kind.EQUAL, a, nan)))
print("Expect SAT.")
print("cvc5:", slv.checkSat())
print(f'Value of `a`: {slv.getValue(a)}')
print(f'Value of `b`: {slv.getValue(b)}')
print(f'Value of `c`: {slv.getValue(c)}')
print()
slv.pop(1)
print("Now, try to find a (normal) floating-point number that rounds")
print("to different integer values for different rounding modes:")
slv.push()
rtp = tm.mkRoundingMode(RoundingMode.ROUND_TOWARD_POSITIVE)
rtn = tm.mkRoundingMode(RoundingMode.ROUND_TOWARD_NEGATIVE)
op = tm.mkOp(Kind.FLOATINGPOINT_TO_UBV, 16) # (_ fp.to_ubv 16)
lhs = tm.mkTerm(op, rtp, d)
rhs = tm.mkTerm(op, rtn, d)
slv.assertFormula(tm.mkTerm(Kind.FLOATINGPOINT_IS_NORMAL, d))
slv.assertFormula(tm.mkTerm(Kind.NOT, tm.mkTerm(Kind.EQUAL, lhs, rhs)))
print("Expect SAT.")
print("cvc5:", slv.checkSat())
print("Get value of `d` as floating-point, bit-vector and real:")
val = slv.getValue(d)
print(f'Value of `d`: {val}')
print(f'Value of `((_ fp.to_ubv 16) RTP d)`: {slv.getValue(lhs)}')
print(f'Value of `((_ fp.to_ubv 16) RTN d)`: {slv.getValue(rhs)}')
print(f'Value of `(fp.to_real d)`: {slv.getValue(tm.mkTerm(Kind.FLOATINGPOINT_TO_REAL, val))}')
print()
slv.pop()
print("Finally, try to find a floating-point number between positive")
print("zero and the smallest positive floating-point number:")
zero = tm.mkFloatingPointPosZero(8, 24)
smallest = tm.mkFloatingPoint(8, 24, tm.mkBitVector(32, 0b001))
slv.assertFormula(tm.mkTerm(
Kind.AND, tm.mkTerm(Kind.FLOATINGPOINT_LT, zero, e),
tm.mkTerm(Kind.FLOATINGPOINT_LT, e, smallest)))
print("Expect UNSAT.")
print("cvc5:", slv.checkSat())
|