summaryrefslogtreecommitdiff
path: root/examples/api/cpp/floating_point_arith.cpp
blob: 5c6c5a8a356e24aead97bb2787adb059896e06ea (plain)
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
/******************************************************************************
 * Top contributors (to current version):
 *   Andres Noetzli
 *
 * This file is part of the cvc5 project.
 *
 * Copyright (c) 2009-2021 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.
 * ****************************************************************************
 *
 * An example of solving floating-point problems with cvc5's cpp API
 *
 * This example shows to create floating-point types, variables and expressions,
 * and how to create rounding mode constants by solving toy problems. The
 * example also shows making special values (such as NaN and +oo) and converting
 * an IEEE 754-2008 bit-vector to a floating-point number.
 */

#include <cvc5/cvc5.h>

#include <iostream>
#include <cassert>

using namespace std;
using namespace cvc5::api;

int main()
{
  Solver solver;
  solver.setOption("produce-models", "true");

  // Make single precision floating-point variables
  Sort fpt32 = solver.mkFloatingPointSort(8, 24);
  Term a = solver.mkConst(fpt32, "a");
  Term b = solver.mkConst(fpt32, "b");
  Term c = solver.mkConst(fpt32, "c");
  Term d = solver.mkConst(fpt32, "d");
  Term e = solver.mkConst(fpt32, "e");

  // Assert that floating-point addition is not associative:
  // (a + (b + c)) != ((a + b) + c)
  Term rm = solver.mkRoundingMode(ROUND_NEAREST_TIES_TO_EVEN);
  Term lhs = solver.mkTerm(
      FLOATINGPOINT_ADD, rm, a, solver.mkTerm(FLOATINGPOINT_ADD, rm, b, c));
  Term rhs = solver.mkTerm(
      FLOATINGPOINT_ADD, rm, solver.mkTerm(FLOATINGPOINT_ADD, rm, a, b), c);
  solver.assertFormula(solver.mkTerm(NOT, solver.mkTerm(EQUAL, a, b)));

  Result r = solver.checkSat();  // result is sat
  assert (r.isSat());

  cout << "a = " << solver.getValue(a) << endl;
  cout << "b = " << solver.getValue(b) << endl;
  cout << "c = " << solver.getValue(c) << endl;

  // Now, let's restrict `a` to be either NaN or positive infinity
  Term nan = solver.mkNaN(8, 24);
  Term inf = solver.mkPosInf(8, 24);
  solver.assertFormula(solver.mkTerm(
      OR, solver.mkTerm(EQUAL, a, inf), solver.mkTerm(EQUAL, a, nan)));

  r = solver.checkSat();  // result is sat
  assert (r.isSat());

  cout << "a = " << solver.getValue(a) << endl;
  cout << "b = " << solver.getValue(b) << endl;
  cout << "c = " << solver.getValue(c) << endl;

  // And now for something completely different. Let's try to find a (normal)
  // floating-point number that rounds to different integer values for
  // different rounding modes.
  Term rtp = solver.mkRoundingMode(ROUND_TOWARD_POSITIVE);
  Term rtn = solver.mkRoundingMode(ROUND_TOWARD_NEGATIVE);
  Op op = solver.mkOp(FLOATINGPOINT_TO_SBV, 16);  // (_ fp.to_sbv 16)
  lhs = solver.mkTerm(op, rtp, d);
  rhs = solver.mkTerm(op, rtn, d);
  solver.assertFormula(solver.mkTerm(FLOATINGPOINT_ISN, d));
  solver.assertFormula(solver.mkTerm(NOT, solver.mkTerm(EQUAL, lhs, rhs)));

  r = solver.checkSat();  // result is sat
  assert (r.isSat());

  // Convert the result to a rational and print it
  Term val = solver.getValue(d);
  Term realVal = solver.getValue(solver.mkTerm(FLOATINGPOINT_TO_REAL, val));
  cout << "d = " << val << " = " << realVal << endl;
  cout << "((_ fp.to_sbv 16) RTP d) = " << solver.getValue(lhs) << endl;
  cout << "((_ fp.to_sbv 16) RTN d) = " << solver.getValue(rhs) << endl;

  // For our final trick, let's try to find a floating-point number between
  // positive zero and the smallest positive floating-point number
  Term zero = solver.mkPosZero(8, 24);
  Term smallest = solver.mkFloatingPoint(8, 24, solver.mkBitVector(32, 0b001));
  solver.assertFormula(
      solver.mkTerm(AND,
                    solver.mkTerm(FLOATINGPOINT_LT, zero, e),
                    solver.mkTerm(FLOATINGPOINT_LT, e, smallest)));

  r = solver.checkSat();  // result is unsat
  assert (!r.isSat());
}
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback