1 /******************************************************************************
2 * Top contributors (to current version):
3 * Tim King, Mathias Preiner, Morgan Deters
5 * This file is part of the cvc5 project.
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 * ****************************************************************************
13 * [[ Add one-line brief description here ]]
15 * [[ Add lengthier description here ]]
16 * \todo document this file
19 #include "cvc5_private.h"
26 #include "options/arith_options.h"
27 #include "theory/arith/arithvar.h"
28 #include "theory/arith/bound_counts.h"
29 #include "theory/arith/callbacks.h"
30 #include "theory/arith/delta_rational.h"
31 #include "theory/arith/partial_model.h"
32 #include "theory/arith/tableau_sizes.h"
33 #include "util/bin_heap.h"
34 #include "util/statistics_stats.h"
42 * The priority queue has 3 different modes of operation:
44 * This passively collects arithmetic variables that may be inconsistent.
45 * This does not maintain any heap structure.
46 * dequeueInconsistentBasicVariable() does not work in this mode!
47 * Entering this mode requires the queue to be empty.
50 * This mode uses the difference between a variables and its bound
51 * to determine which to dequeue first.
53 * - Variable Order Queue
54 * This mode uses the variable order to determine which ArithVar is dequeued first.
56 * The transitions between the modes of operation are:
57 * Collection => Difference Queue
58 * Difference Queue => Variable Order Queue
59 * Difference Queue => Collection (queue must be empty!)
60 * Variable Order Queue => Collection (queue must be empty!)
62 * The queue begins in Collection mode.
68 class ComparatorPivotRule
{
70 const ErrorSet
* d_errorSet
;
72 options::ErrorSelectionRule d_rule
;
75 ComparatorPivotRule();
76 ComparatorPivotRule(const ErrorSet
* es
, options::ErrorSelectionRule r
);
78 bool operator()(ArithVar v
, ArithVar u
) const;
79 options::ErrorSelectionRule
getRule() const { return d_rule
; }
82 // typedef boost::heap::d_ary_heap<
84 // boost::heap::arity<2>,
85 // boost::heap::compare<ComparatorPivotRule>,
86 // boost::heap::mutable_<true> > FocusSet;
88 // typedef FocusSet::handle_type FocusSetHandle;
90 // typedef CVC5_PB_DS_NAMESPACE::priority_queue<
92 // ComparatorPivotRule,
93 // CVC5_PB_DS_NAMESPACE::pairing_heap_tag> FocusSet;
95 // typedef FocusSet::point_iterator FocusSetHandle;
97 typedef BinaryHeap
<ArithVar
, ComparatorPivotRule
> FocusSet
;
98 typedef FocusSet::handle FocusSetHandle
;
101 class ErrorInformation
{
103 /** The variable that is in error. */
107 * The constraint that was violated.
108 * This needs to be saved in case that the
109 * violated constraint
111 ConstraintP d_violated
;
114 * This is the sgn of the first derivate the variable must move to satisfy
115 * the bound violated.
116 * If d_sgn > 0, then d_violated was a lowerbound.
117 * If d_sgn < 0, then d_violated was an upperbound.
122 * If this is true, then the bound is no longer set on d_variables.
123 * This MUST be undone before this is deleted.
128 * If this is true, then the variable is in the focus set and the focus heap.
129 * d_handle is then a reasonable thing to interpret.
130 * If this is false, the variable is somewhere in
133 FocusSetHandle d_handle
;
136 * Auxillary information for storing the difference between a variable and its bound.
137 * Only set on signals.
139 std::unique_ptr
<DeltaRational
> d_amount
;
146 ErrorInformation(ArithVar var
, ConstraintP vio
, int sgn
);
148 ErrorInformation(const ErrorInformation
& ei
);
149 ErrorInformation
& operator=(const ErrorInformation
& ei
);
151 void reset(ConstraintP c
, int sgn
);
153 inline ArithVar
getVariable() const { return d_variable
; }
155 bool isRelaxed() const { return d_relaxed
; }
167 inline int sgn() const { return d_sgn
; }
169 inline bool inFocus() const { return d_inFocus
; }
170 inline int focusSgn() const {
171 return (d_inFocus
) ? sgn() : 0;
174 inline void setInFocus(bool inFocus
) { d_inFocus
= inFocus
; }
176 const DeltaRational
& getAmount() const {
177 Assert(d_amount
!= nullptr);
181 void setAmount(const DeltaRational
& am
);
182 void setMetric(uint32_t m
) { d_metric
= m
; }
183 uint32_t getMetric() const { return d_metric
; }
185 inline void setHandle(FocusSetHandle h
) {
189 inline const FocusSetHandle
& getHandle() const{ return d_handle
; }
191 inline ConstraintP
getViolated() const { return d_violated
; }
193 bool debugInitialized() const {
195 d_variable
!= ARITHVAR_SENTINEL
&&
196 d_violated
!= NullConstraint
&&
199 void print(std::ostream
& os
) const {
200 os
<< "{ErrorInfo: " << d_variable
201 << ", " << d_violated
204 << ", " << d_inFocus
;
205 if (d_amount
== nullptr)
217 class ErrorInfoMap
: public DenseMap
<ErrorInformation
> {};
222 * Reference to the arithmetic partial model for checking if a variable
223 * is consistent with its upper and lower bounds.
225 ArithVariables
& d_variables
;
228 * The set of all variables that violate exactly one of their bounds.
230 ErrorInfoMap d_errInfo
;
232 options::ErrorSelectionRule d_selectionRule
;
234 * The ordered heap for the variables that are in ErrorSet.
240 * A strict subset of the error set.
241 * d_outOfFocus \neq d_errInfo.
243 * Its symbolic complement is Focus.
244 * d_outOfFocus \intersect Focus == \emptyset
245 * d_outOfFocus \union Focus == d_errInfo
247 ArithVarVec d_outOfFocus
;
250 * Before a variable is added to the error set, it is added to the signals list.
251 * A variable may appear on the list multiple times.
252 * This introduces a delay.
254 ArithVarVec d_signals
;
256 TableauSizes d_tableauSizes
;
258 BoundCountingLookup d_boundLookup
;
261 * Computes the difference between the assignment and its bound for x.
264 DeltaRational
computeDiff(ArithVar x
) const;
266 void recomputeAmount(ErrorInformation
& ei
, options::ErrorSelectionRule r
);
268 void update(ErrorInformation
& ei
);
269 void transitionVariableOutOfError(ArithVar v
);
270 void transitionVariableIntoError(ArithVar v
);
271 void addBackIntoFocus(ArithVar v
);
275 /** The new focus set is the entire error set. */
277 void dropFromFocus(ArithVar v
);
279 void dropFromFocusAll(const ArithVarVec
& vec
) {
280 for(ArithVarVec::const_iterator i
= vec
.begin(), i_end
= vec
.end(); i
!= i_end
; ++i
){
286 ErrorSet(ArithVariables
& var
, TableauSizes tabSizes
, BoundCountingLookup boundLookup
);
288 typedef ErrorInfoMap::const_iterator error_iterator
;
289 error_iterator
errorBegin() const { return d_errInfo
.begin(); }
290 error_iterator
errorEnd() const { return d_errInfo
.end(); }
292 bool inError(ArithVar v
) const { return d_errInfo
.isKey(v
); }
293 bool inFocus(ArithVar v
) const { return d_errInfo
[v
].inFocus(); }
295 void pushErrorInto(ArithVarVec
& vec
) const;
296 void pushFocusInto(ArithVarVec
& vec
) const;
298 options::ErrorSelectionRule
getSelectionRule() const;
299 void setSelectionRule(options::ErrorSelectionRule rule
);
301 inline ArithVar
topFocusVariable() const{
302 Assert(!focusEmpty());
303 return d_focus
.top();
306 inline void signalVariable(ArithVar var
){
307 d_signals
.push_back(var
);
310 inline void signalUnderCnd(ArithVar var
, bool b
){
311 if(b
){ signalVariable(var
); }
314 inline bool inconsistent(ArithVar var
) const{
315 return !d_variables
.assignmentIsConsistent(var
) ;
317 inline void signalIfInconsistent(ArithVar var
){
318 signalUnderCnd(var
, inconsistent(var
));
321 inline bool errorEmpty() const{
322 return d_errInfo
.empty();
324 inline uint32_t errorSize() const{
325 return d_errInfo
.size();
328 inline bool focusEmpty() const {
329 return d_focus
.empty();
331 inline uint32_t focusSize() const{
332 return d_focus
.size();
335 inline int getSgn(ArithVar x
) const {
337 return d_errInfo
[x
].sgn();
339 inline int focusSgn(ArithVar v
) const {
341 return d_errInfo
[v
].focusSgn();
347 void focusDownToJust(ArithVar v
);
351 /** Clears the set. */
353 void reduceToSignals();
355 bool noSignals() const {
356 return d_signals
.empty();
358 bool moreSignals() const {
361 ArithVar
topSignal() const {
362 Assert(moreSignals());
363 return d_signals
.back();
367 * Moves a variable out of the signals.
368 * This moves it into the error set.
369 * Return the previous focus sign.
373 const DeltaRational
& getAmount(ArithVar v
) const {
374 return d_errInfo
[v
].getAmount();
377 uint32_t sumMetric(ArithVar a
) const{
379 BoundCounts bcs
= d_boundLookup
.atBounds(a
);
380 uint32_t count
= getSgn(a
) > 0 ? bcs
.upperBoundCount() : bcs
.lowerBoundCount();
382 uint32_t length
= d_tableauSizes
.getRowLength(a
);
384 return (length
- count
);
387 uint32_t getMetric(ArithVar a
) const {
388 return d_errInfo
[a
].getMetric();
391 ConstraintP
getViolated(ArithVar a
) const {
392 return d_errInfo
[a
].getViolated();
396 typedef FocusSet::const_iterator focus_iterator
;
397 focus_iterator
focusBegin() const { return d_focus
.begin(); }
398 focus_iterator
focusEnd() const { return d_focus
.end(); }
400 void debugPrint(std::ostream
& out
) const;
406 IntStat d_enqueuesCollection
;
407 IntStat d_enqueuesDiffMode
;
408 IntStat d_enqueuesVarOrderMode
;
410 IntStat d_enqueuesCollectionDuplicates
;
411 IntStat d_enqueuesVarOrderModeDuplicates
;
416 Statistics d_statistics
;
420 } // namespace theory