use crate::math::Operator;
use crate::parser::FileParseResult;
pub struct Verifier;
impl Verifier {
pub fn new() -> Self {
Verifier
}
pub fn verify_file(&self, parsed: &FileParseResult) -> Vec<VerificationResult> {
let mut results = vec![];
let mut current = parsed.ori.clone();
for (step_idx, step) in parsed.steps.iter().enumerate() {
let diff_text = step
.ops
.iter()
.map(|(_, s)| s.as_str())
.collect::<Vec<_>>()
.join("; ");
if step.ops.is_empty() {
results.push(if current == step.expected {
VerificationResult::Correct {
line: step_idx + 1,
operation: diff_text,
}
} else {
VerificationResult::Incorrect {
line: step_idx + 1,
operation: diff_text,
expected: step.expected.clone(),
got: current.clone(),
}
});
continue;
}
let mut computed = current.clone();
let mut last_error = None;
let replaces: Vec<(usize, usize)> = step
.ops
.iter()
.filter_map(|(t, s)| {
crate::math::parse_operation(s, *t)
.ok()
.filter(|op| op.operator == Operator::Replace)
.and_then(|op| {
op.source_row()
.map(|src| (op.target.saturating_sub(1), src.saturating_sub(1)))
})
})
.collect();
if !replaces.is_empty() {
let mut new_rows: Vec<Option<nalgebra::DVector<f64>>> =
vec![None; computed.nrows()];
for &(target, source) in &replaces {
if source < computed.nrows() {
new_rows[target] = Some(computed.row(source).clone_owned().transpose());
}
}
for (i, row_opt) in new_rows.iter().enumerate() {
if let Some(row) = row_opt {
computed.set_row(i, &row.transpose());
}
}
}
for (target_1, op_str) in &step.ops {
let parsed = match crate::math::parse_operation(op_str, *target_1) {
Ok(op) => op,
Err(_) => continue,
};
if parsed.operator == Operator::Replace {
continue;
}
match crate::ops::apply(&computed, step.kind, &parsed) {
Ok(m) => computed = m,
Err(e) => {
last_error = Some(e);
break;
}
}
}
results.push(if let Some(err) = last_error {
VerificationResult::Error {
line: step_idx + 1,
operation: diff_text,
message: err,
}
} else if computed == step.expected {
VerificationResult::Correct {
line: step_idx + 1,
operation: diff_text,
}
} else {
VerificationResult::Incorrect {
line: step_idx + 1,
operation: diff_text,
expected: step.expected.clone(),
got: computed.clone(),
}
});
current = computed;
}
results
}
}
#[derive(Debug, Clone)]
pub enum VerificationResult {
Correct {
line: usize,
operation: String,
},
Incorrect {
line: usize,
operation: String,
expected: crate::matrix::Matrix,
got: crate::matrix::Matrix,
},
Error {
line: usize,
operation: String,
message: String,
},
}
impl std::fmt::Display for VerificationResult {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
VerificationResult::Correct { line, operation } => {
writeln!(f, "✓ Line {}: {}", line, operation)
}
VerificationResult::Incorrect {
line,
operation,
expected,
got,
} => {
writeln!(f, "✗ Line {}: {}", line, operation)?;
writeln!(f, " Expected:\n{}", expected)?;
writeln!(f, " Got:\n{}", got)
}
VerificationResult::Error {
line,
operation,
message,
} => writeln!(f, "⚠ Line {}: {} - {}", line, operation, message),
}
}
}