elementary-row-operation-verifier 0.0.1

A tool to verify the correctness of elementary row operations on matrices
Documentation
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),
        }
    }
}