Problem: linearsys_gf2

Your task is to implement a linear system solver for the field $GF(2)$ (integers modulo 2) and verify its correctness in Dafny.  Preconditions: Inputs: A matrix matrix (size $M \times N$) and a target vector b (size $M$), both represented using seq<int>. Domain: All elements in the input matrix and vector are guaranteed to be either 0 or 1. Dimensions: You may assume the dimensions are small (e.g., $M, N \le 100$) to keep verification tractable, though the logic should be general. Requirements: Implement the method solve_linear_system_gf2 which returns Option<seq<int>>. Goal: Find a vector $x$ (of size $N$) such that $A x \equiv b \pmod 2$. (1) Algorithm: Use standard Gaussian Elimination adapted for binary arithmetic: Field Arithmetic: Addition is equivalent to XOR (^). Multiplication is equivalent to AND (&). Row Operations: To zero out a column below a pivot, you simply XOR the current row with the pivot row (since $1 + 1 = 0$ in $GF(2)$). Pivoting: If the current diagonal element is 0, find a row below it with a 1 in that column and swap. Output: Return Some(x) if a valid solution vector is found. Return None if the system is inconsistent (i.e., row reduction leads to an equation of the form $0 = 1$). Verification Challenges: (1) Solution Set Preservation: You must prove that every elementary row operation (swapping rows, XORing one row into another) preserves the set of solutions. This implies that if $x$ is a solution to the transformed system, it is also a solution to the original system. (2) Completeness (The None Case): The most difficult part is verifying the negative case. If your algorithm returns None, you must prove that no vector $x$ exists that satisfies the original equation. This typically requires showing that the row operations derived a logical contradiction (like $0=1$) implied by the original constraints. (3) Field Axioms: SMT solvers treat integers as standard arithmetic by default. You may need to verify or hint small lemmas about GF(2) properties (e.g., $a + a = 0$ or $(a - b) \equiv (a + b) \pmod 2$) to justify the correctness of your update steps.

// Following is the block for necessary definitions
// <preamble>
// 1. Field Arithmetic Helpers (GF(2))
function add_gf2(a: int, b: int): int {
    (a + b) % 2
}

function mul_gf2(a: int, b: int): int {
    (a * b) % 2
}

// 2. Validity Checks
predicate is_binary_vector(v: seq<int>) {
    forall i :: 0 <= i < |v| ==> (v[i] == 0 || v[i] == 1)
}

predicate is_binary_matrix(m: seq<seq<int>>, rows: int, cols: int) {
    |m| == rows &&
    // Added trigger { |m[i]| } implicitly via access or explicit if needed
    (forall i :: 0 <= i < rows ==> |m[i]| == cols) &&
    (forall i, j :: 0 <= i < rows && 0 <= j < cols 
        ==> (m[i][j] == 0 || m[i][j] == 1))
}

// 3. Dot Product Specification (Row * Vector)
// Recursive definition matching the Verus spec
function spec_dot_product_gf2(row: seq<int>, x: seq<int>, k: int): int
    decreases if k < 0 then 0 else k + 1
{
    if k < 0 then
        0
    else
        // Bounds check logic from Verus spec
        if k < |row| && k < |x| then
            add_gf2(
                mul_gf2(row[k], x[k]),
                spec_dot_product_gf2(row, x, k - 1)
            )
        else
            spec_dot_product_gf2(row, x, k - 1)
}

// 4. Matrix-Vector Multiplication Specification
predicate is_solution(a: seq<seq<int>>, b: seq<int>, x: seq<int>) {
    |a| == |b| &&
    |a| > 0 &&
    |x| == |a[0]| &&
    is_binary_vector(x) &&
    (forall i :: 0 <= i < |a| ==> 
        spec_dot_product_gf2(a[i], x, |x| - 1) == b[i])
}

// --- Type Conversion Helpers ---
// Dafny uses 'int' natively, so these are identity functions essentially,
// but kept to match the structure if we were wrapping types.
// Since the input is already seq<seq<int>>, we don't strictly need them
// but we define identity mappings for structural alignment.

function to_int_vec(s: seq<int>): seq<int> {
    s
}

function to_int_mat(s: seq<seq<int>>): seq<seq<int>> {
    s
}
// </preamble>

// Following is the block for potential helper specifications
// <helpers>

// </helpers>

// Following is the block for proofs of lemmas
// <proofs>

// </proofs>

// Following is the block for the main specification
// <spec>
// We use 'Option' pattern via a datatype in Dafny
datatype Option<T> = Some(value: T) | None

method solve_linear_system_gf2(matrix: seq<seq<int>>, b: seq<int>) returns (res: Option<seq<int>>)
    requires |matrix| > 0
    requires |matrix[0]| > 0
    requires |matrix| == |b|
    requires |matrix| <= 100
    requires |matrix[0]| <= 100
    requires is_binary_matrix(matrix, |matrix|, |matrix[0]|)
    requires is_binary_vector(b)
    
    ensures match res
        case Some(x) => is_solution(matrix, b, x)
        case None => 
            forall x: seq<int> :: 
                (|x| == |matrix[0]| && is_binary_vector(x)) 
                ==> !is_solution(matrix, b, x)
// </spec>
// <code>
{
    // Implement and verify the GF(2) linear system solver here.
}
// </code>

method Main() {}