GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/smt/check_models.cpp Lines: 36 48 75.0 %
Date: 2021-11-07 Branches: 81 202 40.1 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Morgan Deters, Andres Noetzli
4
 *
5
 * This file is part of the cvc5 project.
6
 *
7
 * Copyright (c) 2009-2021 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
 * Utility for constructing and maintaining abstract values.
14
 */
15
16
#include "smt/check_models.h"
17
18
#include "base/modal_exception.h"
19
#include "options/smt_options.h"
20
#include "smt/env.h"
21
#include "smt/preprocessor.h"
22
#include "smt/smt_solver.h"
23
#include "theory/rewriter.h"
24
#include "theory/substitutions.h"
25
#include "theory/theory_engine.h"
26
#include "theory/theory_model.h"
27
28
using namespace cvc5::theory;
29
30
namespace cvc5 {
31
namespace smt {
32
33
15273
CheckModels::CheckModels(Env& e) : EnvObj(e) {}
34
35
3862
void CheckModels::checkModel(TheoryModel* m,
36
                             const context::CDList<Node>& al,
37
                             bool hardFailure)
38
{
39
  // Throughout, we use verbose(1) to give diagnostic output.
40
  //
41
  // If this function is running, the user gave --check-model (or equivalent),
42
  // and if verbose(1) is on, the user gave --verbose (or equivalent).
43
44
  // check-model is not guaranteed to succeed if approximate values were used.
45
  // Thus, we intentionally abort here.
46
3862
  if (m->hasApproximations())
47
  {
48
    throw RecoverableModalException(
49
1
        "Cannot run check-model on a model with approximate values.");
50
  }
51
3903
  Node sepHeap, sepNeq;
52
3861
  if (m->getHeapModel(sepHeap, sepNeq))
53
  {
54
    throw RecoverableModalException(
55
        "Cannot run check-model on a model with a separation logic heap.");
56
  }
57
58
3861
  theory::SubstitutionMap& sm = d_env.getTopLevelSubstitutions().get();
59
3861
  Trace("check-model") << "checkModel: Check assertions..." << std::endl;
60
3903
  std::unordered_map<Node, Node> cache;
61
  // the list of assertions that did not rewrite to true
62
3903
  std::vector<Node> noCheckList;
63
  // Now go through all our user assertions checking if they're satisfied.
64
27312
  for (const Node& assertion : al)
65
  {
66
46902
    verbose(1) << "SolverEngine::checkModel(): checking assertion " << assertion
67
23451
               << std::endl;
68
69
    // Apply any define-funs from the problem. We do not expand theory symbols
70
    // like integer division here. Hence, the code below is not able to properly
71
    // evaluate e.g. divide-by-zero. This is intentional since the evaluation
72
    // is not trustworthy, since the UF introduced by expanding definitions may
73
    // not be properly constrained.
74
23451
    Node n = sm.apply(assertion, false);
75
46902
    verbose(1) << "SolverEngine::checkModel(): -- substitutes to " << n
76
23451
               << std::endl;
77
78
23451
    n = rewrite(n);
79
46902
    verbose(1) << "SolverEngine::checkModel(): -- rewrites to " << n
80
23451
               << std::endl;
81
82
    // We look up the value before simplifying. If n contains quantifiers,
83
    // this may increases the chance of finding its value before the node is
84
    // altered by simplification below.
85
23451
    n = m->getValue(n);
86
46902
    verbose(1) << "SolverEngine::checkModel(): -- get value : " << n
87
23451
               << std::endl;
88
89
23451
    if (n.isConst() && n.getConst<bool>())
90
    {
91
      // assertion is true, everything is fine
92
23403
      continue;
93
    }
94
95
    // Otherwise, we did not succeed in showing the current assertion to be
96
    // true. This may either indicate that our model is wrong, or that we cannot
97
    // check it. The latter may be the case for several reasons.
98
    // One example is the occurrence of partial operators. Another example
99
    // are quantified formulas, which are not checkable, although we assign
100
    // them to true/false based on the satisfying assignment. However,
101
    // quantified formulas can be modified during preprocess, so they may not
102
    // correspond to those in the satisfying assignment. Hence we throw
103
    // warnings for assertions that do not simplify to either true or false.
104
    // Other theories such as non-linear arithmetic (in particular,
105
    // transcendental functions) also have the property of not being able to
106
    // be checked precisely here.
107
    // Note that warnings like these can be avoided for quantified formulas
108
    // by making preprocessing passes explicitly record how they
109
    // rewrite quantified formulas (see cvc4-wishues#43).
110
96
    if (!n.isConst())
111
    {
112
      // Not constant, print a less severe warning message here.
113
48
      warning()
114
          << "Warning : SolverEngine::checkModel(): cannot check simplified "
115
48
             "assertion : "
116
48
          << n << std::endl;
117
48
      noCheckList.push_back(n);
118
48
      continue;
119
    }
120
    // Assertions that simplify to false result in an InternalError or
121
    // Warning being thrown below (when hardFailure is false).
122
    verbose(1) << "SolverEngine::checkModel(): *** PROBLEM: EXPECTED `TRUE' ***"
123
               << std::endl;
124
    std::stringstream ss;
125
    ss << "SolverEngine::checkModel(): "
126
       << "ERRORS SATISFYING ASSERTIONS WITH MODEL:" << std::endl
127
       << "assertion:     " << assertion << std::endl
128
       << "simplifies to: " << n << std::endl
129
       << "expected `true'." << std::endl
130
       << "Run with `--check-models -v' for additional diagnostics.";
131
    if (hardFailure)
132
    {
133
      // internal error if hardFailure is true
134
      InternalError() << ss.str();
135
    }
136
    else
137
    {
138
      warning() << ss.str() << std::endl;
139
    }
140
  }
141
3861
  if (noCheckList.empty())
142
  {
143
3819
    verbose(1) << "SolverEngine::checkModel(): all assertions checked out OK !"
144
3819
               << std::endl;
145
3819
    return;
146
  }
147
  // if the noCheckList is non-empty, we could expand definitions on this list
148
  // and check satisfiability
149
150
42
  Trace("check-model") << "checkModel: Finish" << std::endl;
151
}
152
153
}  // namespace smt
154
31137
}  // namespace cvc5