├── CMakeLists.txt ├── LICENSE ├── README.md ├── example ├── CMakeLists.txt └── example.cpp ├── include └── CEGIS.h └── src └── CEGIS.cpp /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.2) 2 | project(CEGIS 3 | LANGUAGES CXX 4 | VERSION 0.2 5 | ) 6 | 7 | set(CMAKE_CXX_STANDARD 11) 8 | 9 | # Find source files 10 | file(GLOB SOURCES src/*.cpp) 11 | 12 | # Include header files 13 | include_directories(include) 14 | 15 | # Require Boost 16 | find_package(Boost 1.58.0 REQUIRED) 17 | if(Boost_FOUND) 18 | include_directories(${Boost_INCLUDE_DIRS}) 19 | endif() 20 | 21 | # Require Python interpreter 22 | find_package(PythonInterp REQUIRED) 23 | 24 | # Give the user the option to avoid downloading Z3 25 | option(INSTALL_Z3 "Z3 will be downloaded, built and installed." ON) 26 | 27 | if(INSTALL_Z3) 28 | # Clone, build and install Z3 29 | include(ExternalProject) 30 | 31 | set(Z3_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/z3/) 32 | set(Z3_SRC ${Z3_PREFIX}/src/z3/) 33 | set(Z3_CMAKE ${Z3_SRC}/contrib/cmake/) 34 | set(Z3_BUILD ${Z3_PREFIX}/src/build/) 35 | 36 | ExternalProject_Add(z3 37 | PREFIX ${Z3_PREFIX} 38 | GIT_REPOSITORY https://github.com/Z3Prover/z3.git 39 | GIT_TAG z3-4.5.0 40 | CONFIGURE_COMMAND ${PYTHON_EXECUTABLE} ${Z3_CMAKE}/bootstrap.py create 41 | BINARY_DIR ${Z3_BUILD} 42 | BUILD_COMMAND cmake ../z3/ && make -j4 43 | INSTALL_COMMAND sudo make install 44 | UPDATE_DISCONNECTED 1 45 | ) 46 | endif() 47 | 48 | # Create shared library 49 | add_library(${PROJECT_NAME} SHARED ${SOURCES}) 50 | 51 | # Install library 52 | install(TARGETS ${PROJECT_NAME} DESTINATION lib/) 53 | 54 | # Install library headers 55 | file(GLOB HEADERS include/*.h) 56 | install(FILES ${HEADERS} DESTINATION include/) 57 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Modified MIT License 2 | 3 | Copyright (c) 2016 Marcel Walter 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software, including the rights 8 | to use, copy, modify, merge, publish, and/or distribute 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, but excluding to sublicense, sell, and/or use in patents, 11 | subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CEGIS 2 | 3 | Counter-example guided inductive synthesis (CEGIS) implementation for the SMT solver 4 | [Z3](https://github.com/Z3Prover/z3) by Microsoft Research. CEGIS is an approach to tackle 5 | complexity of exact syntheses using satisfiability solvers. It was first introduced by 6 | *Armando Solar-Lezama* in his Ph.D. Thesis 7 | [Program Synthesis by Sketching](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.207.9048&rep=rep1&type=pdf) 8 | back in 2008. 9 | 10 | ## What is CEGIS? 11 | 12 | Synthesis tasks often have the same structure: an implementation is sought that behaves correctly under all possible 13 | inputs (with the help of some extra variables, i.e. helper variables). 14 | 15 | More formal: ∃ Implementation : ∀ Inputs : ∃ Helper Variables : Implementation behaves correctly. 16 | 17 | It is absolutely legal to pass such a term to an SMT solver like Z3. A big drawback is the universal quantifier though. 18 | 19 | For many real world problems it is not necessary to consider all inputs to derive an implementation that behaves 20 | correctly for all of them. Following this observation, the problem was just moved to another position: which is the 21 | minimal subset of inputs one have to consider to ensure a correct synthesis? 22 | 23 | This is the point where CEGIS comes into play. CEGIS is a loop looking for exactly this minimal subset of inputs and 24 | performing the implementation synthesis as a "by-product". Therefore CEGIS uses one satisfiability solver to generate 25 | new implementations based on all the inputs considered so far (starting with zero); and another one to generate counter 26 | examples that uncover incorrect behavior in the latest synthesised implementation. Eventually there will be no more 27 | implementations possible, i.e. the specification is not realisable, or no more counter examples possible, i.e. the 28 | latest implementation must be correct. 29 | 30 | This CEGIS library works with the SMT solver Z3 and requires insight in the synthesis task to be executed, as it has to 31 | be specified which variables belong to implementation, inputs, etc. Boundary conditions are to be specified manually as 32 | well. 33 | 34 | ## Building and installing 35 | 36 | Git, g++, cmake, a Python interpreter and the Boost Library are necessary in order to build CEGIS. 37 | In *Ubuntu* the packages can be installed with 38 | 39 | ```sh 40 | sudo apt-get install git g++ cmake python libboost-all-dev 41 | ``` 42 | 43 | Afterwards, CEGIS is ready to be installed. 44 | 45 | ```sh 46 | git clone https://github.com/marcelwa/CEGIS.git 47 | cd CEGIS 48 | mkdir build 49 | cd build 50 | cmake .. 51 | make 52 | sudo make install 53 | ``` 54 | 55 | Since Z3 is automatically downloaded, configured and installed during this procedure, this step may take a while. 56 | Please enter your super user password to provide installation rights. 57 | 58 | The standard install prefix is `/usr/local/`. If another prefix is desired, just replace 59 | `cmake ..` by `cmake -DCMAKE_INSTALL_PREFIX:PATH=/YOUR_PREFIX ..`. If you do not want Z3 to be downloaded and installed 60 | during the build step because you have it already set up in your system, simply add `-DINSTALL_Z3=OFF` to your 61 | `cmake` parameter list. Both options can be configured using `ccmake`, too, of course. 62 | 63 | ### Uninstall 64 | 65 | If you want to uninstall the CEGIS library and the downloaded Z3 solver, simply type 66 | 67 | ```sh 68 | sudo xargs rm < install_manifest.txt 69 | ``` 70 | 71 | in the build directory. 72 | 73 | ## Usage 74 | 75 | The functionality of this library is encapsulated in a class called `CEGISHandler`. This class handles the given 76 | variables, constraints and execution of the CEGIS loop as well as runtime measurement and many other tasks. 77 | 78 | ```cpp 79 | using namespace z3; 80 | 81 | /* PREVIOUS USAGE */ 82 | context c; 83 | 84 | // ...a lot of stuff... 85 | 86 | solver s(c); 87 | s.add(exists(implementation, forall(inputs, exists(helpers, constraints)))); 88 | s.check(); 89 | 90 | 91 | /* BETTER CEGIS USAGE */ 92 | context c; 93 | 94 | // implementation, input and helper variables 95 | expr_vector impl(c), inp(c), hlp(c); 96 | 97 | // ...fill the vectors... 98 | 99 | // implementation constraints, e.g. no cycles allowed 100 | expr impl_cons(c); 101 | // behavior constraints, e.g. desired propagation 102 | expr behav_cons(c); 103 | // correctness constraints, e.g. outputs depend on the inputs in a specifc way 104 | expr corr_cons(c); 105 | 106 | // ...fill all those... 107 | 108 | // let's rock CEGIS 109 | CEGISHandler handler(&c, impl, inp, hlp, impl_cons, behav_cons, corr_cons); 110 | auto result = handler.CEGISRoutine(); 111 | result.print(); 112 | ``` 113 | -------------------------------------------------------------------------------- /example/CMakeLists.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelwa/CEGIS/05d01c8d4274af21b19b57d5ac6f154971cde675/example/CMakeLists.txt -------------------------------------------------------------------------------- /example/example.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by marcel on 27.12.16. 3 | // 4 | 5 | -------------------------------------------------------------------------------- /include/CEGIS.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by marcel on 03.12.16. 3 | // 4 | 5 | #ifndef CEGIS_CEGIS_H 6 | #define CEGIS_CEGIS_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | /** 15 | * Handler for Counter Example Guided Inductive Synthesis (CEGIS) routine for the SMT solver z3. 16 | */ 17 | class CEGISHandler { 18 | 19 | private: 20 | /** 21 | * A class representing an implementation, i.e. a valuation to the implementation variables. 22 | */ 23 | class Implementation { 24 | 25 | private: 26 | /** 27 | * The given model to store the valuation. 28 | */ 29 | const z3::model model; 30 | 31 | public: 32 | /** 33 | * The constructor. Takes a model to store the current valuation determined by the implementationSolver. 34 | * 35 | * @param mdl A model representing the implementation valuation. 36 | */ 37 | Implementation(const z3::model & mdl); 38 | 39 | /** 40 | * Extracts constraints from the stored model concerning the implementation variables, i.e. extracts an 41 | * expression stating that the given implementation variables should have the values they have in the model. 42 | * 43 | * @param implVars The variables for which the valuation is sought. 44 | * @return A constraint forcing implVars to have the same valuation as they originally had in the stored 45 | * model. 46 | */ 47 | const z3::expr extractConstraints(const z3::expr_vector & implVars, 48 | z3::context * ctx) const; 49 | /** 50 | * Returns the valuation to the given variable. Returns the variable itself iff no valuation exists. 51 | * 52 | * @return The valuation to the given (implementation) variables. 53 | */ 54 | const z3::expr getValuation(z3::expr var) const; 55 | }; // Implementation 56 | 57 | /** 58 | * Class representing a counter example within the CEGIS routine, i.e. a valuation to the input variables 59 | * so that the current implementation works incorrectly. 60 | */ 61 | class CounterExample { 62 | 63 | private: 64 | /** 65 | * The given model to store the valuation. 66 | */ 67 | const z3::model model; 68 | /** 69 | * A serial number. 70 | */ 71 | const size_t id; 72 | 73 | public: 74 | /** 75 | * Constructor of the CounterExample. Takes a model to store the current valuation determined by 76 | * the counterExampleSolver. 77 | * 78 | * @param mdl A model representing the counter example valuation. 79 | */ 80 | CounterExample(const z3::model & mdl); 81 | /** 82 | * Default copy constructor. 83 | * 84 | * @param ce CounterExample to be copied. 85 | */ 86 | CounterExample(const CounterExample & ce) = default; 87 | /** 88 | * Move constructor. 89 | * 90 | * @param ce CounterExample to be moved. 91 | */ 92 | CounterExample(CounterExample && ce); 93 | 94 | /** 95 | * Extracts constraints from the stored model concerning the input variables, i.e. extracts an expression 96 | * stating that the given input variables should have the values they have in the model. 97 | * 98 | * @param inputVars The variables for which the valuation is sought. 99 | * @param templ A pattern to relabel the variables concerning to the actual counter example number. 100 | * @return A constraint forcing relabeled inputVars to have the same valuation as they originally 101 | * had in the stored model. 102 | */ 103 | const z3::expr extractConstraints(const z3::expr_vector & inputVars, 104 | boost::format templ, 105 | z3::context * ctx) const; 106 | 107 | /** 108 | * Returns the serial number. 109 | * 110 | * @return The serial number. 111 | */ 112 | const size_t getNumber() const; 113 | }; // CounterExample 114 | 115 | /** 116 | * Alias to use as findImplementation() return type. 117 | */ 118 | using ImplementationPair = std::pair, z3::check_result>; 119 | /** 120 | * Returns the boost::optional of an ImplementationPair. 121 | * 122 | * @param implP ImplementationPair. 123 | * @return First value of implP, namely the optional Implementation. 124 | */ 125 | static inline const boost::optional & getOImpl(const ImplementationPair & implP) { return implP.first; } 126 | /** 127 | * Returns the Implementation of an ImplementationPair. 128 | * 129 | * @param implP ImplementationPair. 130 | * @return First value of implP, namely the Implementation. 131 | */ 132 | static inline const Implementation & getImpl(const ImplementationPair & implP) { return implP.first.get(); } 133 | /** 134 | * Returns the result of an ImplementationPair. 135 | * 136 | * @param implP ImplementationPair. 137 | * @return Second value of implP, namely the result returned by Z3. 138 | */ 139 | static inline const z3::check_result & getResult(const ImplementationPair & implP) { return implP.second; } 140 | /** 141 | * Alias to use as findCounterExample() return type. 142 | */ 143 | using CounterExamplePair = std::pair, z3::check_result>; 144 | /** 145 | * Returns the boost::optional of a CounterExamplePair. 146 | * 147 | * @param ceP CounterExamplePair. 148 | * @return First value of ceP, namely the optional CounterExample. 149 | */ 150 | static inline const boost::optional & getOCE(const CounterExamplePair & ceP) { return ceP.first; } 151 | /** 152 | * Returns the CounterExample of a CounterExamplePair. 153 | * 154 | * @param ceP CounterExamplePair. 155 | * @return First value of ceP, namely the CounterExample. 156 | */ 157 | static inline const CounterExample & getCE(const CounterExamplePair & ceP) { return ceP.first.get(); } 158 | /** 159 | * Returns the result of a CounterExamplePair. 160 | * 161 | * @param ceP CounterExamplePair. 162 | * @return Second value of ceP, namely the result returned by Z3. 163 | */ 164 | static inline const z3::check_result & getResult(const CounterExamplePair & ceP) { return ceP.second; } 165 | 166 | /** 167 | * The result type of the CEGIS routine storing the found implementation, all the counter examples 168 | * needed and the runtime. 169 | */ 170 | class CEGISResult { 171 | /** 172 | * Alias for the time_point type of the std::chrono library. 173 | */ 174 | using TimePoint = std::chrono::high_resolution_clock::time_point; 175 | 176 | private: 177 | /** 178 | * Stores the found implementation. Contains none iff CEGIS routine failed. 179 | */ 180 | const boost::optional implementation; 181 | /** 182 | * Solvers result. 183 | */ 184 | const z3::check_result result; 185 | /** 186 | * Stores all the needed counter examples. 187 | */ 188 | const std::vector counterExamples; 189 | /** 190 | * Start and end point of the CEGIS routine. 191 | */ 192 | const TimePoint startPoint, endPoint; 193 | /** 194 | * The name of the current implementation task. 195 | */ 196 | const std::string name; 197 | 198 | public: 199 | /** 200 | * Constructor. Gets the implementation and the counter examples to store as well as two time points 201 | * representing the start and the end of the CEGIS routine. 202 | * 203 | * @param implTp The found valuation to the implementation variables plus the solver state. 204 | * @param ces The needed counter examples during the CEGIS routine. 205 | * @param start The time stamp where the CEGIS routine started. 206 | * @param end The time stamp where the CEGIS routine finished. 207 | * @param n The name of the current implementation task. 208 | */ 209 | CEGISResult(const ImplementationPair & implP, 210 | const std::vector & ces, 211 | const TimePoint & start, 212 | const TimePoint & end, 213 | const std::string & n); 214 | 215 | /** 216 | * Indicates whether the CEGIS routine was able to find an implementation. 217 | * 218 | * @return z3::sat if an implementation was found, 219 | * z3::unsat if no implementation is possible, 220 | * z3::unknown if the solvers were not able to reason about it. 221 | */ 222 | const z3::check_result check() const; 223 | 224 | /** 225 | * Returns the valuation to the given variable. Returns the variable itself iff no valuation exists. 226 | * 227 | * @return The valuation to the given (implementation) variables. 228 | */ 229 | const z3::expr getValuation(const z3::expr var) const; 230 | 231 | /** 232 | * Gets the number of counter examples needed. 233 | * 234 | * @return The number of all needed counter examples. 235 | */ 236 | const size_t getNumberOfCounterExamples() const; 237 | 238 | /** 239 | * Gets the runtime in milliseconds needed to execute the whole CEGIS routine. 240 | * 241 | * @return The runtime in milliseconds needed to execute the CEGIS routine. 242 | */ 243 | long getRuntime() const; 244 | 245 | /** 246 | * Writes formatted results to the given std::ostream object. std::cout is used if no std::ostream object 247 | * is specified. Setting the csv flag to true outputs a comma-separated string line (ideal for 248 | * benchmarking). 249 | * 250 | * @param out The std::ostream object to which the results should be written. 251 | * @param csv A flag to indicate whether the output should be formatted comma-seperated. 252 | * If csv is set, the header should look like this: 253 | * Benchmark, Result, #Counter-examples, Runtime 254 | */ 255 | void print(std::ostream &out = std::cout, bool csv = false); 256 | }; // CEGISResult 257 | 258 | /** 259 | * Alias for high_resolution_clock type of the std::chrono library. 260 | */ 261 | using clock = std::chrono::high_resolution_clock; 262 | 263 | /** 264 | * The variables appearing in the expression to solve. 265 | */ 266 | const z3::expr_vector implementationVariables, inputVariables, helperVariables; 267 | /** 268 | * The expression to solve splitted in different parts. 269 | */ 270 | const z3::expr implementationExpression, behavioralExpression, correctnessExpression; 271 | /** 272 | * The given context used for all variables. 273 | */ 274 | z3::context * const context; 275 | /** 276 | * Two solvers are used alternately within the CEGIS routine. One to find valuations to the implementation 277 | * variables and one to find counter examples for the found valuation. 278 | */ 279 | z3::solver implementationSolver, counterExampleSolver; 280 | /** 281 | * A vector storing all found counter examples. 282 | */ 283 | std::vector counterExamples; 284 | 285 | /** 286 | * Counts the number of created counter examples. 287 | */ 288 | static size_t ceID; 289 | 290 | /** 291 | * Template used for substituting the input variables during the CEGIS routine. 292 | */ 293 | const boost::format INPUT_VAR_TEMPLATE{"inp_%1%_%2%"}; 294 | /** 295 | * Template used for substituting the helper variables during the CEGIS routine. 296 | */ 297 | const boost::format HELPER_VAR_TEMPLATE{"hlp_%1%_%2%"}; 298 | 299 | /** 300 | * Name of the current implementation task. 301 | */ 302 | std::string name = ""; 303 | 304 | /** 305 | * Taking into account all found counter examples, this function calls the implementationSolver to find 306 | * a new valuation to the implementation variables that could satisfy the overall instance. 307 | * 308 | * @return A boost::optional containing this valuation as an Implementation object iff one was found. 309 | */ 310 | const ImplementationPair findImplementation(); 311 | 312 | /** 313 | * Given the current Implementation, this function calls the counterExampleSolver to find a new valuation 314 | * to the input variables that leads to a contradiction. 315 | * 316 | * @param impl Current implementation for which a counter example should be found. 317 | * @return A boost::optional containing this contradiction, i.e. the valuation of the input variables, as 318 | * a CounterExample object iff one was found. 319 | */ 320 | const CounterExamplePair findCounterExample(const Implementation & impl); 321 | 322 | /** 323 | * Returns a z3::expr where all variables of vars appearing in expr are replaced by the pattern templ using the 324 | * current number of counter examples. 325 | * 326 | * @param expr Expression to be substituted. 327 | * @param vars Variables to be substituted in expr. 328 | * @param templ Pattern to perform the substitution. 329 | * @return A substituted expression. 330 | */ 331 | const z3::expr substituteVars(const z3::expr & expr, 332 | const z3::expr_vector & vars, 333 | boost::format templ) const; 334 | 335 | public: 336 | /** 337 | * Constructor. Creates a CEGISHandler object that is able to perform the CEGIS routine. 338 | * Requires a lot of parameters to keep the class immutable. 339 | * 340 | * @param ctx Pointer to the used context for all variables. 341 | * @param implVars The variables representing the sought implementation. 342 | * @param inpVars The variables representing the possible inputs. 343 | * @param hlpVars The variables representing the helpers. 344 | * @param implExpr Constraints ensuring validity of the implementation. 345 | * @param behavExpr Constraints ensuring correct internal behavior. 346 | * @param corrExpr Constraints ensuring desired output or similar. 347 | * 348 | */ 349 | CEGISHandler(z3::context * const ctx, 350 | z3::expr_vector const & implVars, 351 | z3::expr_vector const & inpVars, 352 | z3::expr_vector const & hlpVars, 353 | z3::expr const & implExpr, 354 | z3::expr const & behavExpr, 355 | z3::expr const & corrExpr); 356 | 357 | /** 358 | * Startes the CEGIS routine which tries to find a valuation to the input variables incrementally 359 | * by alternately calling two different solvers. 360 | * 361 | * @return a CEGISResult that stores the found implementation, all needed counter examples and the runtime. 362 | */ 363 | const CEGISResult CEGISRoutine(); 364 | 365 | /** 366 | * Sets the name of the current implementation task. 367 | * 368 | * @param n The desired name. 369 | */ 370 | void setName(std::string n); 371 | 372 | }; 373 | 374 | #endif //CEGIS_CEGIS_H 375 | -------------------------------------------------------------------------------- /src/CEGIS.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by marcel on 03.12.16. 3 | // 4 | 5 | #include "CEGIS.h" 6 | 7 | // *********************************************************** 8 | // ******************* CEGISHandler ************************** 9 | // *********************************************************** 10 | 11 | size_t CEGISHandler::ceID = 0; 12 | 13 | CEGISHandler::CEGISHandler(z3::context * const ctx, 14 | z3::expr_vector const & implVars, 15 | z3::expr_vector const & inpVars, 16 | z3::expr_vector const & hlpVars, 17 | z3::expr const & implExpr, 18 | z3::expr const & behavExpr, 19 | z3::expr const & corrExpr) 20 | : 21 | context{ctx}, 22 | implementationVariables{implVars}, 23 | inputVariables{inpVars}, 24 | helperVariables{hlpVars}, 25 | implementationExpression{implExpr}, 26 | behavioralExpression{behavExpr}, 27 | correctnessExpression{corrExpr}, 28 | implementationSolver{*context}, 29 | counterExampleSolver{*context}, 30 | counterExamples{} 31 | {} 32 | 33 | const CEGISHandler::CEGISResult CEGISHandler::CEGISRoutine() 34 | { 35 | implementationSolver.add(implementationExpression); 36 | counterExampleSolver.add(behavioralExpression && !correctnessExpression); 37 | 38 | auto start = clock::now(); 39 | while (true) { 40 | auto implTp = findImplementation(); 41 | if (getResult(implTp) == z3::sat) // another implementation was found 42 | { 43 | auto ceTp = findCounterExample(getImpl(implTp)); 44 | if (getResult(ceTp) == z3::sat) // another counter-example was found 45 | { 46 | counterExamples.push_back(std::move(getCE(ceTp))); 47 | } else // no more counter-examples possible 48 | { 49 | return CEGISResult(implTp, counterExamples, start, clock::now(), name); 50 | } 51 | } else // no implementation possible 52 | { 53 | return CEGISResult(implTp, counterExamples, start, clock::now(), name); 54 | } 55 | } 56 | } 57 | 58 | const CEGISHandler::ImplementationPair CEGISHandler::findImplementation() 59 | { 60 | if (!counterExamples.empty()) { 61 | // extract constraints from latest counter example 62 | auto counterExampleCons = counterExamples.back() 63 | .extractConstraints(inputVariables, INPUT_VAR_TEMPLATE, context); 64 | 65 | // substitute variables in behavior and correctness expression 66 | auto subExpr = substituteVars(behavioralExpression && correctnessExpression, 67 | inputVariables, INPUT_VAR_TEMPLATE); 68 | subExpr = substituteVars(subExpr, helperVariables, HELPER_VAR_TEMPLATE); 69 | 70 | implementationSolver.add(counterExampleCons && subExpr); 71 | } 72 | switch (implementationSolver.check()) 73 | { 74 | case z3::sat: 75 | { 76 | auto m = implementationSolver.get_model(); 77 | return std::make_pair(Implementation(m), z3::sat); 78 | } 79 | case z3::unsat: 80 | return std::make_pair(boost::optional(), z3::unsat); 81 | case z3::unknown: 82 | return std::make_pair(boost::optional(), z3::unknown); 83 | } 84 | } 85 | 86 | const CEGISHandler::CounterExamplePair CEGISHandler::findCounterExample(const Implementation & impl) 87 | { 88 | auto implCons = impl.extractConstraints(implementationVariables, context); 89 | counterExampleSolver.push(); 90 | counterExampleSolver.add(implCons); 91 | switch (counterExampleSolver.check()) 92 | { 93 | case z3::sat: 94 | { 95 | auto m = counterExampleSolver.get_model(); 96 | counterExampleSolver.pop(); 97 | return std::make_pair(CounterExample(m), z3::sat); 98 | } 99 | case z3::unsat: 100 | return std::make_pair(boost::optional(), z3::unsat); 101 | case z3::unknown: 102 | return std::make_pair(boost::optional(), z3::unknown); 103 | } 104 | } 105 | 106 | const z3::expr CEGISHandler::substituteVars(const z3::expr & expr, 107 | const z3::expr_vector & vars, 108 | boost::format templ) const 109 | { 110 | z3::expr_vector sub_vars{*context}; 111 | for (auto i = 0; i < vars.size(); ++i) 112 | { 113 | z3::expr current = vars[i]; 114 | const char *name = (templ % i % ceID).str().c_str(); 115 | z3::expr e = context->constant(name, current.get_sort()); 116 | sub_vars.push_back(e); 117 | } 118 | return z3::expr(expr).substitute(vars, sub_vars); 119 | } 120 | 121 | void CEGISHandler::setName(std::string n) { name = n; } 122 | 123 | 124 | // ************************************************************ 125 | // ******************* Implementation ************************* 126 | // ************************************************************ 127 | 128 | CEGISHandler::Implementation::Implementation(const z3::model & mdl) 129 | : 130 | model(mdl) 131 | {} 132 | 133 | const z3::expr CEGISHandler::Implementation::extractConstraints(const z3::expr_vector & implVars, 134 | z3::context * ctx) const 135 | { 136 | z3::expr_vector val{*ctx}; 137 | for (auto i = 0; i < implVars.size(); ++i) { 138 | z3::expr var = implVars[i]; 139 | val.push_back(var == model.eval(var)); 140 | } 141 | return z3::mk_and(val); 142 | } 143 | 144 | const z3::expr CEGISHandler::Implementation::getValuation(z3::expr var) const { return model.eval(var); } 145 | 146 | 147 | // ************************************************************ 148 | // ******************* CounterExample ************************* 149 | // ************************************************************ 150 | 151 | CEGISHandler::CounterExample::CounterExample(const z3::model & mdl) 152 | : 153 | model(mdl), 154 | id(ceID++) 155 | {} 156 | 157 | CEGISHandler::CounterExample::CounterExample(CounterExample && ce) 158 | : 159 | model(std::move(ce.model)), 160 | id(std::move(ce.id)) 161 | {} 162 | 163 | const z3::expr CEGISHandler::CounterExample::extractConstraints(const z3::expr_vector & inputVars, 164 | boost::format templ, 165 | z3::context * ctx) const 166 | { 167 | z3::expr_vector val{*ctx}; 168 | for (auto i = 0; i < inputVars.size(); ++i) 169 | { 170 | z3::expr var = inputVars[i]; 171 | const char *name = (templ % i % id).str().c_str(); 172 | val.push_back(ctx->constant(name, var.get_sort()) == model.eval(var)); 173 | } 174 | return z3::mk_and(val); 175 | } 176 | 177 | const size_t CEGISHandler::CounterExample::getNumber() const { return id; } 178 | 179 | 180 | 181 | // ************************************************************ 182 | // ********************* CEGISResult ************************** 183 | // ************************************************************ 184 | 185 | CEGISHandler::CEGISResult::CEGISResult(const ImplementationPair & implP, 186 | const std::vector & ces, 187 | const CEGISResult::TimePoint & start, 188 | const CEGISResult::TimePoint & end, 189 | const std::string & n) 190 | : 191 | implementation(getOImpl(implP)), 192 | result(getResult(implP)), 193 | counterExamples(ces), 194 | startPoint(start), 195 | endPoint(end), 196 | name(n) 197 | {} 198 | 199 | const z3::check_result CEGISHandler::CEGISResult::check() const { return result; } 200 | 201 | const z3::expr CEGISHandler::CEGISResult::getValuation(const z3::expr var) const 202 | { 203 | assert(check() == z3::sat); 204 | return implementation.get().getValuation(var); 205 | } 206 | 207 | const size_t CEGISHandler::CEGISResult::getNumberOfCounterExamples() const { return counterExamples.size(); } 208 | 209 | long CEGISHandler::CEGISResult::getRuntime() const 210 | { 211 | return std::chrono::duration_cast( endPoint - startPoint ).count(); 212 | } 213 | 214 | void CEGISHandler::CEGISResult::print(std::ostream &out, bool csv) 215 | { 216 | if (csv) 217 | out << name << ", " << result << ", " << getNumberOfCounterExamples() << ", " << getRuntime() << std::endl; 218 | else 219 | { 220 | out << "Benchmark: " << name << std::endl; 221 | out << "Result: " << result << std::endl; 222 | out << "#Counter-examples: " << getNumberOfCounterExamples() << std::endl; 223 | out << "Runtime: " << getRuntime() << " milliseconds" << std::endl; 224 | } 225 | } 226 | --------------------------------------------------------------------------------