1use crate::error::{Fault, RuntimeError};
5use crate::weight::Weight;
6use probl_syntax::Span;
7
8#[derive(Clone, Debug, Default)]
10pub struct Failures {
11 pub groups: Vec<Failure>,
13 pub weight: Weight,
15 pub squares: Weight,
17 pub runs: u64,
19 pub before_evidence: bool,
23 pub densities: Option<u32>,
27 pub mixed_densities: bool,
28 pub other_units: bool,
32}
33
34#[derive(Clone, Debug)]
36pub struct Failure {
37 pub error: RuntimeError,
39 pub weight: Weight,
40 pub squares: Weight,
42 pub runs: u64,
45 pub first_run: Option<u32>,
46 pub before_evidence: bool,
48}
49
50impl Failures {
51 pub fn is_empty(&self) -> bool {
52 self.groups.is_empty()
53 }
54
55 pub fn comparable(&self) -> bool {
57 !self.before_evidence && !self.other_units
58 }
59
60 fn note_densities(&mut self, n: u32) {
61 match self.densities {
62 Some(m) if m != n => self.mixed_densities = true,
63 _ => self.densities = Some(n),
64 }
65 }
66
67 pub fn record(
70 &mut self,
71 error: RuntimeError,
72 weight: Weight,
73 run: Option<u32>,
74 before_evidence: bool,
75 densities: u32,
76 ) {
77 self.note_densities(densities);
78 let runs = run.is_some() as u64;
79 let squares = if run.is_some() { weight * weight } else { Weight::ZERO };
80 self.weight += weight;
81 self.squares += squares;
82 self.runs += runs;
83 self.before_evidence |= before_evidence;
84 let (span, fault) = (error.span, error.fault);
85 match self.group(span, fault) {
86 Some(g) => {
87 g.weight += weight;
88 g.squares += squares;
89 g.runs += runs;
90 g.before_evidence |= before_evidence;
91 }
92 None => self.groups.push(Failure {
93 error,
94 weight,
95 squares,
96 runs,
97 first_run: run,
98 before_evidence,
99 }),
100 }
101 }
102
103 pub fn absorb(&mut self, other: &Failures, times: Weight, run: Option<u32>, before_evidence: bool) {
108 for theirs in &other.groups {
109 self.absorb_group(theirs, times, run, before_evidence, other.densities.unwrap_or(0));
110 }
111 self.mixed_densities |= other.mixed_densities;
112 }
113
114 pub fn absorb_group(
117 &mut self,
118 theirs: &Failure,
119 times: Weight,
120 run: Option<u32>,
121 before_evidence: bool,
122 densities: u32,
123 ) {
124 self.note_densities(densities);
125 let weight = theirs.weight * times;
126 let squares = theirs.squares * times * times;
127 let before_evidence = theirs.before_evidence || before_evidence;
128 self.weight += weight;
129 self.squares += squares;
130 self.runs += theirs.runs;
131 self.before_evidence |= before_evidence;
132 match self.group(theirs.error.span, theirs.error.fault) {
133 Some(g) => {
134 g.weight += weight;
135 g.squares += squares;
136 g.runs += theirs.runs;
137 g.before_evidence |= before_evidence;
138 }
139 None => self.groups.push(Failure {
140 error: theirs.error.clone(),
141 weight,
142 squares,
143 runs: theirs.runs,
144 first_run: run.or(theirs.first_run),
145 before_evidence,
146 }),
147 }
148 }
149
150 pub fn append(&mut self, later: Failures) {
152 self.weight += later.weight;
153 self.squares += later.squares;
154 self.runs += later.runs;
155 self.before_evidence |= later.before_evidence;
156 if let Some(n) = later.densities {
157 self.note_densities(n);
158 }
159 self.mixed_densities |= later.mixed_densities;
160 self.other_units |= later.other_units;
161 for theirs in later.groups {
162 match self.group(theirs.error.span, theirs.error.fault) {
163 Some(g) => {
164 g.weight += theirs.weight;
165 g.squares += theirs.squares;
166 g.runs += theirs.runs;
167 g.before_evidence |= theirs.before_evidence;
168 }
169 None => self.groups.push(theirs),
170 }
171 }
172 }
173
174 fn group(&mut self, span: Span, fault: Option<Fault>) -> Option<&mut Failure> {
175 self.groups
176 .iter_mut()
177 .find(|g| g.error.span == span && g.error.fault == fault)
178 }
179}