summaryrefslogtreecommitdiff
path: root/src/theory/idl/theory_idl.cpp
blob: bf2297d3d41e79ef19c58d76b88bbfc6976e0eff (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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include "theory/idl/theory_idl.h"
#include "theory/idl/options.h"
#include "theory/rewriter.h"

#include <set>
#include <queue>

using namespace std;

using namespace CVC4;
using namespace theory;
using namespace idl;

TheoryIdl::TheoryIdl(context::Context* c, context::UserContext* u, OutputChannel& out,
                     Valuation valuation, const LogicInfo& logicInfo, QuantifiersEngine* qe)
: Theory(THEORY_ARITH, c, u, out, valuation, logicInfo, qe)
, d_model(c)
, d_assertionsDB(c)
{}

Node TheoryIdl::ppRewrite(TNode atom) {
  if (atom.getKind() == kind::EQUAL  && options::idlRewriteEq()) {
    // If the option is turned on, each equality into two inequalities. This in
    // effect removes equalities, and theorefore dis-equalities too.
    Node leq = NodeBuilder<2>(kind::LEQ) << atom[0] << atom[1];
    Node geq = NodeBuilder<2>(kind::GEQ) << atom[0] << atom[1];
    Node rewritten = Rewriter::rewrite(leq.andNode(geq));
    return rewritten;
  } else {
    return atom;
  }
}

void TheoryIdl::check(Effort level) {

  while(!done()) {

    // Get the next assertion
    Assertion assertion = get();
    Debug("theory::idl") << "TheoryIdl::check(): processing " << assertion.assertion << std::endl;

    // Convert the assertion into the internal representation
    IDLAssertion idlAssertion(assertion.assertion);
    Debug("theory::idl") << "TheoryIdl::check(): got " << idlAssertion << std::endl;

    if (idlAssertion.ok()) {
      if (idlAssertion.getOp() == kind::DISTINCT) {
        // We don't handle dis-equalities
        d_out->setIncomplete();
      } else {
        // Process the convex assertions immediately
        bool ok = processAssertion(idlAssertion);
        if (!ok) {
          // In conflict, we're done
          return;
        }
      }
    } else {
      // Not an IDL assertion, set incomplete
      d_out->setIncomplete();
    }
  }

}

bool TheoryIdl::processAssertion(const IDLAssertion& assertion) {

  Debug("theory::idl") << "TheoryIdl::processAssertion(" << assertion << ")" << std::endl;

  // Add the constraint (x - y op c) to the list assertions of x
  d_assertionsDB.add(assertion, assertion.getX());

  // Update the model, if forced by the assertion
  bool y_updated = assertion.propagate(d_model);

  // If the value of y was updated, we might need to update further
  if (y_updated) {

    std::queue<TNode> queue; // Queue of variables to consider
    std::set<TNode> inQueue; // Current elements of the queue

    // Add the first updated variable to the queue
    queue.push(assertion.getY());
    inQueue.insert(assertion.getY());

    while (!queue.empty()) {
      // Pop a new variable x off the queue
      TNode x = queue.front();
      queue.pop();
      inQueue.erase(x);

      // Go through the constraint (x - y op c), and update values of y
      IDLAssertionDB::iterator it(d_assertionsDB, x);
      while (!it.done()) {
        // Get the assertion and update y
        IDLAssertion x_y_assertion = it.get();
        y_updated = x_y_assertion.propagate(d_model);
        // If updated add to the queue
        if (y_updated) {
          // If the variable that we updated is the same as the first
          // variable that we updated, it's a cycle of updates => conflict
          if (x_y_assertion.getY() == assertion.getX()) {
            std::vector<TNode> reasons;
            d_model.getReasonCycle(x_y_assertion.getY(), reasons);
            // Construct the reason of the conflict
            Node conflict = NodeManager::currentNM()->mkNode(kind::AND, reasons);
            d_out->conflict(conflict);
            return false;
          } else {
            // No cycle, just a model update, so we add to the queue
            TNode y = x_y_assertion.getY();
            if (inQueue.count(y) == 0) {
              queue.push(y);
              inQueue.insert(x_y_assertion.getY());
            }
          }
        }
        // Go to the next constraint
        it.next();
      }
    }
  }

  // Everything fine, no conflict
  return true;
}
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback