CIRCT 23.0.0git
Loading...
Searching...
No Matches
SATSolver.h
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This header defines an abstract incremental SAT interface
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef CIRCT_SUPPORT_SATSOLVER_H
14#define CIRCT_SUPPORT_SATSOLVER_H
15
16#include "llvm/ADT/ArrayRef.h"
17#include <memory>
18
19namespace circt {
20template <typename T>
21struct HeapScore;
22
23/// A max-heap of ids into caller-owned storage.
24///
25/// The heap stores only integer ids and keeps a reverse map from each id to its
26/// heap slot. That lets callers update an existing entry without creating
27/// duplicates. Scores come from a stateless policy type. If a caller changes an
28/// element in `storage` in a way that raises its score, it must call
29/// `increase(id)` to restore heap order.
30///
31/// This data structure design is inspired by MiniSat's `minisat/mtl/Heap.h`.
32template <typename T, typename ScoreFn = HeapScore<T>>
34public:
35 // Create an empty heap referencing caller-owned storage. Caller must keep
36 // storage alive; heap is empty until insert() is used.
37 explicit IndexedMaxHeap(llvm::SmallVectorImpl<T> &storage)
38 : storage(storage) {}
39
40 void resize(unsigned size) {
41 if (positions.size() < size)
42 positions.resize(size, kInvalidIndex);
43 }
44
45 bool empty() const { return heap.empty(); }
46
47 bool contains(unsigned id) const {
48 return id < positions.size() && positions[id] != kInvalidIndex;
49 }
50
51 /// Remove all heap entries while keeping the underlying storage untouched.
52 void clear() {
53 heap.clear();
54 std::fill(positions.begin(), positions.end(), kInvalidIndex);
55 }
56
57 /// Insert `id` if it is not already present.
58 ///
59 /// This heap treats ids as stable identities; duplicates are ignored instead
60 /// of creating multiple entries for the same object.
61 void insert(unsigned id) {
62 if (contains(id))
63 return;
64 resize(id + 1);
65 positions[id] = heap.size();
66 heap.push_back(id);
67 siftUp(positions[id]);
68 }
69
70 /// Restore heap order after the score for an existing `id` increased.
71 ///
72 /// This only moves the entry upward. Callers should use this when the score
73 /// policy is monotonic in the "better" direction, such as SAT variable
74 /// activity bumps. Mutating a stored element without calling `increase(id)`
75 /// leaves the heap order stale.
76 void increase(unsigned id) {
77 if (contains(id))
78 siftUp(positions[id]);
79 }
80
81 /// Remove and return the highest-scoring id.
82 unsigned pop() {
83 assert(!empty() && "cannot pop from empty heap");
84 unsigned top = heap.front();
86 if (heap.size() == 1) {
87 heap.pop_back();
88 return top;
89 }
90
91 // Move the last entry to the root and sift down to restore heap order.
92 heap.front() = heap.back();
93 positions[heap.front()] = 0;
94 heap.pop_back();
95 siftDown(0);
96 return top;
97 }
98
99private:
100 static constexpr unsigned kInvalidIndex = ~0u;
101
102 /// Compute the ordering score for one heap entry.
103 double score(unsigned id) const { return ScoreFn{}(storage[id]); }
104
105 /// Swap two heap slots and keep the reverse index in sync.
106 void swapHeapEntries(unsigned lhs, unsigned rhs) {
107 std::swap(heap[lhs], heap[rhs]);
108 positions[heap[lhs]] = lhs;
109 positions[heap[rhs]] = rhs;
110 }
111
112 /// Bubble one entry toward the root until the heap property is restored.
113 void siftUp(unsigned index) {
114 unsigned elem = heap[index];
115 double elemScore = score(elem);
116 while (index > 0) {
117 unsigned parent = (index - 1) / 2;
118 if (score(heap[parent]) >= elemScore)
119 break;
120 swapHeapEntries(index, parent);
121 index = parent;
122 }
123 assert(heap[index] == elem && "siftUp must preserve the promoted element");
124 }
125
126 /// Push one entry toward the leaves until the heap property is restored.
127 void siftDown(unsigned index) {
128 unsigned elem = heap[index];
129 double elemScore = score(elem);
130 unsigned heapSize = heap.size();
131 while (true) {
132 unsigned child = 2 * index + 1;
133 if (child >= heapSize)
134 break;
135 if (child + 1 < heapSize && score(heap[child + 1]) > score(heap[child]))
136 ++child;
137 if (elemScore >= score(heap[child]))
138 break;
139 swapHeapEntries(index, child);
140 index = child;
141 }
142 assert(heap[index] == elem && "siftDown must preserve the demoted element");
143 }
144
145 /// The caller-owned objects indexed by heap ids.
146 llvm::SmallVectorImpl<T> &storage;
147
148 /// Binary heap of ids ordered by descending score.
149 llvm::SmallVector<unsigned, 0> heap;
150
151 /// Reverse map from id to heap slot, or `InvalidIndex` if absent.
152 llvm::SmallVector<unsigned, 0> positions;
153};
154
155/// Abstract interface for incremental SAT solvers with an IPASIR-style API.
157public:
158 enum Result : int { kSAT = 10, kUNSAT = 20, kUNKNOWN = 0 };
159
160 virtual ~IncrementalSATSolver() = default;
161
162 /// Add one literal to the clause currently under construction. A `0`
163 /// literal terminates the clause and submits it to the solver.
164 virtual void add(int lit) = 0;
165 /// Add an assumption literal for the next `solve()` call only.
166 virtual void assume(int lit) = 0;
167 /// Solve under the previously added clauses and current assumptions.
168 virtual Result solve() = 0;
169 virtual Result solve(llvm::ArrayRef<int> assumptions) {
170 for (int lit : assumptions)
171 assume(lit);
172 return solve();
173 };
174 /// Return the satisfying assignment for variable `v` from the last SAT
175 /// result. The sign of the returned literal encodes the Boolean value.
176 virtual int val(int v) const = 0;
177
178 // These helpers are not part of the standard IPASIR interface.
179 /// Set the per-`solve()` conflict budget. Negative values restore the
180 /// backend default of no explicit conflict limit. The backend may choose to
181 /// ignore this if it does not support conflict limits.
182 virtual void setConflictLimit(int limit) {}
183 /// Reserve storage for variables in the range `[1, maxVar]`.
184 virtual void reserveVars(int maxVar) {}
185 /// Add a complete clause in one call.
186 virtual void addClause(llvm::ArrayRef<int> lits) {
187 for (int lit : lits)
188 add(lit);
189 add(0);
190 }
191};
192
193/// Construct a Z3-backed incremental IPASIR-style SAT solver.
194std::unique_ptr<IncrementalSATSolver> createZ3SATSolver();
197 Default, // Default.
198 Plain, // Disable preprocessing.
199 Sat, // Target satisfiable instances.
200 Unsat, // Target unsatisfiable instances.
201 };
203};
204/// Construct a CaDiCaL-backed incremental IPASIR-style SAT solver.
205std::unique_ptr<IncrementalSATSolver>
207/// Return true when at least one incremental SAT backend is available.
209
210} // namespace circt
211
212#endif // CIRCT_SUPPORT_SATSOLVER_H
assert(baseType &&"element must be base type")
Abstract interface for incremental SAT solvers with an IPASIR-style API.
Definition SATSolver.h:156
virtual Result solve(llvm::ArrayRef< int > assumptions)
Definition SATSolver.h:169
virtual void reserveVars(int maxVar)
Reserve storage for variables in the range [1, maxVar].
Definition SATSolver.h:184
virtual void addClause(llvm::ArrayRef< int > lits)
Add a complete clause in one call.
Definition SATSolver.h:186
virtual ~IncrementalSATSolver()=default
virtual void add(int lit)=0
Add one literal to the clause currently under construction.
virtual void setConflictLimit(int limit)
Set the per-solve() conflict budget.
Definition SATSolver.h:182
virtual int val(int v) const =0
Return the satisfying assignment for variable v from the last SAT result.
virtual Result solve()=0
Solve under the previously added clauses and current assumptions.
virtual void assume(int lit)=0
Add an assumption literal for the next solve() call only.
A max-heap of ids into caller-owned storage.
Definition SATSolver.h:33
void increase(unsigned id)
Restore heap order after the score for an existing id increased.
Definition SATSolver.h:76
static constexpr unsigned kInvalidIndex
Definition SATSolver.h:100
llvm::SmallVector< unsigned, 0 > heap
Binary heap of ids ordered by descending score.
Definition SATSolver.h:149
double score(unsigned id) const
Compute the ordering score for one heap entry.
Definition SATSolver.h:103
bool empty() const
Definition SATSolver.h:45
void siftDown(unsigned index)
Push one entry toward the leaves until the heap property is restored.
Definition SATSolver.h:127
void swapHeapEntries(unsigned lhs, unsigned rhs)
Swap two heap slots and keep the reverse index in sync.
Definition SATSolver.h:106
llvm::SmallVectorImpl< T > & storage
The caller-owned objects indexed by heap ids.
Definition SATSolver.h:146
IndexedMaxHeap(llvm::SmallVectorImpl< T > &storage)
Definition SATSolver.h:37
llvm::SmallVector< unsigned, 0 > positions
Reverse map from id to heap slot, or InvalidIndex if absent.
Definition SATSolver.h:152
void insert(unsigned id)
Insert id if it is not already present.
Definition SATSolver.h:61
bool contains(unsigned id) const
Definition SATSolver.h:47
unsigned pop()
Remove and return the highest-scoring id.
Definition SATSolver.h:82
void siftUp(unsigned index)
Bubble one entry toward the root until the heap property is restored.
Definition SATSolver.h:113
void clear()
Remove all heap entries while keeping the underlying storage untouched.
Definition SATSolver.h:52
void resize(unsigned size)
Definition SATSolver.h:40
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
bool hasIncrementalSATSolverBackend()
Return true when at least one incremental SAT backend is available.
std::unique_ptr< IncrementalSATSolver > createZ3SATSolver()
Construct a Z3-backed incremental IPASIR-style SAT solver.
std::unique_ptr< IncrementalSATSolver > createCadicalSATSolver(const CadicalSATSolverOptions &options={})
Construct a CaDiCaL-backed incremental IPASIR-style SAT solver.
CadicalSolverConfig config
Definition SATSolver.h:202