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