1use crate::decisions::{Decisions, SolverBug};
5use crate::package::Package;
6use crate::platform_filter::PlatformRequirementFilter;
7use crate::policy::DefaultPolicy;
8use crate::pool::{Pool, Request};
9use crate::rule::{Reason, Rule, RuleKind, RuleSet, RuleType};
10use crate::rules_gen::RuleSetGenerator;
11use crate::transaction::LockTransaction;
12use crate::watch::{RuleWatchGraph, RuleWatchNode};
13use std::collections::{HashMap, HashSet};
14
15#[derive(Debug, Clone, Default)]
17pub struct Problem {
18 pub sections: Vec<Vec<ProblemRule>>,
22 seen: HashSet<usize>,
23 pending_section: bool,
24}
25
26#[derive(Debug, Clone)]
27pub enum ProblemRule {
28 InSet(usize),
29 Detached(Rule),
30}
31
32impl Problem {
33 pub fn new() -> Problem {
34 Problem {
35 sections: Vec::new(),
36 seen: HashSet::new(),
37 pending_section: true,
38 }
39 }
40
41 fn push(&mut self, rule: ProblemRule) {
42 if self.pending_section || self.sections.is_empty() {
43 self.sections.push(Vec::new());
44 self.pending_section = false;
45 }
46 let last = self.sections.len() - 1;
47 self.sections[last].push(rule);
48 }
49
50 pub fn add_rule(&mut self, rule: usize) {
51 if !self.seen.insert(rule) {
52 return;
53 }
54 self.push(ProblemRule::InSet(rule));
55 }
56
57 pub fn add_detached(&mut self, rule: Rule) {
58 self.push(ProblemRule::Detached(rule));
59 }
60
61 pub fn next_section(&mut self) {
62 self.pending_section = true;
63 }
64}
65
66#[derive(Debug, thiserror::Error)]
67pub enum SolveError {
68 #[error("{0}")]
69 Bug(String),
70 #[error("Your requirements could not be resolved to an installable set of packages.")]
71 Problems(Vec<Problem>),
72}
73
74impl From<SolverBug> for SolveError {
75 fn from(e: SolverBug) -> SolveError {
76 SolveError::Bug(e.0)
77 }
78}
79
80pub struct Solver<'a> {
81 pool: &'a Pool,
82 arena: &'a [Package],
83 pub rules: RuleSet,
84 watch_graph: RuleWatchGraph,
85 pub decisions: Decisions,
86 fixed_map: HashSet<usize>,
87 propagate_index: usize,
88 branches: Vec<(Vec<i64>, i64)>,
90 pub problems: Vec<Problem>,
91 learned_pool: Vec<Vec<usize>>,
93 learned_why: HashMap<usize, usize>,
95}
96
97impl<'a> Solver<'a> {
98 pub fn new(pool: &'a Pool, arena: &'a [Package]) -> Solver<'a> {
99 Solver {
100 pool,
101 arena,
102 rules: RuleSet::new(),
103 watch_graph: RuleWatchGraph::new(),
104 decisions: Decisions::new(pool.len()),
105 fixed_map: HashSet::new(),
106 propagate_index: 0,
107 branches: Vec::new(),
108 problems: Vec::new(),
109 learned_pool: Vec::new(),
110 learned_why: HashMap::new(),
111 }
112 }
113
114 pub fn rule_set_size(&self) -> usize {
115 self.rules.len()
116 }
117
118 fn make_assertion_rule_decisions(&mut self) -> Result<(), SolveError> {
120 let decision_start = self.decisions.len() as i64 - 1;
121 let rules_count = self.rules.len();
122 let mut rule_index: i64 = 0;
123 while (rule_index as usize) < rules_count {
124 let id = self.rules.rule_by_id[rule_index as usize];
125 rule_index += 1;
126 let rule = &self.rules.rules[id];
127 if !rule.is_assertion() || rule.disabled {
128 continue;
129 }
130 let literal = rule.literals[0];
131 if !self.decisions.decided(literal) {
132 self.decisions.decide(literal, 1, id)?;
133 continue;
134 }
135 if self.decisions.satisfy(literal) {
136 continue;
137 }
138 if rule.rule_type == Some(RuleType::Learned) {
139 self.rules.rules[id].disabled = true;
140 continue;
141 }
142 let conflict = self.decisions.decision_rule(literal)?;
143 if self.rules.rules[conflict].rule_type == Some(RuleType::Package) {
144 let mut problem = Problem::new();
145 problem.add_rule(id);
146 problem.add_rule(conflict);
147 self.rules.rules[id].disabled = true;
148 self.problems.push(problem);
149 continue;
150 }
151 let mut problem = Problem::new();
152 problem.add_rule(id);
153 problem.add_rule(conflict);
154 for &assert_id in self.rules.ids_of_type(RuleType::Request).to_vec().iter() {
155 let assert_rule = &self.rules.rules[assert_id];
156 if assert_rule.disabled || !assert_rule.is_assertion() {
157 continue;
158 }
159 if literal.abs() != assert_rule.literals[0].abs() {
160 continue;
161 }
162 problem.add_rule(assert_id);
163 self.rules.rules[assert_id].disabled = true;
164 }
165 self.problems.push(problem);
166 self.decisions.reset_to_offset(decision_start);
167 rule_index = 0;
168 }
169 Ok(())
170 }
171
172 fn check_for_filter_list_removed_locked_packages(&mut self, request: &Request) {
175 for idx in request.locked_packages_all() {
176 let p = &self.arena[idx];
177 if !self.pool.is_filter_list_removed(&p.name, &p.version) {
178 continue;
179 }
180 let mut problem = Problem::new();
181 problem.add_detached(Rule::generic(
182 Vec::new(),
183 Reason::LockedFilterListRemoved { package: idx },
184 ));
185 self.problems.push(problem);
186 }
187 }
188
189 fn check_for_root_require_problems(
191 &mut self,
192 request: &Request,
193 filter: &PlatformRequirementFilter,
194 ) {
195 for (name, constraint) in request.requires.iter() {
196 if filter.is_ignored(name) {
197 continue;
198 }
199 let constraint = filter.filter_constraint(name, constraint, true);
200 if self
201 .pool
202 .what_provides(self.arena, name, Some(&constraint))
203 .is_empty()
204 {
205 let mut problem = Problem::new();
206 problem.add_detached(Rule::generic(
207 Vec::new(),
208 Reason::RootRequire {
209 package_name: name.clone(),
210 constraint,
211 },
212 ));
213 self.problems.push(problem);
214 }
215 }
216 }
217
218 pub fn solve(
220 &mut self,
221 request: &Request,
222 policy: &mut DefaultPolicy,
223 filter: &PlatformRequirementFilter,
224 ) -> Result<LockTransaction, SolveError> {
225 self.fixed_map = request
226 .fixed_packages
227 .iter()
228 .filter_map(|&idx| self.pool.id_of(idx))
229 .collect();
230 let generator = RuleSetGenerator::new(self.pool, self.arena);
231 self.rules = generator
232 .rules_for(request, filter)
233 .map_err(|e| SolveError::Bug(e.0))?;
234 self.check_for_root_require_problems(request, filter);
235 self.check_for_filter_list_removed_locked_packages(request);
236 self.decisions = Decisions::new(self.pool.len());
237 self.watch_graph = RuleWatchGraph::new();
238 for id in self.rules.ids_in_iterator_order() {
239 let node = RuleWatchNode::new(&self.rules, id);
240 self.watch_graph.insert(&self.rules, node);
241 }
242 self.make_assertion_rule_decisions()?;
243 self.run_sat(policy)?;
244 if !self.problems.is_empty() {
245 return Err(SolveError::Problems(std::mem::take(&mut self.problems)));
246 }
247 Ok(LockTransaction::new(
248 self.pool,
249 self.arena,
250 request,
251 &self.decisions,
252 ))
253 }
254
255 fn propagate(&mut self, level: i64) -> Result<Option<usize>, SolveError> {
257 while self.decisions.valid_offset(self.propagate_index) {
258 let decision = self.decisions.at_offset(self.propagate_index);
259 let conflict = self.watch_graph.propagate_literal(
260 &self.rules,
261 decision.literal,
262 level,
263 &mut self.decisions,
264 )?;
265 self.propagate_index += 1;
266 if conflict.is_some() {
267 return Ok(conflict);
268 }
269 }
270 Ok(None)
271 }
272
273 fn revert(&mut self, level: i64) {
275 while !self.decisions.is_empty() {
276 let literal = self.decisions.last_literal();
277 if self.decisions.undecided(literal) {
278 break;
279 }
280 let decision_level = self.decisions.decision_level(literal);
281 if decision_level <= level {
282 break;
283 }
284 self.decisions.revert_last();
285 self.propagate_index = self.decisions.len();
286 }
287 while self.branches.last().is_some_and(|(_, l)| *l >= level) {
288 self.branches.pop();
289 }
290 }
291
292 fn set_propagate_learn(
294 &mut self,
295 mut level: i64,
296 literal: i64,
297 rule: usize,
298 ) -> Result<i64, SolveError> {
299 level += 1;
300 self.decisions.decide(literal, level, rule)?;
301 loop {
302 let Some(conflict) = self.propagate(level)? else {
303 break;
304 };
305 if level == 1 {
306 self.analyze_unsolvable(conflict);
307 return Ok(0);
308 }
309 let (learn_literal, new_level, new_rule, why) = self.analyze(level, conflict)?;
310 if new_level <= 0 || new_level >= level {
311 return Err(SolveError::Bug(format!(
312 "Trying to revert to invalid level {new_level} from level {level}."
313 )));
314 }
315 level = new_level;
316 self.revert(level);
317 let (new_id, _) = self.rules.add(new_rule, RuleType::Learned);
321 self.learned_why.insert(new_id, why);
322 let mut node = RuleWatchNode::new(&self.rules, new_id);
323 node.watch2_on_highest(&self.rules, &self.decisions);
324 self.watch_graph.insert(&self.rules, node);
325 self.decisions.decide(learn_literal, level, new_id)?;
326 }
327 Ok(level)
328 }
329
330 fn select_and_install(
332 &mut self,
333 level: i64,
334 decision_queue: &[i64],
335 rule: usize,
336 policy: &mut DefaultPolicy,
337 ) -> Result<i64, SolveError> {
338 let required = self.rules.rules[rule]
339 .required_package(self.arena)
340 .map(str::to_owned);
341 let mut literals = policy.select_preferred_packages(
342 self.pool,
343 self.arena,
344 decision_queue,
345 required.as_deref(),
346 );
347 let selected = literals.remove(0);
348 if !literals.is_empty() {
349 self.branches.push((literals, level));
350 }
351 self.set_propagate_learn(level, selected, rule)
352 }
353
354 fn analyze(&mut self, level: i64, rule: usize) -> Result<(i64, i64, Rule, usize), SolveError> {
356 let analyzed_rule = rule;
357 let mut rule = rule;
358 let mut rule_level: i64 = 1;
359 let mut num = 0;
360 let mut l1num = 0;
361 let mut seen: HashSet<i64> = HashSet::new();
362 let mut learned_literal: Option<i64> = None;
363 let mut other_learned_literals: Vec<i64> = Vec::new();
364 let mut decision_id = self.decisions.len() as i64;
365 self.learned_pool.push(Vec::new());
366 let why = self.learned_pool.len() - 1;
367 'outer: loop {
368 self.learned_pool[why].push(rule);
369 let is_multi = self.rules.rules[rule].kind == RuleKind::MultiConflict;
370 for &literal in &self.rules.rules[rule].literals {
371 if is_multi && !self.decisions.decided(literal) {
372 continue;
373 }
374 if self.decisions.satisfy(literal) {
375 continue;
376 }
377 if seen.contains(&literal.abs()) {
378 continue;
379 }
380 seen.insert(literal.abs());
381 let l = self.decisions.decision_level(literal);
382 if l == 1 {
383 l1num += 1;
384 } else if level == l {
385 num += 1;
386 } else {
387 other_learned_literals.push(literal);
388 if l > rule_level {
389 rule_level = l;
390 }
391 }
392 }
393 let mut l1retry = true;
394 let mut literal: i64;
395 while l1retry {
396 l1retry = false;
397 if num == 0 {
398 l1num -= 1;
399 if l1num == 0 {
400 break 'outer;
401 }
402 }
403 loop {
404 if decision_id <= 0 {
405 return Err(SolveError::Bug(format!(
406 "Reached invalid decision id {decision_id} while looking through rule {rule} for a literal present in the analyzed rule {analyzed_rule}."
407 )));
408 }
409 decision_id -= 1;
410 let decision = self.decisions.at_offset(decision_id as usize);
411 literal = decision.literal;
412 if seen.contains(&literal.abs()) {
413 break;
414 }
415 }
416 seen.remove(&literal.abs());
417 if num != 0 {
418 num -= 1;
419 if num == 0 {
420 learned_literal = Some(-literal);
421 if l1num == 0 {
422 break 'outer;
423 }
424 for other in &other_learned_literals {
425 seen.remove(&other.abs());
426 }
427 l1num += 1;
428 l1retry = true;
429 continue;
430 }
431 }
432 let decision = self.decisions.at_offset(decision_id as usize);
435 rule = decision.reason;
436 if self.rules.rules[rule].kind == RuleKind::MultiConflict {
437 let literals = self.rules.rules[rule].literals.clone();
438 for rule_literal in literals {
439 if !seen.contains(&rule_literal.abs())
440 && self.decisions.satisfy(-rule_literal)
441 {
442 self.learned_pool[why].push(rule);
443 let l = self.decisions.decision_level(rule_literal);
444 if l == 1 {
445 l1num += 1;
446 } else if level == l {
447 num += 1;
448 } else {
449 other_learned_literals.push(rule_literal);
450 if l > rule_level {
451 rule_level = l;
452 }
453 }
454 seen.insert(rule_literal.abs());
455 break;
456 }
457 }
458 l1retry = true;
459 }
460 }
461 let decision = self.decisions.at_offset(decision_id as usize);
462 rule = decision.reason;
463 }
464 let Some(learned_literal) = learned_literal else {
465 return Err(SolveError::Bug(format!(
466 "Did not find a learnable literal in analyzed rule {analyzed_rule}."
467 )));
468 };
469 other_learned_literals.insert(0, learned_literal);
470 let new_rule = Rule::generic(other_learned_literals, Reason::Learned(why));
471 Ok((learned_literal, rule_level, new_rule, why))
472 }
473
474 fn analyze_unsolvable_rule(
476 &self,
477 problem: &mut Problem,
478 conflict_rule: usize,
479 rule_seen: &mut HashSet<usize>,
480 ) {
481 rule_seen.insert(conflict_rule);
482 let rule = &self.rules.rules[conflict_rule];
483 if rule.rule_type == Some(RuleType::Learned) {
484 let learned_why = self.learned_why[&conflict_rule];
485 let problem_rules = self.learned_pool[learned_why].clone();
486 for problem_rule in problem_rules {
487 if !rule_seen.contains(&problem_rule) {
488 self.analyze_unsolvable_rule(problem, problem_rule, rule_seen);
489 }
490 }
491 return;
492 }
493 if rule.rule_type == Some(RuleType::Package) {
494 return;
495 }
496 problem.next_section();
497 problem.add_rule(conflict_rule);
498 }
499
500 fn analyze_unsolvable(&mut self, conflict_rule: usize) {
502 let mut problem = Problem::new();
503 problem.add_rule(conflict_rule);
504 let mut rule_seen: HashSet<usize> = HashSet::new();
505 self.analyze_unsolvable_rule(&mut problem, conflict_rule, &mut rule_seen);
506 let mut seen: HashSet<i64> = HashSet::new();
507 for &literal in &self.rules.rules[conflict_rule].literals {
508 if self.decisions.satisfy(literal) {
509 continue;
510 }
511 seen.insert(literal.abs());
512 }
513 for i in (0..self.decisions.len()).rev() {
515 let decision = self.decisions.at_offset(i);
516 if !seen.contains(&decision.literal.abs()) {
517 continue;
518 }
519 let why = decision.reason;
520 problem.add_rule(why);
521 self.analyze_unsolvable_rule(&mut problem, why, &mut rule_seen);
522 for &literal in &self.rules.rules[why].literals {
523 if self.decisions.satisfy(literal) {
524 continue;
525 }
526 seen.insert(literal.abs());
527 }
528 }
529 self.problems.push(problem);
530 }
531
532 fn run_sat(&mut self, policy: &mut DefaultPolicy) -> Result<(), SolveError> {
534 self.propagate_index = 0;
535 let mut level: i64 = 1;
536 let mut system_level = level + 1;
537 loop {
538 if level == 1 {
539 if let Some(conflict) = self.propagate(level)? {
540 self.analyze_unsolvable(conflict);
541 return Ok(());
542 }
543 }
544 if level < system_level {
545 let request_rules: Vec<usize> = self.rules.ids_of_type(RuleType::Request).to_vec();
550 let mut position = 0;
551 let mut broke = false;
552 while position < request_rules.len() {
553 let rule_id = request_rules[position];
554 if self.rules.rules[rule_id].is_enabled() {
555 let mut decision_queue: Vec<i64> = Vec::new();
556 let mut none_satisfied = true;
557 for &literal in &self.rules.rules[rule_id].literals {
558 if self.decisions.satisfy(literal) {
559 none_satisfied = false;
560 break;
561 }
562 if literal > 0 && self.decisions.undecided(literal) {
563 decision_queue.push(literal);
564 }
565 }
566 if none_satisfied && !decision_queue.is_empty() {
567 let pruned: Vec<i64> = decision_queue
568 .iter()
569 .copied()
570 .filter(|l| self.fixed_map.contains(&(l.unsigned_abs() as usize)))
571 .collect();
572 if !pruned.is_empty() {
573 decision_queue = pruned;
574 }
575 }
576 if none_satisfied && !decision_queue.is_empty() {
577 let o_level = level;
578 level =
579 self.select_and_install(level, &decision_queue, rule_id, policy)?;
580 if level == 0 {
581 return Ok(());
582 }
583 if level <= o_level {
584 broke = true;
585 break;
586 }
587 }
588 }
589 position += 1;
590 }
591 system_level = level + 1;
592 if broke {
593 position += 1;
594 if position < request_rules.len() {
595 continue;
596 }
597 }
598 }
599 if level < system_level {
600 system_level = level;
601 }
602 let mut rules_count = self.rules.len();
603 let mut i = 0;
604 let mut n = 0;
605 while n < rules_count {
606 if i == rules_count {
607 i = 0;
608 }
609 let rule_id = self.rules.rule_by_id[i];
610 i += 1;
611 n += 1;
612 let rule = &self.rules.rules[rule_id];
613 if rule.disabled {
614 continue;
615 }
616 let mut decision_queue: Vec<i64> = Vec::new();
617 let mut skip = false;
618 for &literal in &rule.literals {
619 if literal <= 0 {
620 if !self.decisions.decided_install(literal) {
621 skip = true;
622 break;
623 }
624 } else {
625 if self.decisions.decided_install(literal) {
626 skip = true;
627 break;
628 }
629 if self.decisions.undecided(literal) {
630 decision_queue.push(literal);
631 }
632 }
633 }
634 if skip || decision_queue.len() < 2 {
635 continue;
636 }
637 level = self.select_and_install(level, &decision_queue, rule_id, policy)?;
638 if level == 0 {
639 return Ok(());
640 }
641 rules_count = self.rules.len();
642 n = 0;
643 }
644 if level < system_level {
645 continue;
646 }
647 if !self.branches.is_empty() {
648 let mut last_literal: Option<i64> = None;
649 let mut last_level: i64 = 0;
650 let mut last_branch_index = 0;
651 let mut last_branch_offset = 0;
652 for bi in (0..self.branches.len()).rev() {
653 let (literals, l) = &self.branches[bi];
654 for (offset, &literal) in literals.iter().enumerate() {
655 if literal > 0 && self.decisions.decision_level(literal) > l + 1 {
656 last_literal = Some(literal);
657 last_branch_index = bi;
658 last_branch_offset = offset;
659 last_level = *l;
660 }
661 }
662 }
663 if let Some(last_literal) = last_literal {
664 self.branches[last_branch_index]
665 .0
666 .remove(last_branch_offset);
667 level = last_level;
668 self.revert(level);
669 let why = self.decisions.last_reason();
670 level = self.set_propagate_learn(level, last_literal, why)?;
671 if level == 0 {
672 return Ok(());
673 }
674 continue;
675 }
676 }
677 break;
678 }
679 Ok(())
680 }
681}