Quickstart Example

examples/api/cpp/quickstart.cpp

  1 /******************************************************************************
  2  * Top contributors (to current version):
  3  *   Yoni Zohar, Gereon Kremer, Mathias Preiner
  4  *
  5  * This file is part of the cvc5 project.
  6  *
  7  * Copyright (c) 2009-2022 by the authors listed in the file AUTHORS
  8  * in the top-level source directory and their institutional affiliations.
  9  * All rights reserved.  See the file COPYING in the top-level source
 10  * directory for licensing information.
 11  * ****************************************************************************
 12  *
 13  * A simple demonstration of the api capabilities of cvc5.
 14  *
 15  */
 16 
 17 #include <cvc5/cvc5.h>
 18 
 19 #include <iostream>
 20 #include <numeric>
 21 
 22 using namespace cvc5;
 23 
 24 int main()
 25 {
 26   // Create a solver
 27   //! [docs-cpp-quickstart-1 start]
 28   Solver solver;
 29   //! [docs-cpp-quickstart-1 end]
 30 
 31   // We will ask the solver to produce models and unsat cores,
 32   // hence these options should be turned on.
 33   //! [docs-cpp-quickstart-2 start]
 34   solver.setOption("produce-models", "true");
 35   solver.setOption("produce-unsat-cores", "true");
 36   //! [docs-cpp-quickstart-2 end]
 37 
 38   // The simplest way to set a logic for the solver is to choose "ALL".
 39   // This enables all logics in the solver.
 40   // Alternatively, "QF_ALL" enables all logics without quantifiers.
 41   // To optimize the solver's behavior for a more specific logic,
 42   // use the logic name, e.g. "QF_BV" or "QF_AUFBV".
 43 
 44   // Set the logic
 45   //! [docs-cpp-quickstart-3 start]
 46   solver.setLogic("ALL");
 47   //! [docs-cpp-quickstart-3 end]
 48 
 49   // In this example, we will define constraints over reals and integers.
 50   // Hence, we first obtain the corresponding sorts.
 51   //! [docs-cpp-quickstart-4 start]
 52   Sort realSort = solver.getRealSort();
 53   Sort intSort = solver.getIntegerSort();
 54   //! [docs-cpp-quickstart-4 end]
 55 
 56   // x and y will be real variables, while a and b will be integer variables.
 57   // Formally, their cpp type is Term,
 58   // and they are called "constants" in SMT jargon:
 59   //! [docs-cpp-quickstart-5 start]
 60   Term x = solver.mkConst(realSort, "x");
 61   Term y = solver.mkConst(realSort, "y");
 62   Term a = solver.mkConst(intSort, "a");
 63   Term b = solver.mkConst(intSort, "b");
 64   //! [docs-cpp-quickstart-5 end]
 65 
 66   // Our constraints regarding x and y will be:
 67   //
 68   //   (1)  0 < x
 69   //   (2)  0 < y
 70   //   (3)  x + y < 1
 71   //   (4)  x <= y
 72   //
 73 
 74   //! [docs-cpp-quickstart-6 start]
 75   // Formally, constraints are also terms. Their sort is Boolean.
 76   // We will construct these constraints gradually,
 77   // by defining each of their components.
 78   // We start with the constant numerals 0 and 1:
 79   Term zero = solver.mkReal(0);
 80   Term one = solver.mkReal(1);
 81 
 82   // Next, we construct the term x + y
 83   Term xPlusY = solver.mkTerm(ADD, {x, y});
 84 
 85   // Now we can define the constraints.
 86   // They use the operators +, <=, and <.
 87   // In the API, these are denoted by ADD, LEQ, and LT.
 88   // A list of available operators is available in:
 89   // src/api/cpp/cvc5_kind.h
 90   Term constraint1 = solver.mkTerm(LT, {zero, x});
 91   Term constraint2 = solver.mkTerm(LT, {zero, y});
 92   Term constraint3 = solver.mkTerm(LT, {xPlusY, one});
 93   Term constraint4 = solver.mkTerm(LEQ, {x, y});
 94 
 95   // Now we assert the constraints to the solver.
 96   solver.assertFormula(constraint1);
 97   solver.assertFormula(constraint2);
 98   solver.assertFormula(constraint3);
 99   solver.assertFormula(constraint4);
100   //! [docs-cpp-quickstart-6 end]
101 
102   // Check if the formula is satisfiable, that is,
103   // are there real values for x and y that satisfy all the constraints?
104   //! [docs-cpp-quickstart-7 start]
105   Result r1 = solver.checkSat();
106   //! [docs-cpp-quickstart-7 end]
107 
108   // The result is either SAT, UNSAT, or UNKNOWN.
109   // In this case, it is SAT.
110   //! [docs-cpp-quickstart-8 start]
111   std::cout << "expected: sat" << std::endl;
112   std::cout << "result: " << r1 << std::endl;
113   //! [docs-cpp-quickstart-8 end]
114 
115   // We can get the values for x and y that satisfy the constraints.
116   //! [docs-cpp-quickstart-9 start]
117   Term xVal = solver.getValue(x);
118   Term yVal = solver.getValue(y);
119   //! [docs-cpp-quickstart-9 end]
120 
121   // It is also possible to get values for compound terms,
122   // even if those did not appear in the original formula.
123   //! [docs-cpp-quickstart-10 start]
124   Term xMinusY = solver.mkTerm(SUB, {x, y});
125   Term xMinusYVal = solver.getValue(xMinusY);
126   //! [docs-cpp-quickstart-10 end]
127 
128   // We can now obtain the string representations of the values.
129   //! [docs-cpp-quickstart-11 start]
130   std::string xStr = xVal.getRealValue();
131   std::string yStr = yVal.getRealValue();
132   std::string xMinusYStr = xMinusYVal.getRealValue();
133 
134   std::cout << "value for x: " << xStr << std::endl;
135   std::cout << "value for y: " << yStr << std::endl;
136   std::cout << "value for x - y: " << xMinusYStr << std::endl;
137   //! [docs-cpp-quickstart-11 end]
138 
139   //! [docs-cpp-quickstart-12 start]
140   // Further, we can convert the values to cpp types
141   std::pair<int64_t, uint64_t> xPair = xVal.getReal64Value();
142   std::pair<int64_t, uint64_t> yPair = yVal.getReal64Value();
143   std::pair<int64_t, uint64_t> xMinusYPair = xMinusYVal.getReal64Value();
144 
145   std::cout << "value for x: " << xPair.first << "/" << xPair.second
146             << std::endl;
147   std::cout << "value for y: " << yPair.first << "/" << yPair.second
148             << std::endl;
149   std::cout << "value for x - y: " << xMinusYPair.first << "/"
150             << xMinusYPair.second << std::endl;
151   //! [docs-cpp-quickstart-12 end]
152 
153   // Another way to independently compute the value of x - y would be
154   // to perform the (rational) arithmetic manually.
155   // However, for more complex terms,
156   // it is easier to let the solver do the evaluation.
157   //! [docs-cpp-quickstart-13 start]
158   std::pair<int64_t, uint64_t> xMinusYComputed = {
159     xPair.first * yPair.second - xPair.second * yPair.first,
160     xPair.second * yPair.second
161   };
162   uint64_t g = std::gcd(xMinusYComputed.first, xMinusYComputed.second);
163   xMinusYComputed = { xMinusYComputed.first / g, xMinusYComputed.second / g };
164   if (xMinusYComputed == xMinusYPair)
165   {
166     std::cout << "computed correctly" << std::endl;
167   }
168   else
169   {
170     std::cout << "computed incorrectly" << std::endl;
171   }
172   //! [docs-cpp-quickstart-13 end]
173 
174   // Next, we will check satisfiability of the same formula,
175   // only this time over integer variables a and b.
176 
177   // We start by resetting assertions added to the solver.
178   //! [docs-cpp-quickstart-14 start]
179   solver.resetAssertions();
180   //! [docs-cpp-quickstart-14 end]
181 
182   // Next, we assert the same assertions above with integers.
183   // This time, we inline the construction of terms
184   // to the assertion command.
185   //! [docs-cpp-quickstart-15 start]
186   solver.assertFormula(solver.mkTerm(LT, {solver.mkInteger(0), a}));
187   solver.assertFormula(solver.mkTerm(LT, {solver.mkInteger(0), b}));
188   solver.assertFormula(
189       solver.mkTerm(LT, {solver.mkTerm(ADD, {a, b}), solver.mkInteger(1)}));
190   solver.assertFormula(solver.mkTerm(LEQ, {a, b}));
191   //! [docs-cpp-quickstart-15 end]
192 
193   // We check whether the revised assertion is satisfiable.
194   //! [docs-cpp-quickstart-16 start]
195   Result r2 = solver.checkSat();
196   //! [docs-cpp-quickstart-16 end]
197 
198   // This time the formula is unsatisfiable
199   //! [docs-cpp-quickstart-17 start]
200   std::cout << "expected: unsat" << std::endl;
201   std::cout << "result: " << r2 << std::endl;
202   //! [docs-cpp-quickstart-17 end]
203 
204   // We can query the solver for an unsatisfiable core, i.e., a subset
205   // of the assertions that is already unsatisfiable.
206   //! [docs-cpp-quickstart-18 start]
207   std::vector<Term> unsatCore = solver.getUnsatCore();
208   std::cout << "unsat core size: " << unsatCore.size() << std::endl;
209   std::cout << "unsat core: " << std::endl;
210   for (const Term& t : unsatCore)
211   {
212     std::cout << t << std::endl;
213   }
214   //! [docs-cpp-quickstart-18 end]
215 
216   return 0;
217 }