GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/omt/bitvector_optimizer.cpp Lines: 87 95 91.6 %
Date: 2021-05-24 Branches: 174 342 50.9 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Yancheng Ou, Michael Chang
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
 * Optimizer for BitVector type.
14
 */
15
16
#include "omt/bitvector_optimizer.h"
17
18
#include "options/smt_options.h"
19
#include "smt/smt_engine.h"
20
21
using namespace cvc5::smt;
22
namespace cvc5::omt {
23
24
10
OMTOptimizerBitVector::OMTOptimizerBitVector(bool isSigned)
25
10
    : d_isSigned(isSigned)
26
{
27
10
}
28
29
226
BitVector OMTOptimizerBitVector::computeAverage(const BitVector& a,
30
                                                const BitVector& b,
31
                                                bool isSigned)
32
{
33
  // computes (a + b) / 2 without overflow
34
  // rounding towards -infinity: -1.5 --> -2,  1.5 --> 1
35
  // average = (a / 2) + (b / 2) + (((a % 2) + (b % 2)) / 2)
36
226
  uint32_t aMod2 = static_cast<uint32_t>(a.isBitSet(0));
37
226
  uint32_t bMod2 = static_cast<uint32_t>(b.isBitSet(0));
38
452
  BitVector aMod2PlusbMod2Div2(a.getSize(), (aMod2 + bMod2) / 2);
39
452
  BitVector bv1 = BitVector::mkOne(a.getSize());
40
290
  return (isSigned) ? ((a.arithRightShift(bv1) + b.arithRightShift(bv1)
41
                        + aMod2PlusbMod2Div2))
42
388
                    : ((a.logicalRightShift(bv1) + b.logicalRightShift(bv1)
43
678
                        + aMod2PlusbMod2Div2));
44
}
45
46
6
OptimizationResult OMTOptimizerBitVector::minimize(SmtEngine* optChecker,
47
                                                   TNode target)
48
{
49
  // the smt engine to which we send intermediate queries
50
  // for the binary search.
51
6
  NodeManager* nm = optChecker->getNodeManager();
52
12
  Result intermediateSatResult = optChecker->checkSat();
53
  // Model-value of objective (used in optimization loop)
54
12
  Node value;
55
6
  if (intermediateSatResult.isUnknown())
56
  {
57
    return OptimizationResult(OptimizationResult::UNKNOWN, value);
58
  }
59
6
  if (intermediateSatResult.isSat() == Result::UNSAT)
60
  {
61
    return OptimizationResult(OptimizationResult::UNSAT, value);
62
  }
63
64
  // value equals to upperBound
65
6
  value = optChecker->getValue(target);
66
67
  // this gets the bitvector!
68
12
  BitVector bvValue = value.getConst<BitVector>();
69
6
  unsigned int bvSize = bvValue.getSize();
70
71
  // lowerbound
72
6
  BitVector lowerBound = ((this->d_isSigned) ? (BitVector::mkMinSigned(bvSize))
73
12
                                             : (BitVector::mkZero(bvSize)));
74
  // upperbound must be a satisfying value
75
  // and value == upperbound
76
12
  BitVector upperBound = bvValue;
77
78
6
  Kind LTOperator =
79
6
      ((d_isSigned) ? (kind::BITVECTOR_SLT) : (kind::BITVECTOR_ULT));
80
6
  Kind GEOperator =
81
6
      ((d_isSigned) ? (kind::BITVECTOR_SGE) : (kind::BITVECTOR_UGE));
82
83
  // the pivot value for binary search,
84
  // pivot = (lowerBound + upperBound) / 2
85
  // rounded towards -infinity
86
12
  BitVector pivot;
87
206
  while ((d_isSigned && lowerBound.signedLessThan(upperBound))
88
206
         || (!d_isSigned && lowerBound.unsignedLessThan(upperBound)))
89
  {
90
100
    pivot = computeAverage(lowerBound, upperBound, d_isSigned);
91
100
    optChecker->push();
92
100
    if (lowerBound == pivot)
93
    {
94
4
      optChecker->assertFormula(
95
8
          nm->mkNode(kind::EQUAL, target, nm->mkConst(lowerBound)));
96
    }
97
    else
98
    {
99
      // lowerBound <= target < pivot
100
96
      optChecker->assertFormula(
101
384
          nm->mkNode(kind::AND,
102
192
                     nm->mkNode(GEOperator, target, nm->mkConst(lowerBound)),
103
192
                     nm->mkNode(LTOperator, target, nm->mkConst(pivot))));
104
    }
105
100
    intermediateSatResult = optChecker->checkSat();
106
100
    if (intermediateSatResult.isUnknown() || intermediateSatResult.isNull())
107
    {
108
      return OptimizationResult(OptimizationResult::UNKNOWN, value);
109
    }
110
100
    if (intermediateSatResult.isSat() == Result::SAT)
111
    {
112
32
      value = optChecker->getValue(target);
113
32
      upperBound = value.getConst<BitVector>();
114
    }
115
68
    else if (intermediateSatResult.isSat() == Result::UNSAT)
116
    {
117
68
      if (lowerBound == pivot)
118
      {
119
        // lowerBound == pivot ==> upperbound = lowerbound + 1
120
        // and lowerbound <= target < upperbound is UNSAT
121
        // return the upperbound
122
2
        return OptimizationResult(OptimizationResult::OPTIMAL, value);
123
      }
124
      else
125
      {
126
66
        lowerBound = pivot;
127
      }
128
    }
129
    else
130
    {
131
      return OptimizationResult(OptimizationResult::UNKNOWN, value);
132
    }
133
98
    optChecker->pop();
134
  }
135
4
  return OptimizationResult(OptimizationResult::OPTIMAL, value);
136
}
137
138
4
OptimizationResult OMTOptimizerBitVector::maximize(SmtEngine* optChecker,
139
                                                   TNode target)
140
{
141
  // the smt engine to which we send intermediate queries
142
  // for the binary search.
143
4
  NodeManager* nm = optChecker->getNodeManager();
144
8
  Result intermediateSatResult = optChecker->checkSat();
145
  // Model-value of objective (used in optimization loop)
146
8
  Node value;
147
4
  if (intermediateSatResult.isUnknown())
148
  {
149
    return OptimizationResult(OptimizationResult::UNKNOWN, value);
150
  }
151
4
  if (intermediateSatResult.isSat() == Result::UNSAT)
152
  {
153
    return OptimizationResult(OptimizationResult::UNSAT, value);
154
  }
155
156
  // value equals to upperBound
157
4
  value = optChecker->getValue(target);
158
159
  // this gets the bitvector!
160
8
  BitVector bvValue = value.getConst<BitVector>();
161
4
  unsigned int bvSize = bvValue.getSize();
162
163
  // lowerbound must be a satisfying value
164
  // and value == lowerbound
165
8
  BitVector lowerBound = bvValue;
166
167
  // upperbound
168
4
  BitVector upperBound = ((this->d_isSigned) ? (BitVector::mkMaxSigned(bvSize))
169
8
                                             : (BitVector::mkOnes(bvSize)));
170
171
4
  Kind LEOperator =
172
4
      ((d_isSigned) ? (kind::BITVECTOR_SLE) : (kind::BITVECTOR_ULE));
173
4
  Kind GTOperator =
174
4
      ((d_isSigned) ? (kind::BITVECTOR_SGT) : (kind::BITVECTOR_UGT));
175
176
  // the pivot value for binary search,
177
  // pivot = (lowerBound + upperBound) / 2
178
  // rounded towards -infinity
179
8
  BitVector pivot;
180
314
  while ((d_isSigned && lowerBound.signedLessThan(upperBound))
181
194
         || (!d_isSigned && lowerBound.unsignedLessThan(upperBound)))
182
  {
183
126
    pivot = computeAverage(lowerBound, upperBound, d_isSigned);
184
185
126
    optChecker->push();
186
    // notice that we don't have boundary condition here
187
    // because lowerBound == pivot / lowerBound == upperBound + 1 is also
188
    // covered
189
    // pivot < target <= upperBound
190
126
    optChecker->assertFormula(
191
504
        nm->mkNode(kind::AND,
192
252
                   nm->mkNode(GTOperator, target, nm->mkConst(pivot)),
193
252
                   nm->mkNode(LEOperator, target, nm->mkConst(upperBound))));
194
126
    intermediateSatResult = optChecker->checkSat();
195
126
    if (intermediateSatResult.isUnknown() || intermediateSatResult.isNull())
196
    {
197
      return OptimizationResult(OptimizationResult::UNKNOWN, value);
198
    }
199
126
    if (intermediateSatResult.isSat() == Result::SAT)
200
    {
201
6
      value = optChecker->getValue(target);
202
6
      lowerBound = value.getConst<BitVector>();
203
    }
204
120
    else if (intermediateSatResult.isSat() == Result::UNSAT)
205
    {
206
120
      if (lowerBound == pivot)
207
      {
208
        // upperbound = lowerbound + 1
209
        // and lowerbound < target <= upperbound is UNSAT
210
        // return the lowerbound
211
2
        return OptimizationResult(OptimizationResult::OPTIMAL, value);
212
      }
213
      else
214
      {
215
118
        upperBound = pivot;
216
      }
217
    }
218
    else
219
    {
220
      return OptimizationResult(OptimizationResult::UNKNOWN, value);
221
    }
222
124
    optChecker->pop();
223
  }
224
2
  return OptimizationResult(OptimizationResult::OPTIMAL, value);
225
}
226
227
28191
}  // namespace cvc5::omt