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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
//! Advanced clause database maintenance and cleaning
//!
//! This module provides utilities for maintaining clause quality through:
//! - Periodic clause cleaning (duplicate removal, normalization)
//! - Advanced reduction strategies
//! - Clause tier optimization
//! - Memory compaction
use crate::clause::{ClauseDatabase, ClauseId, ClauseTier};
use crate::literal::LBool;
#[allow(unused_imports)]
use crate::prelude::*;
/// Statistics for clause maintenance operations
#[derive(Debug, Clone, Default)]
pub struct MaintenanceStats {
/// Number of duplicates removed
pub duplicates_removed: usize,
/// Number of tautologies detected
pub tautologies_removed: usize,
/// Number of clauses strengthened
pub clauses_strengthened: usize,
/// Number of tier promotions
pub tier_promotions: usize,
/// Number of tier demotions
pub tier_demotions: usize,
/// Total maintenance operations
pub operations: usize,
}
impl MaintenanceStats {
/// Display maintenance statistics
pub fn display(&self) {
println!("Clause Maintenance Statistics:");
println!(" Operations: {}", self.operations);
println!(" Duplicates removed: {}", self.duplicates_removed);
println!(" Tautologies removed: {}", self.tautologies_removed);
println!(" Clauses strengthened: {}", self.clauses_strengthened);
println!(" Tier promotions: {}", self.tier_promotions);
println!(" Tier demotions: {}", self.tier_demotions);
}
}
/// Clause maintenance manager
#[derive(Debug)]
pub struct ClauseMaintenance {
/// Statistics
stats: MaintenanceStats,
/// Clause IDs to clean
cleanup_queue: Vec<ClauseId>,
}
impl Default for ClauseMaintenance {
fn default() -> Self {
Self::new()
}
}
impl ClauseMaintenance {
/// Create a new clause maintenance manager
#[must_use]
pub fn new() -> Self {
Self {
stats: MaintenanceStats::default(),
cleanup_queue: Vec::new(),
}
}
/// Get statistics
#[must_use]
pub fn stats(&self) -> &MaintenanceStats {
&self.stats
}
/// Queue a clause for cleaning
pub fn queue_for_cleanup(&mut self, clause_id: ClauseId) {
self.cleanup_queue.push(clause_id);
}
/// Perform periodic maintenance on the clause database
///
/// This performs various cleaning operations:
/// - Remove duplicate literals
/// - Detect and remove tautologies
/// - Normalize clause representation
/// - Update tier assignments based on usage
pub fn periodic_maintenance(
&mut self,
clauses: &mut ClauseDatabase,
assignments: &[LBool],
) -> Vec<ClauseId> {
self.stats.operations += 1;
let mut removed_clauses = Vec::new();
// Process cleanup queue
let queue: Vec<_> = self.cleanup_queue.drain(..).collect();
for clause_id in queue {
if let Some(clause) = clauses.get_mut(clause_id) {
if clause.deleted {
continue;
}
let old_len = clause.lits.len();
// Normalize clause (remove duplicates, sort, check tautology)
if clause.normalize() {
// Tautology detected - remove clause
clauses.remove(clause_id);
removed_clauses.push(clause_id);
self.stats.tautologies_removed += 1;
continue;
}
// Track if duplicates were removed
if clause.lits.len() < old_len {
self.stats.duplicates_removed += old_len - clause.lits.len();
}
// Strengthen clause by removing falsified literals
if self.strengthen_clause(clause, assignments) {
self.stats.clauses_strengthened += 1;
}
// Optimize tier based on usage and quality
self.optimize_tier(clause);
}
}
// Compact the database periodically
clauses.compact();
removed_clauses
}
/// Strengthen a clause by removing falsified literals
///
/// Returns true if the clause was modified
fn strengthen_clause(&self, clause: &mut crate::clause::Clause, assignments: &[LBool]) -> bool {
let original_len = clause.lits.len();
clause.lits.retain(|lit| {
let var_idx = lit.var().index();
if var_idx >= assignments.len() {
return true; // Keep unassigned variables
}
let value = assignments[var_idx];
// Keep literal if variable is undefined
if value == LBool::Undef {
return true;
}
// A literal is falsified if:
// - Variable is True and literal is negative
// - Variable is False and literal is positive
let is_falsified =
(value == LBool::True && lit.is_neg()) || (value == LBool::False && !lit.is_neg());
!is_falsified
});
clause.lits.len() < original_len
}
/// Optimize clause tier based on usage and quality metrics
fn optimize_tier(&mut self, clause: &mut crate::clause::Clause) {
if !clause.learned {
return;
}
let old_tier = clause.tier;
// Promotion criteria:
// - High usage count
// - Low LBD (high quality)
// - Small size
if clause.tier == ClauseTier::Local {
// Promote Local -> Mid if used frequently or has good LBD
if clause.usage_count >= 3 || (clause.lbd <= 3 && clause.usage_count >= 2) {
clause.tier = ClauseTier::Mid;
self.stats.tier_promotions += 1;
}
} else if clause.tier == ClauseTier::Mid {
// Promote Mid -> Core if very high usage or excellent LBD
if clause.usage_count >= 10
|| clause.lbd <= 2
|| (clause.lbd <= 3 && clause.usage_count >= 5)
{
clause.tier = ClauseTier::Core;
self.stats.tier_promotions += 1;
}
}
// Demotion criteria:
// - Low activity for extended period
// - High LBD with low usage
if clause.tier == ClauseTier::Mid && clause.activity < 0.1 && clause.usage_count < 2 {
clause.tier = ClauseTier::Local;
self.stats.tier_demotions += 1;
}
// Track tier changes in clause
if old_tier != clause.tier {
clause.usage_count = 0; // Reset usage counter on tier change
}
}
/// Advanced clause reduction strategy
///
/// Identifies clauses to delete based on multiple criteria:
/// - Activity
/// - LBD
/// - Tier
/// - Size
/// - Age (usage count as proxy)
///
/// Returns a list of clause IDs that should be deleted
pub fn select_clauses_for_deletion(
&self,
clauses: &ClauseDatabase,
target_count: usize,
) -> Vec<ClauseId> {
let mut candidates: Vec<(ClauseId, f64)> = Vec::new();
// Collect learned clauses with quality scores
for i in 0..clauses.num_learned() {
let clause_id = ClauseId::new(i as u32);
if let Some(clause) = clauses.get(clause_id) {
if clause.deleted || !clause.learned {
continue;
}
// Skip Core tier clauses (protected)
if clause.tier == ClauseTier::Core {
continue;
}
// Compute deletion priority (higher = more likely to delete)
// Factors:
// - Low activity (weight: 0.4)
// - High LBD (weight: 0.3)
// - Large size (weight: 0.2)
// - Tier (weight: 0.1)
let activity_score = 1.0 - clause.activity.min(1.0);
let lbd_score = (clause.lbd as f64 / 20.0).min(1.0);
let size_score = ((clause.len() - 2) as f64 / 20.0).min(1.0);
let tier_score = match clause.tier {
ClauseTier::Core => 0.0, // Protected
ClauseTier::Mid => 0.3, // Less likely to delete
ClauseTier::Local => 1.0, // Most likely to delete
};
let score =
activity_score * 0.4 + lbd_score * 0.3 + size_score * 0.2 + tier_score * 0.1;
candidates.push((clause_id, score));
}
}
// Sort by score (highest first = most deletable)
candidates.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(core::cmp::Ordering::Equal));
// Return top candidates up to target_count
candidates
.into_iter()
.take(target_count)
.map(|(id, _)| id)
.collect()
}
/// Reset statistics
pub fn reset_stats(&mut self) {
self.stats = MaintenanceStats::default();
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::clause::Clause;
use crate::literal::{Lit, Var};
#[test]
fn test_maintenance_stats() {
let mut maintenance = ClauseMaintenance::new();
maintenance.stats.operations = 10;
maintenance.stats.duplicates_removed = 5;
let stats = maintenance.stats();
assert_eq!(stats.operations, 10);
assert_eq!(stats.duplicates_removed, 5);
}
#[test]
fn test_tier_optimization() {
let mut maintenance = ClauseMaintenance::new();
let mut clause = Clause::learned([Lit::pos(Var::new(0)), Lit::pos(Var::new(1))]);
clause.usage_count = 3;
clause.lbd = 3;
maintenance.optimize_tier(&mut clause);
// Should be promoted from Local to Mid
assert_eq!(clause.tier, ClauseTier::Mid);
assert_eq!(maintenance.stats.tier_promotions, 1);
}
#[test]
fn test_clause_strengthening() {
let maintenance = ClauseMaintenance::new();
let mut clause = Clause::learned([
Lit::pos(Var::new(0)),
Lit::pos(Var::new(1)),
Lit::pos(Var::new(2)),
]);
let mut assignments = vec![LBool::Undef; 3];
assignments[1] = LBool::False; // Var(1) is false
// Lit::pos(Var::new(1)) should be removed since Var(1) is false
let modified = maintenance.strengthen_clause(&mut clause, &assignments);
assert!(modified);
assert_eq!(clause.len(), 2);
}
#[test]
fn test_deletion_selection() {
let mut db = ClauseDatabase::new();
let maintenance = ClauseMaintenance::new();
// Add some learned clauses with different properties
let mut c1 = Clause::learned([Lit::pos(Var::new(0)), Lit::pos(Var::new(1))]);
c1.activity = 0.1; // Low activity
c1.lbd = 10; // High LBD
let _id1 = db.add(c1);
let mut c2 = Clause::learned([Lit::pos(Var::new(2)), Lit::pos(Var::new(3))]);
c2.activity = 0.9; // High activity
c2.lbd = 2; // Low LBD
c2.promote_to_core(); // Protected
let _id2 = db.add(c2);
let to_delete = maintenance.select_clauses_for_deletion(&db, 1);
// Should select c1 for deletion (low activity, high LBD, not protected)
assert_eq!(to_delete.len(), 1);
}
}