Skip to content

Tests

Tip

The following test code and cases also serve as usage teaching examples.

tiny_matrix_test.hpp

/**
 * @file tiny_matrix_test.hpp
 * @author SHUAIWEN CUI (SHUAIWEN001@e.ntu.edu.sg)
 * @brief This file is the header file for the test of the submodule matrix (advanced matrix operations) of the tiny_math middleware.
 * @version 1.0
 * @date 2025-04-17
 * @copyright Copyright (c) 2025
 *
 */

#pragma once

/* DEPENDENCIES */
#include "tiny_matrix.hpp" // TinyMatrix Header

/* STATEMENTS */
void tiny_matrix_test();  // C-compatible test entry

tiny_matrix_test.cpp

/**
 * @file tiny_matrix_test.cpp
 * @author SHUAIWEN CUI (SHUAIWEN001@e.ntu.edu.sg)
 * @brief This file is the source file for the test of the submodule matrix (advanced matrix operations) of the tiny_math middleware.
 * @version 1.0
 * @date 2025-04-17
 * @copyright Copyright (c) 2025
 *
 */

/* DEPENDENCIES */
#include "tiny_matrix_test.hpp" // TinyMatrix Test Header
#include "tiny_time.h"           // For performance testing

#include <iostream>
#include <iomanip>
#include <cmath>
#include <sstream>  // For std::istringstream (used in stream operator tests)

#if MCU_PLATFORM_SELECTED == MCU_PLATFORM_ESP32
#include "esp_task_wdt.h"       // For FreeRTOS task watchdog
#endif

/* PERFORMANCE TESTING MACROS */
// Reduced matrix sizes and iterations to prevent watchdog timeout and memory issues
#define PERFORMANCE_TEST_ITERATIONS 100        // Reduced from 1000 to prevent timeout
#define PERFORMANCE_TEST_ITERATIONS_HEAVY 10   // Reduced from 100 for compute-intensive operations
#define PERFORMANCE_TEST_WARMUP 3              // Reduced from 10

// Macro for timing a single operation
#define TIME_OPERATION(operation, description) \
    do { \
        TinyTimeMark_t t0 = tiny_get_running_time(); \
        operation; \
        TinyTimeMark_t t1 = tiny_get_running_time(); \
        double dt_us = (double)(t1 - t0); \
        std::cout << "[Performance] " << description << ": " << std::fixed << std::setprecision(2) << dt_us << " us\n"; \
    } while(0)

// Helper function to feed watchdog (inline to avoid function call overhead in tight loops)
#if MCU_PLATFORM_SELECTED == MCU_PLATFORM_ESP32
// Static flag to track if task has been added to watchdog
static bool task_wdt_added = false;

inline void ensure_task_wdt_added()
{
    if (!task_wdt_added)
    {
        esp_task_wdt_add(NULL);  // Add current task to watchdog (NULL = current task)
        task_wdt_added = true;
    }
}

inline void feed_watchdog()
{
    ensure_task_wdt_added();
    esp_task_wdt_reset();
}

inline void feed_watchdog_if_needed(int iteration, int interval)
{
    if ((iteration + 1) % interval == 0)
    {
        feed_watchdog();
    }
}
#else
inline void feed_watchdog()
{
    // No-op for non-ESP32 platforms
}

inline void feed_watchdog_if_needed(int iteration, int interval)
{
    // No-op for non-ESP32 platforms
    (void)iteration;
    (void)interval;
}
#endif

// Macro for timing repeated operations
#define TIME_REPEATED_OPERATION(operation, iterations, description) \
    do { \
        /* Feed watchdog before starting */ \
        feed_watchdog(); \
        /* Warmup */ \
        for (int w = 0; w < PERFORMANCE_TEST_WARMUP; ++w) { \
            feed_watchdog();  /* Feed watchdog before each operation */ \
            operation; \
            feed_watchdog();  /* Feed watchdog after each operation */ \
        } \
        /* Actual test */ \
        TinyTimeMark_t perf_t0 = tiny_get_running_time(); \
        for (int i = 0; i < iterations; ++i) { \
            /* Feed watchdog every 10 iterations (increased interval to reduce overhead) */ \
            if (i % 10 == 0) feed_watchdog(); \
            operation; \
        } \
        feed_watchdog();  /* Final feed after loop */ \
        TinyTimeMark_t perf_t1 = tiny_get_running_time(); \
        double perf_dt_total_us = (double)(perf_t1 - perf_t0); \
        double perf_dt_avg_us = perf_dt_total_us / iterations; \
        std::cout << "[Performance] " << description << " (" << iterations << " iterations): " \
                  << std::fixed << std::setprecision(2) << perf_dt_total_us << " us total, " \
                  << perf_dt_avg_us << " us avg\n"; \
    } while(0)

// Helper function to check if two matrices are approximately equal
bool matrices_approximately_equal(const tiny::Mat &m1, const tiny::Mat &m2, float epsilon = 1e-5f)
{
    if (m1.row != m2.row || m1.col != m2.col)
        return false;

    for (int i = 0; i < m1.row; ++i)
    {
        for (int j = 0; j < m1.col; ++j)
        {
            if (std::fabs(m1(i, j) - m2(i, j)) > epsilon)
                return false;
        }
    }
    return true;
}

// ============================================================================
// A1: Constructor & Destructor
// ============================================================================
void test_constructor_destructor()
{
    std::cout << "\n[A1: Constructor & Destructor Tests]\n";

    // A1.1: default constructor
    std::cout << "[A1.1] Default Constructor\n";
    tiny::Mat mat1;
    mat1.print_info();
    mat1.print_matrix(true);

    // A1.2: constructor with rows and cols, using internal allocation
    std::cout << "[A1.2] Constructor with Rows and Cols\n";
    tiny::Mat mat2(3, 4);
    mat2.print_info();
    mat2.print_matrix(true);

    // A1.3: constructor with rows and cols, specifying stride, using internal allocation
    std::cout << "[A1.3] Constructor with Rows, Cols and Stride\n";
    tiny::Mat mat3(3, 4, 5);
    mat3.print_info();
    mat3.print_matrix(true);

    // A1.4: constructor with external data
    std::cout << "[A1.4] Constructor with External Data\n";
    float data[12] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
    tiny::Mat mat4(data, 3, 4);
    mat4.print_info();
    mat4.print_matrix(true);

    // A1.5: constructor with external data and stride
    std::cout << "[A1.5] Constructor with External Data and Stride\n";
    float data_stride[15] = {0, 1, 2, 3, 0, 4, 5, 6, 7, 0, 8, 9, 10, 11, 0};
    tiny::Mat mat5(data_stride, 3, 4, 5);
    mat5.print_info();
    mat5.print_matrix(true);

    // A1.6: copy constructor
    std::cout << "[A1.6] Copy Constructor\n";
    tiny::Mat mat6(mat5);
    mat6.print_info();
    mat6.print_matrix(true);
}

// ============================================================================
// A2: Element Access
// ============================================================================
void test_element_access()
{
    std::cout << "\n[A2: Element Access Tests]\n";
    tiny::Mat mat(2, 3);

    // A2.1: non-const access
    std::cout << "[A2.1] Non-const Access\n";
    mat(0, 0) = 1.1f;
    mat(0, 1) = 2.2f;
    mat(0, 2) = 3.3f;
    mat(1, 0) = 4.4f;
    mat(1, 1) = 5.5f;
    mat(1, 2) = 6.6f;
    mat.print_info();
    mat.print_matrix(true);

    // A2.2: const access
    std::cout << "[A2.2] Const Access\n";
    const tiny::Mat const_mat = mat;
    std::cout << "const_mat(0, 0): " << const_mat(0, 0) << "\n";
}

// ============================================================================
// A3: ROI Operations
// ============================================================================
void test_roi_operations()
{
    std::cout << "\n[A3: ROI Operations Tests]\n";

    // Material Matrices
    tiny::Mat matA(2, 3);
    for (int i = 0; i < 2; ++i)
    {
        for (int j = 0; j < 3; ++j)
        {
            matA(i, j) = i * 3 + j + 1;
            matA(i, j) = matA(i, j) / 10;
        }
    }

    float data[15] = {0, 1, 2, 3, 0, 4, 5, 6, 7, 0, 8, 9, 10, 11, 0};
    tiny::Mat matB(data, 3, 4, 5);

    tiny::Mat matC;

    std::cout << "[Material Matrices]\n";
    std::cout << "matA:\n";
    matA.print_info();
    matA.print_matrix(true);
    std::cout << "matB:\n";
    matB.print_info();
    matB.print_matrix(true);
    std::cout << "matC:\n";
    matC.print_info();
    matC.print_matrix(true);

    // A3.1: Copy ROI
    std::cout << "[A3.1] Copy ROI - Over Range Case\n";
    matB.copy_paste(matA, 1, 2);
    std::cout << "matB after copy_paste matA at (1, 2):\n";
    matB.print_matrix(true);
    std::cout << "nothing changed.\n";

    std::cout << "[A3.2] Copy ROI - Suitable Range Case\n";
    matB.copy_paste(matA, 1, 1);
    std::cout << "matB after copy_paste matA at (1, 1):\n";
    matB.print_info();
    matB.print_matrix(true);
    std::cout << "successfully copied.\n";

    // A3.3: Copy Head
    std::cout << "[A3.3] Copy Head\n";
    matC.copy_head(matB);
    std::cout << "matC after copy_head matB:\n";
    matC.print_info();
    matC.print_matrix(true);

    std::cout << "[A3.4] Copy Head - Memory Sharing Check\n"; // matB and matC share the same data pointer
    matB(0, 0) = 99.99f;
    std::cout << "matB(0, 0) = 99.99f\n";

    // A3.5: copy_paste() - Error handling - negative position
    std::cout << "\n[A3.5] copy_paste() - Error Handling - Negative Position\n";
    tiny::Mat dest1(3, 3);
    tiny::Mat src1(2, 2);
    src1(0, 0) = 1.0f; src1(0, 1) = 2.0f;
    src1(1, 0) = 3.0f; src1(1, 1) = 4.0f;
    tiny_error_t err1 = dest1.copy_paste(src1, -1, 0);
    std::cout << "copy_paste with row_pos=-1: error = " << err1 
              << " (Expected: TINY_ERR_INVALID_ARG) " 
              << (err1 == TINY_ERR_INVALID_ARG ? "[PASS]" : "[FAIL]") << "\n";
    err1 = dest1.copy_paste(src1, 0, -1);
    std::cout << "copy_paste with col_pos=-1: error = " << err1 
              << " (Expected: TINY_ERR_INVALID_ARG) " 
              << (err1 == TINY_ERR_INVALID_ARG ? "[PASS]" : "[FAIL]") << "\n";

    // A3.6: copy_paste() - Error handling - out of bounds
    std::cout << "\n[A3.6] copy_paste() - Error Handling - Out of Bounds\n";
    tiny::Mat dest2(2, 2);
    tiny::Mat src2(3, 3);  // Larger than destination
    err1 = dest2.copy_paste(src2, 0, 0);
    std::cout << "copy_paste 3x3 into 2x2 at (0,0): error = " << err1 
              << " (Expected: TINY_ERR_INVALID_ARG) " 
              << (err1 == TINY_ERR_INVALID_ARG ? "[PASS]" : "[FAIL]") << "\n";
    err1 = dest2.copy_paste(src1, 1, 1);  // src1 is 2x2, dest2 is 2x2, position (1,1) would exceed
    std::cout << "copy_paste 2x2 into 2x2 at (1,1): error = " << err1 
              << " (Expected: TINY_ERR_INVALID_ARG) " 
              << (err1 == TINY_ERR_INVALID_ARG ? "[PASS]" : "[FAIL]") << "\n";

    // A3.7: copy_paste() - Boundary case - empty source
    std::cout << "\n[A3.7] copy_paste() - Boundary Case - Empty Source Matrix\n";
    tiny::Mat dest3(3, 3);
    tiny::Mat empty_src(0, 0);
    err1 = dest3.copy_paste(empty_src, 0, 0);
    std::cout << "copy_paste empty matrix: error = " << err1 
              << " (Expected: TINY_ERR_INVALID_ARG) " 
              << (err1 == TINY_ERR_INVALID_ARG ? "[PASS]" : "[FAIL]") << "\n";

    // A3.8: copy_head() - Error handling - source owns its memory
    std::cout << "\n[A3.8] copy_head() - Error Handling - Source Owns Its Memory\n";
    tiny::Mat dest4;
    tiny::Mat owned_src(2, 2);  // Creates matrix with its own memory (ext_buff=false)
    owned_src(0, 0) = 1.0f; owned_src(0, 1) = 2.0f;
    owned_src(1, 0) = 3.0f; owned_src(1, 1) = 4.0f;
    // Note: copy_head should only work with external buffers or submatrix views
    // If source owns its memory, copy_head should return error to prevent double-free
    tiny_error_t err2 = dest4.copy_head(owned_src);
    std::cout << "copy_head from matrix with owned memory: error = " << err2 
              << " (Expected: TINY_ERR_INVALID_ARG) " 
              << (err2 == TINY_ERR_INVALID_ARG ? "[PASS]" : "[FAIL]") << "\n";
    std::cout << "matC (should be unchanged):\n";
    matC.print_info();
    matC.print_matrix(true);

    // A3.9: Get a View of ROI - low level function
    std::cout << "[A3.9] Get a View of ROI - Low Level Function\n";
    std::cout << "get a view of ROI with overrange dimensions - rows:\n";
    tiny::Mat roi1 = matB.view_roi(1, 1, 3, 2); // note here, C++ will use the copy constructor, which will copy according to the case (submatrix - shallow copy | normal - deep copy)
    std::cout << "get a view of ROI with overrange dimensions - cols:\n";
    tiny::Mat roi2 = matB.view_roi(1, 1, 2, 4); // note here, C++ will use the copy constructor, which will copy according to the case (submatrix - shallow copy | normal - deep copy)
    std::cout << "get a view of ROI with suitable dimensions:\n";
    tiny::Mat roi3 = matB.view_roi(1, 1, 2, 2); // note here, C++ will use the copy constructor, which will copy according to the case (submatrix - shallow copy | normal - deep copy)
    std::cout << "roi3:\n";
    roi3.print_info();
    roi3.print_matrix(true);

    // A3.10: Get a View of ROI - using ROI structure
    std::cout << "[A3.10] Get a View of ROI - Using ROI Structure\n";
    tiny::Mat::ROI roi_struct(1, 1, 2, 2);
    tiny::Mat roi4 = matB.view_roi(roi_struct);
    roi4.print_info();
    roi4.print_matrix(true);

    // A3.11: Copy ROI - low level function
    std::cout << "[A3.11] Copy ROI - Low Level Function\n";
    tiny::Mat mat_deep_copy = matB.copy_roi(1, 1, 2, 2);
    mat_deep_copy.print_info();
    mat_deep_copy.print_matrix(true);

    // A3.12: Copy ROI - using ROI structure
    std::cout << "[A3.12] Copy ROI - Using ROI Structure\n";
    TinyTimeMark_t tic1 = tiny_get_running_time();
    tiny::Mat::ROI roi_struct2(1, 1, 2, 2);
    tiny::Mat mat_deep_copy2 = matB.copy_roi(roi_struct2);
    TinyTimeMark_t toc1 = tiny_get_running_time();
    TinyTimeMark_t copy_roi_time = toc1 - tic1;
    std::cout << "time for copy_roi using ROI structure: " << copy_roi_time << " ms\n";
    mat_deep_copy2.print_info();
    mat_deep_copy2.print_matrix(true);

    // A3.13: ROI resize_roi() function
    std::cout << "\n[A3.13] ROI resize_roi() Function\n";
    tiny::Mat::ROI test_roi(0, 0, 2, 2);
    std::cout << "Initial ROI: pos_x=" << test_roi.pos_x << ", pos_y=" << test_roi.pos_y 
              << ", width=" << test_roi.width << ", height=" << test_roi.height << "\n";
    test_roi.resize_roi(1, 1, 3, 3);
    std::cout << "After resize_roi(1, 1, 3, 3): pos_x=" << test_roi.pos_x << ", pos_y=" << test_roi.pos_y 
              << ", width=" << test_roi.width << ", height=" << test_roi.height << "\n";
    bool roi_resize_correct = (test_roi.pos_x == 1 && test_roi.pos_y == 1 && 
                                test_roi.width == 3 && test_roi.height == 3);
    std::cout << "ROI resize test: " << (roi_resize_correct ? "[PASS]" : "[FAIL]") << "\n";

    // A3.14: ROI area_roi() function
    std::cout << "\n[A3.14] ROI area_roi() Function\n";
    tiny::Mat::ROI area_roi1(0, 0, 3, 4);
    int area1 = area_roi1.area_roi();
    std::cout << "ROI(0, 0, 3, 4) area: " << area1 << " (Expected: 12) ";
    std::cout << (area1 == 12 ? "[PASS]" : "[FAIL]") << "\n";

    tiny::Mat::ROI area_roi2(1, 2, 5, 6);
    int area2 = area_roi2.area_roi();
    std::cout << "ROI(1, 2, 5, 6) area: " << area2 << " (Expected: 30) ";
    std::cout << (area2 == 30 ? "[PASS]" : "[FAIL]") << "\n";

    // A3.15: Block
    std::cout << "[A3.15] Block\n";
    TinyTimeMark_t tic2 = tiny_get_running_time();
    tiny::Mat mat_block = matB.block(1, 1, 2, 2);
    TinyTimeMark_t toc2 = tiny_get_running_time();
    TinyTimeMark_t block_roi_time = toc2 - tic2;
    std::cout << "time for block: " << block_roi_time << " ms\n";
    mat_block.print_info();
    mat_block.print_matrix(true);

    // A3.16: Swap Rows
    std::cout << "[A3.16] Swap Rows\n";
    std::cout << "matB before swap rows:\n";
    matB.print_info();
    matB.print_matrix(true);
    std::cout << "matB after swap_rows(0, 2):\n";
    matB.swap_rows(0, 2);
    matB.print_info();
    matB.print_matrix(true);

    // A3.17: Swap Columns
    std::cout << "[A3.17] Swap Columns\n";
    std::cout << "matB before swap columns:\n";
    matB.print_info();
    matB.print_matrix(true);
    std::cout << "matB after swap_cols(0, 2):\n";
    matB.swap_cols(0, 2);
    matB.print_info();
    matB.print_matrix(true);

    // A3.18: Clear
    std::cout << "[A3.18] Clear\n";
    std::cout << "matB before clear:\n";
    matB.print_info();
    matB.print_matrix(true);
    std::cout << "matB after clear:\n";
    matB.clear();
    matB.print_info();
    matB.print_matrix(true);
}

// ============================================================================
// B1: Assignment Operator
// ============================================================================
void test_assignment_operator()
{
    std::cout << "\n[B1: Assignment Operator Tests]\n";

    std::cout << "\n[B1.1] Assignment (Same Dimensions)\n";
    tiny::Mat dst(2, 3), src(2, 3);
    for (int i = 0; i < 2; ++i)
        for (int j = 0; j < 3; ++j)
            src(i, j) = static_cast<float>(i * 3 + j + 1);
    dst = src;
    dst.print_matrix(true);

    std::cout << "\n[B1.2] Assignment (Different Dimensions)\n";
    tiny::Mat dst2(4, 2);
    dst2 = src;
    dst2.print_matrix(true);

    std::cout << "\n[B1.3] Assignment to Sub-Matrix (Expect Error)\n";
    float data[15] = {0, 1, 2, 3, 0, 4, 5, 6, 7, 0, 8, 9, 10, 11, 0};
    tiny::Mat base(data, 3, 4, 5);
    tiny::Mat subView = base.view_roi(1, 1, 2, 2);
    subView = src;
    subView.print_matrix(true);

    std::cout << "\n[B1.4] Self-Assignment\n";
    src = src;
    src.print_matrix(true);
}

// ============================================================================
// B2: Matrix Addition
// ============================================================================
void test_matrix_addition()
{
    std::cout << "\n[B2: Matrix Addition Tests]\n";

    std::cout << "\n[B2.1] Matrix Addition (Same Dimensions)\n";
    tiny::Mat A(2, 3), B(2, 3);
    for (int i = 0; i < 2; ++i)
        for (int j = 0; j < 3; ++j)
        {
            A(i, j) = static_cast<float>(i * 3 + j + 1);
            B(i, j) = 1.0f;
        }
    A += B;
    A.print_matrix(true);

    std::cout << "\n[B2.2] Sub-Matrix Addition\n";
    float data[20] = {0,1,2,3,0,4,5,6,7,0,8,9,10,11,0,12,13,14,15,0};
    tiny::Mat base(data, 4, 4, 5);
    tiny::Mat subA = base.view_roi(1,1,2,2);
    tiny::Mat subB = base.view_roi(1,1,2,2);
    subA += subB;
    subA.print_matrix(true);

    std::cout << "\n[B2.3] Full Matrix + Sub-Matrix Addition\n";
    tiny::Mat full(2,2);
    for(int i=0;i<2;++i) for(int j=0;j<2;++j) full(i,j)=2.0f;
    full += subB;
    full.print_matrix(true);

    std::cout << "\n[B2.4] Addition Dimension Mismatch (Expect Error)\n";
    tiny::Mat wrongDim(3,3);
    full += wrongDim;
}

// ============================================================================
// B3: Constant Addition
// ============================================================================
void test_constant_addition()
{
    std::cout << "\n[B3: Constant Addition Tests]\n";

    std::cout << "\n[B3.1] Full Matrix + Constant\n";
    tiny::Mat mat1(2,3);
    for (int i = 0; i < 2; ++i)
        for (int j = 0; j < 3; ++j)
            mat1(i,j) = static_cast<float>(i*3 + j);
    mat1 += 5.0f;
    mat1.print_matrix(true);

    std::cout << "\n[B3.2] Sub-Matrix + Constant\n";
    float data[20] = {0,1,2,3,0,4,5,6,7,0,8,9,10,11,0,12,13,14,15,0};
    tiny::Mat base(data,4,4,5);
    tiny::Mat sub = base.view_roi(1,1,2,2);
    sub += 3.0f;
    sub.print_matrix(true);

    std::cout << "\n[B3.3] Add Zero\n";
    tiny::Mat mat2(2,2);
    mat2(0,0)=1; mat2(0,1)=2; mat2(1,0)=3; mat2(1,1)=4;
    mat2 += 0.0f;
    mat2.print_matrix(true);

    std::cout << "\n[B3.4] Add Negative Constant\n";
    tiny::Mat mat3(2,2);
    mat3(0,0)=10; mat3(0,1)=20; mat3(1,0)=30; mat3(1,1)=40;
    mat3 += -15.0f;
    mat3.print_matrix(true);
}

// ============================================================================
// B4: Matrix Subtraction
// ============================================================================
void test_matrix_subtraction()
{
    std::cout << "\n[B4: Matrix Subtraction Tests]\n";

    std::cout << "\n[B4.1] Matrix Subtraction\n";
    tiny::Mat A(2,2), B(2,2);
    A(0,0)=5; A(0,1)=7; A(1,0)=9; A(1,1)=11;
    B(0,0)=1; B(0,1)=2; B(1,0)=3; B(1,1)=4;
    A -= B;
    A.print_matrix(true);

    std::cout << "\n[B4.2] Subtraction Dimension Mismatch (Expect Error)\n";
    tiny::Mat wrong(3,3);
    A -= wrong;
}

// ============================================================================
// B5: Constant Subtraction
// ============================================================================
void test_constant_subtraction()
{
    std::cout << "\n[B5: Constant Subtraction Tests]\n";

    std::cout << "\n[B5.1] Full Matrix - Constant\n";
    tiny::Mat mat(2,3);
    for (int i=0;i<2;++i) for(int j=0;j<3;++j) mat(i,j) = i*3+j+1;
    mat -= 2.0f;
    mat.print_matrix(true);

    std::cout << "\n[B5.2] Sub-Matrix - Constant\n";
    float data[15] = {0,1,2,3,0,4,5,6,7,0,8,9,10,11,0};
    tiny::Mat base(data,3,4,5);
    tiny::Mat sub = base.view_roi(1,1,2,2);
    sub -= 1.5f;
    sub.print_matrix(true);
}

// ============================================================================
// B6: Matrix Division
// ============================================================================
void test_matrix_division()
{
    std::cout << "\n[B6: Matrix Element-wise Division Tests]\n";

    std::cout << "\n[B6.1] Element-wise Division (Same Dimensions, No Zero)\n";
    tiny::Mat A(2, 2), B(2, 2);
    A(0,0) = 10; A(0,1) = 20; A(1,0) = 30; A(1,1) = 40;
    B(0,0) = 2;  B(0,1) = 4;  B(1,0) = 5;  B(1,1) = 8;
    A /= B;
    A.print_matrix(true);

    std::cout << "\n[B6.2] Dimension Mismatch (Expect Error)\n";
    tiny::Mat wrongDim(3, 3);
    A /= wrongDim;

    std::cout << "\n[B6.3] Division by Matrix Containing Zero (Expect Error)\n";
    tiny::Mat C(2, 2), D(2, 2);
    C(0,0)=5; C(0,1)=10; C(1,0)=15; C(1,1)=20;
    D(0,0)=1; D(0,1)=0;  D(1,0)=3;  D(1,1)=4;  // Contains zero
    C /= D;
    C.print_matrix(true);  // Should remain unchanged
}

// ============================================================================
// B7: Constant Division
// ============================================================================
void test_constant_division()
{
    std::cout << "\n[B7: Matrix Division by Constant Tests]\n";

    std::cout << "\n[B7.1] Divide Full Matrix by Positive Constant\n";
    tiny::Mat mat1(2, 3);
    for (int i = 0; i < 2; ++i)
        for (int j = 0; j < 3; ++j)
            mat1(i, j) = static_cast<float>(i * 3 + j + 2);  // Avoid zero
    mat1 /= 2.0f;
    mat1.print_matrix(true);

    std::cout << "\n[B7.2] Divide Matrix by Negative Constant\n";
    tiny::Mat mat2(2, 2);
    mat2(0,0)=6; mat2(0,1)=12; mat2(1,0)=18; mat2(1,1)=24;
    mat2 /= -3.0f;
    mat2.print_matrix(true);

    std::cout << "\n[B7.3] Division by Zero Constant (Expect Error)\n";
    tiny::Mat mat3(2, 2);
    mat3(0,0)=1; mat3(0,1)=2; mat3(1,0)=3; mat3(1,1)=4;
    mat3 /= 0.0f;
    mat3.print_matrix(true);  // Should remain unchanged
}

// ============================================================================
// B8: Matrix Exponentiation
// ============================================================================
void test_matrix_exponentiation()
{
    std::cout << "\n[B8: Matrix Exponentiation Tests]\n";

    std::cout << "\n[B8.1] Raise Each Element to Power of 2\n";
    tiny::Mat mat1(2, 2);
    mat1(0,0)=2; mat1(0,1)=3; mat1(1,0)=4; mat1(1,1)=5;
    tiny::Mat result1 = mat1 ^ 2;
    result1.print_matrix(true);

    std::cout << "\n[B8.2] Raise Each Element to Power of 0\n";
    tiny::Mat mat2(2, 2);
    mat2(0,0)=7; mat2(0,1)=-3; mat2(1,0)=0.5f; mat2(1,1)=10;
    tiny::Mat result2 = mat2 ^ 0;
    result2.print_matrix(true);  // Expect all 1

    std::cout << "\n[B8.3] Raise Each Element to Power of 1\n";
    tiny::Mat mat3(2, 2);
    mat3(0,0)=9; mat3(0,1)=8; mat3(1,0)=7; mat3(1,1)=6;
    tiny::Mat result3 = mat3 ^ 1;
    result3.print_matrix(true);  // Expect same as original

    std::cout << "\n[B8.4] Raise Each Element to Power of -1 (Expect Error or Warning)\n";
    tiny::Mat mat4(2, 2);
    mat4(0,0)=1; mat4(0,1)=2; mat4(1,0)=4; mat4(1,1)=5;
    tiny::Mat result4 = mat4 ^ -1;
    result4.print_matrix(true);

    std::cout << "\n[B8.5] Raise Matrix Containing Zero to Power of 3\n";
    tiny::Mat mat5(2, 2);
    mat5(0,0)=0; mat5(0,1)=2; mat5(1,0)=-1; mat5(1,1)=3;
    tiny::Mat result5 = mat5 ^ 3;
    result5.print_matrix(true);
}

// ============================================================================
// C1: Matrix Transpose
// ============================================================================
void test_matrix_transpose()
{
    std::cout << "\n[C1: Matrix Transpose Tests]\n";

    // C1.1: Basic 2x3 matrix transpose
    std::cout << "\n[C1.1] Transpose of 2x3 Matrix\n";
    tiny::Mat mat1(2, 3);
    int val = 1;
    for (int i = 0; i < 2; ++i)
        for (int j = 0; j < 3; ++j)
            mat1(i, j) = val++;

    std::cout << "Original 2x3 Matrix:\n";
    mat1.print_matrix(true);

    tiny::Mat transposed1 = mat1.transpose();
    std::cout << "Transposed 3x2 Matrix:\n";
    transposed1.print_matrix(true);

    // C1.2: Square matrix transpose (3x3)
    std::cout << "\n[C1.2] Transpose of 3x3 Square Matrix\n";
    tiny::Mat mat2(3, 3);
    val = 1;
    for (int i = 0; i < 3; ++i)
        for (int j = 0; j < 3; ++j)
            mat2(i, j) = val++;

    std::cout << "Original 3x3 Matrix:\n";
    mat2.print_matrix(true);

    tiny::Mat transposed2 = mat2.transpose();
    std::cout << "Transposed 3x3 Matrix:\n";
    transposed2.print_matrix(true);

    // C1.3: Matrix with padding (4x2, stride=3)
    std::cout << "\n[C1.3] Transpose of Matrix with Padding\n";
    float data[12] = {1, 2, 0, 3, 4, 0, 5, 6, 0, 7, 8, 0};  // stride=3, 4 rows
    tiny::Mat mat3(data, 4, 2, 3);
    std::cout << "Original 4x2 Matrix (with padding):\n";
    mat3.print_matrix(true);

    tiny::Mat transposed3 = mat3.transpose();
    std::cout << "Transposed 2x4 Matrix:\n";
    transposed3.print_matrix(true);

    // C1.4: Transpose of empty matrix
    std::cout << "\n[C1.4] Transpose of Empty Matrix\n";
    tiny::Mat mat4;
    mat4.print_matrix(true);

    tiny::Mat transposed4 = mat4.transpose();
    transposed4.print_matrix(true);
}

// ============================================================================
// C2: Matrix Minor and Cofactor
// ============================================================================
void test_matrix_cofactor()
{
    std::cout << "\n[C2: Matrix Minor and Cofactor Tests]\n";

    // C2.1: Minor of 3x3 Matrix - Standard Case
    std::cout << "\n[C2.1] Minor of 3x3 Matrix (Remove Row 1, Col 1)\n";
    tiny::Mat mat1(3, 3);
    int val = 1;
    for (int i = 0; i < 3; ++i)
        for (int j = 0; j < 3; ++j)
            mat1(i, j) = val++;

    std::cout << "Original 3x3 Matrix:\n";
    mat1.print_matrix(true);

    tiny::Mat minor1 = mat1.minor(1, 1);
    std::cout << "Minor Matrix (remove row 1, col 1, no sign):\n";
    minor1.print_matrix(true);  // Expected: [[1,3],[7,9]]

    // C2.2: Cofactor of 3x3 Matrix - Same position
    std::cout << "\n[C2.2] Cofactor of 3x3 Matrix (Remove Row 1, Col 1)\n";
    std::cout << "Note: Cofactor matrix is the same as minor matrix.\n";
    std::cout << "      The sign (-1)^(i+j) is applied when computing cofactor value, not to matrix elements.\n";
    tiny::Mat cof1 = mat1.cofactor(1, 1);
    std::cout << "Cofactor Matrix (same as minor):\n";
    cof1.print_matrix(true);  // Expected: [[1,3],[7,9]] (same as minor)

    // C2.3: Minor - Remove first row and first column
    std::cout << "\n[C2.3] Minor (Remove Row 0, Col 0)\n";
    tiny::Mat minor2 = mat1.minor(0, 0);
    minor2.print_matrix(true);  // Expected: [[5,6],[8,9]]

    // C2.4: Cofactor - Remove first row and first column
    std::cout << "\n[C2.4] Cofactor (Remove Row 0, Col 0)\n";
    std::cout << "Note: Cofactor matrix is the same as minor matrix.\n";
    tiny::Mat cof2 = mat1.cofactor(0, 0);
    cof2.print_matrix(true);  // Expected: [[5,6],[8,9]] (same as minor)

    // C2.5: Cofactor - Remove row 0, col 1
    std::cout << "\n[C2.5] Cofactor (Remove Row 0, Col 1)\n";
    std::cout << "Note: Cofactor matrix is the same as minor matrix.\n";
    std::cout << "      When computing cofactor value, sign (-1)^(0+1) = -1 would be applied.\n";
    tiny::Mat cof2_neg = mat1.cofactor(0, 1);
    std::cout << "Cofactor Matrix (same as minor):\n";
    cof2_neg.print_matrix(true);  // Expected: [[4,6],[7,9]] (same as minor, no sign in matrix)

    // C2.6: Minor - Remove last row and last column
    std::cout << "\n[C2.6] Minor (Remove Row 2, Col 2)\n";
    tiny::Mat minor3 = mat1.minor(2, 2);
    minor3.print_matrix(true);  // Expected: [[1,2],[4,5]]

    // C2.7: Cofactor - Remove last row and last column
    std::cout << "\n[C2.7] Cofactor (Remove Row 2, Col 2)\n";
    std::cout << "Note: Cofactor matrix is the same as minor matrix.\n";
    tiny::Mat cof3 = mat1.cofactor(2, 2);
    cof3.print_matrix(true);  // Expected: [[1,2],[4,5]] (same as minor)

    // C2.8: 4x4 Matrix Example - Minor
    std::cout << "\n[C2.8] Minor of 4x4 Matrix (Remove Row 2, Col 1)\n";
    tiny::Mat mat4(4, 4);
    val = 1;
    for (int i = 0; i < 4; ++i)
        for (int j = 0; j < 4; ++j)
            mat4(i, j) = val++;

    mat4.print_matrix(true);
    tiny::Mat minor4 = mat4.minor(2, 1);
    std::cout << "Minor Matrix:\n";
    minor4.print_matrix(true);

    // C2.9: 4x4 Matrix Example - Cofactor
    std::cout << "\n[C2.9] Cofactor of 4x4 Matrix (Remove Row 2, Col 1)\n";
    std::cout << "Note: Cofactor matrix is the same as minor matrix.\n";
    std::cout << "      When computing cofactor value, sign (-1)^(2+1) = -1 would be applied.\n";
    tiny::Mat cof4 = mat4.cofactor(2, 1);
    std::cout << "Cofactor Matrix (same as minor):\n";
    cof4.print_matrix(true);

    // C2.10: Non-square Matrix (Expect Error)
    std::cout << "\n[C2.10] Non-square Matrix (Expect Error)\n";
    tiny::Mat rectMat(3, 4);
    std::cout << "Testing minor():\n";
    tiny::Mat minor_rect = rectMat.minor(1, 1);
    bool minor_rect_empty = (minor_rect.row == 0 && minor_rect.col == 0);
    std::cout << "minor() result: " << (minor_rect_empty ? "Empty matrix (Expected)" : "Non-empty (Error)") 
              << " " << (minor_rect_empty ? "[PASS]" : "[FAIL]") << "\n";
    std::cout << "Testing cofactor():\n";
    tiny::Mat cof_rect = rectMat.cofactor(1, 1);
    bool cof_rect_empty = (cof_rect.row == 0 && cof_rect.col == 0);
    std::cout << "cofactor() result: " << (cof_rect_empty ? "Empty matrix (Expected)" : "Non-empty (Error)") 
              << " " << (cof_rect_empty ? "[PASS]" : "[FAIL]") << "\n";

    // C2.11: minor() - Boundary case - out of bounds indices
    std::cout << "\n[C2.11] minor() - Boundary Case - Out of Bounds Indices\n";
    tiny::Mat test_mat(3, 3);
    for (int i = 0; i < 3; ++i)
        for (int j = 0; j < 3; ++j)
            test_mat(i, j) = i * 3 + j + 1;

    tiny::Mat minor_out1 = test_mat.minor(-1, 0);
    bool minor_out1_empty = (minor_out1.row == 0 && minor_out1.col == 0);
    std::cout << "minor(-1, 0): " << (minor_out1_empty ? "Empty matrix (Expected)" : "Non-empty (Error)") 
              << " " << (minor_out1_empty ? "[PASS]" : "[FAIL]") << "\n";

    tiny::Mat minor_out2 = test_mat.minor(0, -1);
    bool minor_out2_empty = (minor_out2.row == 0 && minor_out2.col == 0);
    std::cout << "minor(0, -1): " << (minor_out2_empty ? "Empty matrix (Expected)" : "Non-empty (Error)") 
              << " " << (minor_out2_empty ? "[PASS]" : "[FAIL]") << "\n";

    tiny::Mat minor_out3 = test_mat.minor(3, 0);
    bool minor_out3_empty = (minor_out3.row == 0 && minor_out3.col == 0);
    std::cout << "minor(3, 0) (out of bounds): " << (minor_out3_empty ? "Empty matrix (Expected)" : "Non-empty (Error)") 
              << " " << (minor_out3_empty ? "[PASS]" : "[FAIL]") << "\n";

    // C2.12: minor() - Boundary case - 1x1 matrix
    std::cout << "\n[C2.12] minor() - Boundary Case - 1x1 Matrix\n";
    tiny::Mat mat1x1(1, 1);
    mat1x1(0, 0) = 5.0f;
    tiny::Mat minor_1x1 = mat1x1.minor(0, 0);
    bool minor_1x1_empty = (minor_1x1.row == 0 && minor_1x1.col == 0);
    std::cout << "1x1 matrix minor(0,0): " << (minor_1x1_empty ? "Empty matrix (Expected)" : "Non-empty (Error)") 
              << " " << (minor_1x1_empty ? "[PASS]" : "[FAIL]") << "\n";
}

// ============================================================================
// C3: Matrix Determinant
// ============================================================================
void test_matrix_determinant()
{
    std::cout << "\n[C3: Matrix Determinant Tests]\n";

    // C3.1: 1x1 Matrix
    std::cout << "\n[C3.1] 1x1 Matrix Determinant\n";
    tiny::Mat mat1(1, 1);
    mat1(0, 0) = 7;
    std::cout << "Matrix:\n";
    mat1.print_matrix(true);
    std::cout << "Determinant: " << mat1.determinant() << "  (Expected: 7)\n";

    // C3.2: 2x2 Matrix
    std::cout << "\n[C3.2] 2x2 Matrix Determinant\n";
    tiny::Mat mat2(2, 2);
    mat2(0, 0) = 3; mat2(0, 1) = 8;
    mat2(1, 0) = 4; mat2(1, 1) = 6;
    std::cout << "Matrix:\n";
    mat2.print_matrix(true);
    std::cout << "Determinant: " << mat2.determinant() << "  (Expected: -14)\n";

    // C3.3: 3x3 Matrix
    std::cout << "\n[C3.3] 3x3 Matrix Determinant\n";
    tiny::Mat mat3(3, 3);
    mat3(0,0) = 1; mat3(0,1) = 2; mat3(0,2) = 3;
    mat3(1,0) = 0; mat3(1,1) = 4; mat3(1,2) = 5;
    mat3(2,0) = 1; mat3(2,1) = 0; mat3(2,2) = 6;
    std::cout << "Matrix:\n";
    mat3.print_matrix(true);
    std::cout << "Determinant: " << mat3.determinant() << "  (Expected: 22)\n";

    // C3.4: 4x4 Matrix
    std::cout << "\n[C3.4] 4x4 Matrix Determinant\n";
    tiny::Mat mat4(4, 4);
    int val = 1;
    for (int i = 0; i < 4; ++i)
        for (int j = 0; j < 4; ++j)
            mat4(i, j) = val++;
    std::cout << "Matrix:\n";
    mat4.print_matrix(true);
    std::cout << "Note: This matrix has linearly dependent rows (each row differs by constant 4),\n";
    std::cout << "      so the determinant should be 0.\n";
    std::cout << "Determinant: " << mat4.determinant() << "  (Expected: 0)\n";  

    // C3.5: 5x5 Matrix (Tests Auto-select Mechanism)
    std::cout << "\n[C3.5] 5x5 Matrix Determinant (Tests Auto-select to LU Method)\n";
    tiny::Mat mat5_basic(5, 5);
    // Create a well-conditioned 5x5 matrix
    mat5_basic(0,0) = 2; mat5_basic(0,1) = 1; mat5_basic(0,2) = 0; mat5_basic(0,3) = 0; mat5_basic(0,4) = 0;
    mat5_basic(1,0) = 1; mat5_basic(1,1) = 2; mat5_basic(1,2) = 1; mat5_basic(1,3) = 0; mat5_basic(1,4) = 0;
    mat5_basic(2,0) = 0; mat5_basic(2,1) = 1; mat5_basic(2,2) = 2; mat5_basic(2,3) = 1; mat5_basic(2,4) = 0;
    mat5_basic(3,0) = 0; mat5_basic(3,1) = 0; mat5_basic(3,2) = 1; mat5_basic(3,3) = 2; mat5_basic(3,4) = 1;
    mat5_basic(4,0) = 0; mat5_basic(4,1) = 0; mat5_basic(4,2) = 0; mat5_basic(4,3) = 1; mat5_basic(4,4) = 2;
    std::cout << "Matrix (5x5, tridiagonal):\n";
    mat5_basic.print_matrix(true);
    float det5_basic = mat5_basic.determinant();
    std::cout << "Determinant (auto-select, should use LU for n > 4): " << det5_basic << "\n";
    std::cout << "Note: For n = 5 > 4, auto-select should use LU decomposition (O(n³)).\n";

    // C3.6: Non-square Matrix (Expect Error)
    std::cout << "\n[C3.6] Non-square Matrix (Expect Error)\n";
    tiny::Mat rectMat(3, 4);
    std::cout << "Matrix (3x4, non-square):\n";
    rectMat.print_matrix(true);
    float det_rect = rectMat.determinant();  // should trigger error
    std::cout << "Determinant: " << det_rect << "  (Expected: 0 with error message)\n";

    // C3.7: Comparison of Different Methods (5x5 Matrix)
    std::cout << "\n[C3.7] Comparison of Different Methods (5x5 Matrix)\n";
    tiny::Mat mat_test(5, 5);
    // Create a test matrix
    for (int i = 0; i < 5; ++i)
    {
        for (int j = 0; j < 5; ++j)
        {
            mat_test(i, j) = static_cast<float>((i + 1) * (j + 1) + (i == j ? 1.0f : 0.0f));
        }
    }
    std::cout << "Matrix (5x5):\n";
    mat_test.print_matrix(true);
    float det_auto = mat_test.determinant();
    float det_laplace = mat_test.determinant_laplace();
    float det_lu = mat_test.determinant_lu();
    float det_gaussian = mat_test.determinant_gaussian();
    std::cout << "Determinant (auto-select): " << det_auto << "  (should use LU for n > 4)\n";
    std::cout << "Determinant (Laplace):     " << det_laplace << "  (O(n!), slow for n=5)\n";
    std::cout << "Determinant (LU):          " << det_lu << "  (O(n³), efficient)\n";
    std::cout << "Determinant (Gaussian):    " << det_gaussian << "  (O(n³), efficient)\n";
    std::cout << "Note: All methods should give the same result (within numerical precision).\n";
    std::cout << "      Auto-select should use LU for n > 4, avoiding slow Laplace expansion.\n";

    // C3.8: Large Matrix (6x6) - Tests Efficient Methods
    std::cout << "\n[C3.8] Large Matrix (6x6) - Tests Efficient Methods\n";
    tiny::Mat mat6(6, 6);
    for (int i = 0; i < 6; ++i)
    {
        for (int j = 0; j < 6; ++j)
        {
            mat6(i, j) = static_cast<float>((i + 1) * (j + 1) + (i == j ? 0.5f : 0.0f));
        }
    }
    std::cout << "Matrix (6x6, showing first 4x4 block):\n";
    for (int i = 0; i < 4; ++i)
    {
        for (int j = 0; j < 4; ++j)
        {
            std::cout << std::setw(10) << mat6(i, j) << " ";
        }
        std::cout << "...\n";
    }
    std::cout << "...\n";
    float det6_auto = mat6.determinant();
    float det6_lu = mat6.determinant_lu();
    float det6_gaussian = mat6.determinant_gaussian();
    std::cout << "Determinant (auto-select, uses LU): " << det6_auto << "\n";
    std::cout << "Determinant (LU):                   " << det6_lu << "\n";
    std::cout << "Determinant (Gaussian):             " << det6_gaussian << "\n";
    std::cout << "Note: For n > 4, auto-select uses LU decomposition (O(n³) instead of O(n!)).\n";

    // C3.9: Large Matrix (8x8) - Performance Test
    std::cout << "\n[C3.9] Large Matrix (8x8) - Performance Comparison\n";
    tiny::Mat mat8(8, 8);
    for (int i = 0; i < 8; ++i)
    {
        for (int j = 0; j < 8; ++j)
        {
            mat8(i, j) = static_cast<float>((i + 1) * (j + 1));
        }
    }
    std::cout << "Matrix (8x8, showing first 4x4 block):\n";
    // Print partial matrix for display
    for (int i = 0; i < 4; ++i)
    {
        for (int j = 0; j < 4; ++j)
        {
            std::cout << std::setw(10) << mat8(i, j) << " ";
        }
        std::cout << "...\n";
    }
    std::cout << "...\n";
    float det8_lu = mat8.determinant_lu();
    float det8_gaussian = mat8.determinant_gaussian();
    std::cout << "Determinant (LU):       " << det8_lu << "\n";
    std::cout << "Determinant (Gaussian): " << det8_gaussian << "\n";
    std::cout << "Note: Both methods are O(n³) and should be much faster than Laplace expansion.\n";

    // C3.10: determinant_laplace() - Boundary case - empty matrix
    std::cout << "\n[C3.10] determinant_laplace() - Boundary Case - Empty Matrix\n";
    tiny::Mat empty_det(0, 0);
    float det_empty_laplace = empty_det.determinant_laplace();
    std::cout << "Empty matrix determinant (Laplace): " << det_empty_laplace 
              << " (Expected: 1.0) " << (fabsf(det_empty_laplace - 1.0f) < 1e-6f ? "[PASS]" : "[FAIL]") << "\n";

    // C3.11: determinant_lu() - Boundary case - empty matrix
    std::cout << "\n[C3.11] determinant_lu() - Boundary Case - Empty Matrix\n";
    float det_empty_lu = empty_det.determinant_lu();
    std::cout << "Empty matrix determinant (LU): " << det_empty_lu 
              << " (Expected: 1.0) " << (fabsf(det_empty_lu - 1.0f) < 1e-6f ? "[PASS]" : "[FAIL]") << "\n";

    // C3.12: determinant_gaussian() - Boundary case - empty matrix
    std::cout << "\n[C3.12] determinant_gaussian() - Boundary Case - Empty Matrix\n";
    float det_empty_gaussian = empty_det.determinant_gaussian();
    std::cout << "Empty matrix determinant (Gaussian): " << det_empty_gaussian 
              << " (Expected: 1.0) " << (fabsf(det_empty_gaussian - 1.0f) < 1e-6f ? "[PASS]" : "[FAIL]") << "\n";

    // C3.13: determinant methods - Non-square matrix (should return 0)
    std::cout << "\n[C3.13] Determinant Methods - Non-Square Matrix\n";
    tiny::Mat rect_det(2, 3);
    float det_rect_laplace = rect_det.determinant_laplace();
    float det_rect_lu = rect_det.determinant_lu();
    float det_rect_gaussian = rect_det.determinant_gaussian();
    std::cout << "Non-square matrix (2x3) determinant (Laplace): " << det_rect_laplace 
              << " (Expected: 0.0) " << (fabsf(det_rect_laplace) < 1e-6f ? "[PASS]" : "[FAIL]") << "\n";
    std::cout << "Non-square matrix (2x3) determinant (LU): " << det_rect_lu 
              << " (Expected: 0.0) " << (fabsf(det_rect_lu) < 1e-6f ? "[PASS]" : "[FAIL]") << "\n";
    std::cout << "Non-square matrix (2x3) determinant (Gaussian): " << det_rect_gaussian 
              << " (Expected: 0.0) " << (fabsf(det_rect_gaussian) < 1e-6f ? "[PASS]" : "[FAIL]") << "\n";
}

// ============================================================================
// C4: Matrix Adjoint
// ============================================================================
void test_matrix_adjoint()
{
    std::cout << "\n[C4: Matrix Adjoint Tests]\n";

    // C4.1: 1x1 Matrix
    std::cout << "\n[C4.1] Adjoint of 1x1 Matrix\n";
    tiny::Mat mat1(1, 1);
    mat1(0, 0) = 5;
    std::cout << "Original Matrix:\n";
    mat1.print_matrix(true);
    tiny::Mat adj1 = mat1.adjoint();
    std::cout << "Adjoint Matrix:\n";
    adj1.print_matrix(true);  // Expected: [1]

    // C4.2: 2x2 Matrix
    std::cout << "\n[C4.2] Adjoint of 2x2 Matrix\n";
    tiny::Mat mat2(2, 2);
    mat2(0, 0) = 1; mat2(0, 1) = 2;
    mat2(1, 0) = 3; mat2(1, 1) = 4;
    std::cout << "Original Matrix:\n";
    mat2.print_matrix(true);
    tiny::Mat adj2 = mat2.adjoint();
    std::cout << "Adjoint Matrix:\n";
    adj2.print_matrix(true);  // Expected: [4, -2; -3, 1]

    // C4.3: 3x3 Matrix
    std::cout << "\n[C4.3] Adjoint of 3x3 Matrix\n";
    tiny::Mat mat3(3, 3);
    mat3(0,0) = 1; mat3(0,1) = 2; mat3(0,2) = 3;
    mat3(1,0) = 0; mat3(1,1) = 4; mat3(1,2) = 5;
    mat3(2,0) = 1; mat3(2,1) = 0; mat3(2,2) = 6;
    std::cout << "Original Matrix:\n";
    mat3.print_matrix(true);
    tiny::Mat adj3 = mat3.adjoint();
    std::cout << "Adjoint Matrix:\n";
    adj3.print_matrix(true);
    // No simple expected value, but should compute correctly

    // C4.4: Non-Square Matrix (Expect Error)
    std::cout << "\n[C4.4] Adjoint of Non-Square Matrix (Expect Error)\n";
    tiny::Mat rectMat(2, 3);
    std::cout << "Original Matrix (2x3, non-square):\n";
    rectMat.print_matrix(true);
    tiny::Mat adjRect = rectMat.adjoint();
    std::cout << "Adjoint Matrix (should be empty due to error):\n";
    adjRect.print_matrix(true);  // Should be empty or default matrix

}

// ============================================================================
// C5: Matrix Normalization
// ============================================================================
void test_matrix_normalize()
{
    std::cout << "\n[C5: Matrix Normalization Tests]\n";

    // C5.1: Standard normalization
    std::cout << "\n[C5.1] Normalize a Standard 2x2 Matrix\n";
    tiny::Mat mat1(2, 2);
    mat1(0, 0) = 3.0f; mat1(0, 1) = 4.0f;
    mat1(1, 0) = 3.0f; mat1(1, 1) = 4.0f;

    std::cout << "Before normalization:\n";
    mat1.print_matrix(true);

    mat1.normalize();

    std::cout << "After normalization (Expected L2 norm = 1):\n";
    mat1.print_matrix(true);

    // C5.2: Matrix with padding
    std::cout << "\n[C5.2] Normalize a 2x2 Matrix with Stride=4 (Padding Test)\n";
    float data_with_padding[8] = {3.0f, 4.0f, 0.0f, 0.0f, 3.0f, 4.0f, 0.0f, 0.0f};
    tiny::Mat mat2(data_with_padding, 2, 2, 4);  // 2x2 matrix, stride 4

    std::cout << "Before normalization:\n";
    mat2.print_matrix(true);

    mat2.normalize();

    std::cout << "After normalization:\n";
    mat2.print_matrix(true);

    // C5.3: Zero matrix normalization
    std::cout << "\n[C5.3] Normalize a Zero Matrix (Expect Warning)\n";
    tiny::Mat mat3(2, 2);
    mat3.clear();  // Assuming clear() sets all elements to zero

    mat3.print_matrix(true);
    mat3.normalize();  // Should trigger warning
}

// ============================================================================
// C6: Matrix Norm Calculation
// ============================================================================
void test_matrix_norm()
{
    std::cout << "\n[C6: Matrix Norm Calculation Tests]\n";

    // C6.1: Simple 2x2 Matrix
    std::cout << "\n[C6.1] 2x2 Matrix Norm (Expect 5.0)\n";
    tiny::Mat mat1(2, 2);
    mat1(0, 0) = 3.0f; mat1(0, 1) = 4.0f;
    mat1(1, 0) = 0.0f; mat1(1, 1) = 0.0f;
    std::cout << "Matrix:\n";
    mat1.print_matrix(true);
    float norm1 = mat1.norm();
    std::cout << "Calculated Norm: " << norm1 << "\n";

    // C6.2: Zero Matrix
    std::cout << "\n[C6.2] Zero Matrix Norm (Expect 0.0)\n";
    tiny::Mat mat2(3, 3);
    mat2.clear();  // Assuming clear() sets all elements to zero
    std::cout << "Matrix:\n";
    mat2.print_matrix(true);
    float norm2 = mat2.norm();
    std::cout << "Calculated Norm: " << norm2 << "\n";

    // C6.3: Matrix with Negative Values
    std::cout << "\n[C6.3] Matrix with Negative Values\n";
    tiny::Mat mat3(2, 2);
    mat3(0, 0) = -1.0f; mat3(0, 1) = -2.0f;
    mat3(1, 0) = -3.0f; mat3(1, 1) = -4.0f;
    std::cout << "Matrix:\n";
    mat3.print_matrix(true);
    float norm3 = mat3.norm();
    std::cout << "Calculated Norm: " << norm3 << "  (Expect sqrt(30) ≈ 5.477)\n";

    // C6.4: Matrix with Padding
    std::cout << "\n[C6.4] 2x2 Matrix with Stride=4 (Padding Test)\n";
    float data4[8] = {1.0f, 2.0f, 0.0f, 0.0f, 3.0f, 4.0f, 0.0f, 0.0f};
    tiny::Mat mat4(data4, 2, 2, 4);  // 2x2 matrix, stride 4
    std::cout << "Matrix:\n";
    mat4.print_matrix(true);
    float norm4 = mat4.norm();
    std::cout << "Calculated Norm: " << norm4 << "  (Expect sqrt(30) ≈ 5.477)\n";
}

// ============================================================================
// C7: Matrix Inversion
// ============================================================================
void test_inverse_adjoint_adjoint()
{
    std::cout << "\n[C7: Matrix Inversion Tests]\n";

    // C7.1: 2x2 Regular Matrix
    std::cout << "\n[C7.1] Inverse of 2x2 Matrix\n";
    tiny::Mat mat1(2, 2);
    mat1(0, 0) = 4;  mat1(0, 1) = 7;
    mat1(1, 0) = 2;  mat1(1, 1) = 6;
    std::cout << "Original Matrix:\n";
    mat1.print_matrix(true);
    tiny::Mat inv1 = mat1.inverse_adjoint();
    std::cout << "Inverse Matrix:\n";
    inv1.print_matrix(true);
    std::cout << "Expected Approx:\n[ 0.6  -0.7 ]\n[ -0.2  0.4 ]\n";

    // C7.2: Singular Matrix (Determinant = 0)
    std::cout << "\n[C7.2] Singular Matrix (Expect Error)\n";
    tiny::Mat mat2(2, 2);
    mat2(0, 0) = 1;  mat2(0, 1) = 2;
    mat2(1, 0) = 2;  mat2(1, 1) = 4;   // Rank-deficient, det = 0
    std::cout << "Original Matrix:\n";
    mat2.print_matrix(true);
    std::cout << "Note: This matrix is singular (determinant = 0), so inverse should fail.\n";
    tiny::Mat inv2 = mat2.inverse_adjoint();
    std::cout << "Inverse Matrix (Should be zero matrix):\n";
    inv2.print_matrix(true);

    // C7.3: 3x3 Regular Matrix
    std::cout << "\n[C7.3] Inverse of 3x3 Matrix\n";
    tiny::Mat mat3(3, 3);
    mat3(0,0) = 3; mat3(0,1) = 0; mat3(0,2) = 2;
    mat3(1,0) = 2; mat3(1,1) = 0; mat3(1,2) = -2;
    mat3(2,0) = 0; mat3(2,1) = 1; mat3(2,2) = 1;
    std::cout << "Original Matrix:\n";
    mat3.print_matrix(true);
    tiny::Mat inv3 = mat3.inverse_adjoint();
    std::cout << "Inverse Matrix:\n";
    inv3.print_matrix(true);

    // C7.4: Non-Square Matrix (Expect Error)
    std::cout << "\n[C7.4] Non-Square Matrix (Expect Error)\n";
    tiny::Mat mat4(2, 3);
    std::cout << "Original Matrix (2x3, non-square):\n";
    mat4.print_matrix(true);
    tiny::Mat inv4 = mat4.inverse_adjoint();
    std::cout << "Inverse Matrix (should be empty due to error):\n";
    inv4.print_matrix(true);
}

// ============================================================================
// C8: Matrix Utilities
// ============================================================================
void test_matrix_utilities()
{
    std::cout << "\n[C8: Matrix Utilities Tests]\n";

    // C8.1: Identity Matrix (eye)
    std::cout << "\n[C8.1] Generate Identity Matrix (eye)\n";
    tiny::Mat I3 = tiny::Mat::eye(3);
    std::cout << "3x3 Identity Matrix:\n";
    I3.print_matrix(true);

    tiny::Mat I5 = tiny::Mat::eye(5);
    std::cout << "5x5 Identity Matrix:\n";
    I5.print_matrix(true);

    // C8.2: Ones Matrix
    std::cout << "\n[C8.2] Generate Ones Matrix\n";
    tiny::Mat ones_3x4 = tiny::Mat::ones(3, 4);
    std::cout << "3x4 Ones Matrix:\n";
    ones_3x4.print_matrix(true);

    tiny::Mat ones_4x4 = tiny::Mat::ones(4);
    std::cout << "4x4 Ones Matrix (Square):\n";
    ones_4x4.print_matrix(true);

    // C8.3: Matrix Augmentation
    std::cout << "\n[C8.3] Augment Two Matrices Horizontally [A | B]\n";

    // Prepare matrices A (2x2) and B (2x3)
    tiny::Mat A(2, 2);
    A(0,0) = 1;  A(0,1) = 2;
    A(1,0) = 3;  A(1,1) = 4;

    tiny::Mat B(2, 3);
    B(0,0) = 5;  B(0,1) = 6;  B(0,2) = 7;
    B(1,0) = 8;  B(1,1) = 9;  B(1,2) = 10;

    std::cout << "Matrix A:\n";
    A.print_matrix(true);
    std::cout << "Matrix B:\n";
    B.print_matrix(true);

    tiny::Mat AB = tiny::Mat::augment(A, B);
    std::cout << "Augmented Matrix [A | B]:\n";
    AB.print_matrix(true);

    // C8.4: Row mismatch case
    std::cout << "\n[C8.4] Augment with Row Mismatch (Expect Error)\n";
    tiny::Mat C(3, 2);  // 3x2 matrix
    tiny::Mat invalidAug = tiny::Mat::augment(A, C);
    invalidAug.print_info();  // Should show empty matrix due to error

    // C8.5: Vertical Stack (vstack)
    std::cout << "\n[C8.5] Vertically Stack Two Matrices [A; B]\n";

    // Prepare matrices A (2x3) and B (2x3)
    tiny::Mat A_vstack(2, 3);
    A_vstack(0,0) = 1;  A_vstack(0,1) = 2;  A_vstack(0,2) = 3;
    A_vstack(1,0) = 4;  A_vstack(1,1) = 5;  A_vstack(1,2) = 6;

    tiny::Mat B_vstack(2, 3);
    B_vstack(0,0) = 7;  B_vstack(0,1) = 8;  B_vstack(0,2) = 9;
    B_vstack(1,0) = 10; B_vstack(1,1) = 11; B_vstack(1,2) = 12;

    std::cout << "Matrix A (top):\n";
    A_vstack.print_matrix(true);
    std::cout << "Matrix B (bottom):\n";
    B_vstack.print_matrix(true);

    tiny::Mat AB_vstack = tiny::Mat::vstack(A_vstack, B_vstack);
    std::cout << "Vertically Stacked Matrix [A; B]:\n";
    AB_vstack.print_matrix(true);
    std::cout << "Expected: 4x3 matrix with A on top, B on bottom\n";

    // C8.6: Vertical Stack with different row counts
    std::cout << "\n[C8.6] Vertical Stack with Different Row Counts (Same Columns)\n";
    tiny::Mat A_small(1, 3);
    A_small(0,0) = 1; A_small(0,1) = 2; A_small(0,2) = 3;

    tiny::Mat B_large(3, 3);
    B_large(0,0) = 4;  B_large(0,1) = 5;  B_large(0,2) = 6;
    B_large(1,0) = 7;  B_large(1,1) = 8;  B_large(1,2) = 9;
    B_large(2,0) = 10; B_large(2,1) = 11; B_large(2,2) = 12;

    std::cout << "Matrix A (1x3):\n";
    A_small.print_matrix(true);
    std::cout << "Matrix B (3x3):\n";
    B_large.print_matrix(true);

    tiny::Mat AB_mixed = tiny::Mat::vstack(A_small, B_large);
    std::cout << "Vertically Stacked Matrix [A; B] (1x3 + 3x3 = 4x3):\n";
    AB_mixed.print_matrix(true);

    // C8.7: Column mismatch case (Expect Error)
    std::cout << "\n[C8.7] VStack with Column Mismatch (Expect Error)\n";
    tiny::Mat A_col(2, 2);
    A_col(0,0) = 1; A_col(0,1) = 2;
    A_col(1,0) = 3; A_col(1,1) = 4;

    tiny::Mat B_col(2, 3);  // Different column count
    B_col(0,0) = 5; B_col(0,1) = 6; B_col(0,2) = 7;
    B_col(1,0) = 8; B_col(1,1) = 9; B_col(1,2) = 10;

    std::cout << "Matrix A (2x2):\n";
    A_col.print_matrix(true);
    std::cout << "Matrix B (2x3, different columns):\n";
    B_col.print_matrix(true);

    tiny::Mat invalidVStack = tiny::Mat::vstack(A_col, B_col);
    std::cout << "Result (should be empty due to error):\n";
    invalidVStack.print_info();  // Should show empty matrix due to error

}

// ============================================================================
// D1: Gaussian Elimination
// ============================================================================
void test_gaussian_eliminate()
{
    std::cout << "\n[D1: Gaussian Elimination Tests]\n";

    // D1.1: Simple 3x3 System
    std::cout << "\n[D1.1] 3x3 Matrix (Simple Upper Triangular)\n";
    tiny::Mat mat1(3, 3);
    mat1(0,0) = 2; mat1(0,1) = 1; mat1(0,2) = -1;
    mat1(1,0) = -3; mat1(1,1) = -1; mat1(1,2) = 2;
    mat1(2,0) = -2; mat1(2,1) = 1; mat1(2,2) = 2;

    std::cout << "Original Matrix:\n";
    mat1.print_matrix(true);

    tiny::Mat result1 = mat1.gaussian_eliminate();

    std::cout << "After Gaussian Elimination (Should be upper triangular):\n";
    result1.print_matrix(true);

    // D1.2: 3x4 Augmented Matrix
    std::cout << "\n[D1.2] 3x4 Augmented Matrix (Linear System Ax = b)\n";
    tiny::Mat mat2(3, 4);
    mat2(0,0) = 1; mat2(0,1) = 2; mat2(0,2) = -1; mat2(0,3) =  8;
    mat2(1,0) = -3; mat2(1,1) = -1; mat2(1,2) = 2; mat2(1,3) = -11;
    mat2(2,0) = -2; mat2(2,1) = 1; mat2(2,2) = 2; mat2(2,3) = -3;

    std::cout << "Original Augmented Matrix [A | b]:\n";
    mat2.print_matrix(true);

    tiny::Mat result2 = mat2.gaussian_eliminate();

    std::cout << "After Gaussian Elimination (Row Echelon Form):\n";
    result2.print_matrix(true);

    // D1.3: Singular Matrix
    std::cout << "\n[D1.3] Singular Matrix (No Unique Solution)\n";
    tiny::Mat mat3(2, 2);
    mat3(0,0) = 1; mat3(0,1) = 2;
    mat3(1,0) = 2; mat3(1,1) = 4;  // Linearly dependent rows

    std::cout << "Original Singular Matrix:\n";
    mat3.print_matrix(true);

    tiny::Mat result3 = mat3.gaussian_eliminate();
    std::cout << "After Gaussian Elimination (Should show rows of zeros):\n";
    result3.print_matrix(true);

    // D1.4: Zero Matrix
    std::cout << "\n[D1.4] Zero Matrix\n";
    tiny::Mat mat4(3, 3);
    mat4.clear();  // Assuming clear() sets all elements to zero
    mat4.print_matrix(true);

    tiny::Mat result4 = mat4.gaussian_eliminate();
    std::cout << "After Gaussian Elimination (Should be a zero matrix):\n";
    result4.print_matrix(true);

    // D1.5: gaussian_eliminate() - Boundary case - empty matrix
    std::cout << "\n[D1.5] gaussian_eliminate() - Boundary Case - Empty Matrix\n";
    tiny::Mat empty_ge(0, 0);
    tiny::Mat result_empty_ge = empty_ge.gaussian_eliminate();
    // Empty matrix should return empty matrix (0x0) or error state (data == nullptr or 1x1 error matrix)
    bool empty_ge_correct = (result_empty_ge.row == 0 && result_empty_ge.col == 0) || 
                           (result_empty_ge.data == nullptr) ||
                           (result_empty_ge.row == 1 && result_empty_ge.col == 1 && result_empty_ge.data != nullptr);
    std::cout << "Empty matrix gaussian_eliminate: " << (empty_ge_correct ? "Empty matrix or error state (Expected)" : "Non-empty (Error)") 
              << " " << (empty_ge_correct ? "[PASS]" : "[FAIL]") << "\n";

    // D1.6: gaussian_eliminate() - Boundary case - 1x1 matrix
    std::cout << "\n[D1.6] gaussian_eliminate() - Boundary Case - 1x1 Matrix\n";
    tiny::Mat mat1x1_ge(1, 1);
    mat1x1_ge(0, 0) = 5.0f;
    tiny::Mat result1x1_ge = mat1x1_ge.gaussian_eliminate();
    std::cout << "1x1 matrix after gaussian_eliminate:\n";
    result1x1_ge.print_matrix(true);
    bool ge1x1_correct = (result1x1_ge.row == 1 && result1x1_ge.col == 1 && 
                          fabsf(result1x1_ge(0, 0) - 5.0f) < 1e-6f);
    std::cout << "1x1 matrix gaussian_eliminate: " << (ge1x1_correct ? "[PASS]" : "[FAIL]") << "\n";
}


// ============================================================================
// D2: Row Reduce from Gaussian (RREF Calculation)
// ============================================================================
void test_row_reduce_from_gaussian()
{
    std::cout << "\n[D2: Row Reduce from Gaussian (RREF) Tests]\n";

    // D2.1: Simple 3x4 augmented matrix (representing a system of equations)
    std::cout << "\n[D2.1] 3x4 Augmented Matrix\n";
    tiny::Mat mat1(3, 4);

    // Matrix:
    // [ 1  2 -1  -4 ]
    // [ 2  3 -1 -11 ]
    // [-2  0 -3  22 ]
    mat1(0,0) = 1;  mat1(0,1) = 2;  mat1(0,2) = -1; mat1(0,3) = -4;
    mat1(1,0) = 2;  mat1(1,1) = 3;  mat1(1,2) = -1; mat1(1,3) = -11;
    mat1(2,0) = -2; mat1(2,1) = 0;  mat1(2,2) = -3; mat1(2,3) = 22;

    std::cout << "Original Matrix:\n";
    mat1.print_matrix(true);

    tiny::Mat rref1 = mat1.gaussian_eliminate().row_reduce_from_gaussian();
    std::cout << "RREF Result:\n";
    rref1.print_matrix(true);

    // D2.2: 2x3 Matrix
    std::cout << "\n[D2.2] 2x3 Matrix\n";
    tiny::Mat mat2(2, 3);
    mat2(0,0) = 1; mat2(0,1) = 2;  mat2(0,2) = 3;
    mat2(1,0) = 4; mat2(1,1) = 5;  mat2(1,2) = 6;

    std::cout << "Original Matrix:\n";
    mat2.print_matrix(true);

    tiny::Mat rref2 = mat2.gaussian_eliminate().row_reduce_from_gaussian();
    std::cout << "RREF Result:\n";
    rref2.print_matrix(true);

    // D2.3: Already reduced matrix (should remain the same)
    std::cout << "\n[D2.3] Already Reduced Matrix\n";
    tiny::Mat mat3(2, 3);
    mat3(0,0) = 1; mat3(0,1) = 0; mat3(0,2) = 2;
    mat3(1,0) = 0; mat3(1,1) = 1; mat3(1,2) = 3;

    std::cout << "Original Matrix:\n";
    mat3.print_matrix(true);

    tiny::Mat rref3 = mat3.row_reduce_from_gaussian();
    std::cout << "RREF Result:\n";
    rref3.print_matrix(true);

    // D2.4: row_reduce_from_gaussian() - Boundary case - empty matrix
    std::cout << "\n[D2.4] row_reduce_from_gaussian() - Boundary Case - Empty Matrix\n";
    tiny::Mat empty_rref(0, 0);
    tiny::Mat result_empty_rref = empty_rref.row_reduce_from_gaussian();
    // Empty matrix should return empty matrix (0x0) or error state (data == nullptr or 1x1 error matrix)
    bool empty_rref_correct = (result_empty_rref.row == 0 && result_empty_rref.col == 0) || 
                              (result_empty_rref.data == nullptr) ||
                              (result_empty_rref.row == 1 && result_empty_rref.col == 1 && result_empty_rref.data != nullptr);
    std::cout << "Empty matrix row_reduce_from_gaussian: " << (empty_rref_correct ? "Empty matrix or error state (Expected)" : "Non-empty (Error)") 
              << " " << (empty_rref_correct ? "[PASS]" : "[FAIL]") << "\n";
}

// ============================================================================
// D3: Gaussian Inverse
// ============================================================================
void test_inverse_gje()
{
    std::cout << "\n[D3: Gaussian Inverse Tests]\n";

    // D3.1: Regular 2x2 Matrix
    std::cout << "\n[D3.1] 2x2 Matrix Inverse\n";
    tiny::Mat mat1(2, 2);
    mat1(0, 0) = 4; mat1(0, 1) = 7;
    mat1(1, 0) = 2; mat1(1, 1) = 6;
    std::cout << "Original matrix (mat1):\n";
    mat1.print_matrix(true);

    tiny::Mat invMat1 = mat1.inverse_gje();
    std::cout << "Inverse matrix (mat1):\n";
    invMat1.print_matrix(true);

    // D3.2: Identity Matrix (should return identity matrix)
    std::cout << "\n[D3.2] Identity Matrix Inverse\n";
    tiny::Mat mat2 = tiny::Mat::eye(3);
    std::cout << "Original matrix (Identity):\n";
    mat2.print_matrix(true);

    tiny::Mat invMat2 = mat2.inverse_gje();
    std::cout << "Inverse matrix (Identity):\n";
    invMat2.print_matrix(true); // Expected: Identity matrix

    // D3.3: Singular Matrix (should return empty matrix or indicate error)
    std::cout << "\n[D3.3] Singular Matrix (Expected: No Inverse)\n";
    tiny::Mat mat3(3, 3);
    mat3(0, 0) = 1; mat3(0, 1) = 2; mat3(0, 2) = 3;
    mat3(1, 0) = 4; mat3(1, 1) = 5; mat3(1, 2) = 6;
    mat3(2, 0) = 7; mat3(2, 1) = 8; mat3(2, 2) = 9;  // Determinant is 0
    std::cout << "Original matrix (singular):\n";
    mat3.print_matrix(true);

    tiny::Mat invMat3 = mat3.inverse_gje();
    std::cout << "Inverse matrix (singular):\n";
    invMat3.print_matrix(true); // Expected: empty matrix or error message

    // D3.4: 3x3 Matrix with a valid inverse
    std::cout << "\n[D3.4] 3x3 Matrix Inverse\n";
    tiny::Mat mat4(3, 3);
    mat4(0, 0) = 4; mat4(0, 1) = 7; mat4(0, 2) = 2;
    mat4(1, 0) = 3; mat4(1, 1) = 5; mat4(1, 2) = 1;
    mat4(2, 0) = 8; mat4(2, 1) = 6; mat4(2, 2) = 9;
    std::cout << "Original matrix (mat4):\n";
    mat4.print_matrix(true);

    tiny::Mat invMat4 = mat4.inverse_gje();
    std::cout << "Inverse matrix (mat4):\n";
    invMat4.print_matrix(true); // Check that the inverse is calculated correctly

    // D3.5: Non-square Matrix (should return error or empty matrix)
    std::cout << "\n[D3.5] Non-square Matrix Inverse (Expected Error)\n";
    tiny::Mat mat5(2, 3);
    mat5(0, 0) = 1; mat5(0, 1) = 2; mat5(0, 2) = 3;
    mat5(1, 0) = 4; mat5(1, 1) = 5; mat5(1, 2) = 6;
    std::cout << "Original matrix (non-square):\n";
    mat5.print_matrix(true);

    tiny::Mat invMat5 = mat5.inverse_gje();
    std::cout << "Inverse matrix (non-square):\n";
    invMat5.print_matrix(true); // Expected: Error message or empty matrix
}

// ============================================================================
// D4: Dot Product
// ============================================================================
void test_dotprod()
{
    std::cout << "\n[D4: Dot Product Tests]\n";

    // D4.1: Valid Dot Product Calculation (Same Length Vectors)
    std::cout << "\n[D4.1] Valid Dot Product (Same Length Vectors)\n";
    tiny::Mat vectorA(3, 1);  // Create a 3x1 vector
    tiny::Mat vectorB(3, 1);  // Create a 3x1 vector

    // Initialize vectors
    vectorA(0, 0) = 1.0f;
    vectorA(1, 0) = 2.0f;
    vectorA(2, 0) = 3.0f;

    vectorB(0, 0) = 4.0f;
    vectorB(1, 0) = 5.0f;
    vectorB(2, 0) = 6.0f;

    std::cout << "Vector A:\n";
    vectorA.print_matrix(true);
    std::cout << "Vector B:\n";
    vectorB.print_matrix(true);

    // Compute the dot product
    float result = vectorA.dotprod(vectorA, vectorB);
    std::cout << "Dot product of vectorA and vectorB: " << result << std::endl;  // Expected result: 1*4 + 2*5 + 3*6 = 32

    // D4.2: Dot Product with Dimension Mismatch (Different Length Vectors)
    std::cout << "\n[D4.2] Invalid Dot Product (Dimension Mismatch)\n";
    tiny::Mat vectorC(2, 1);  // Create a 2x1 vector (different size)
    vectorC(0, 0) = 1.0f;
    vectorC(1, 0) = 2.0f;

    std::cout << "Vector A (3x1):\n";
    vectorA.print_matrix(true);
    std::cout << "Vector C (2x1, different size):\n";
    vectorC.print_matrix(true);

    float invalidResult = vectorA.dotprod(vectorA, vectorC);  // Should print an error and return 0
    std::cout << "Dot product (dimension mismatch): " << invalidResult << std::endl;  // Expected: 0 and error message

    // D4.3: Dot Product of Zero Vectors
    std::cout << "\n[D4.3] Dot Product of Zero Vectors\n";
    tiny::Mat zeroVectorA(3, 1);  // Create a 3x1 zero vector
    tiny::Mat zeroVectorB(3, 1);  // Create a 3x1 zero vector

    // Initialize vectors
    zeroVectorA(0, 0) = 0.0f;
    zeroVectorA(1, 0) = 0.0f;
    zeroVectorA(2, 0) = 0.0f;

    zeroVectorB(0, 0) = 0.0f;
    zeroVectorB(1, 0) = 0.0f;
    zeroVectorB(2, 0) = 0.0f;

    std::cout << "Zero Vector A:\n";
    zeroVectorA.print_matrix(true);
    std::cout << "Zero Vector B:\n";
    zeroVectorB.print_matrix(true);

    float zeroResult = zeroVectorA.dotprod(zeroVectorA, zeroVectorB);
    std::cout << "Dot product of zero vectors: " << zeroResult << std::endl;  // Expected: 0

}

// ============================================================================
// D5: Solve Linear System
// ============================================================================
void test_solve()
{
    std::cout << "\n[D5: Solve Linear System Tests]\n";

    // D5.1: Solving a simple 2x2 system
    std::cout << "\n[D5.1] Solving a Simple 2x2 System Ax = b\n";
    tiny::Mat A(2, 2);
    tiny::Mat b(2, 1);

    A(0, 0) = 2; A(0, 1) = 1;
    A(1, 0) = 1; A(1, 1) = 3;

    b(0, 0) = 5;
    b(1, 0) = 6;

    std::cout << "Matrix A:\n";
    A.print_matrix(true);
    std::cout << "Vector b:\n";
    b.print_matrix(true);

    tiny::Mat solution = A.solve(A, b);
    std::cout << "Solution x:\n";
    solution.print_matrix(true);

    // D5.2: Solving a 3x3 system
    std::cout << "\n[D5.2] Solving a 3x3 System Ax = b\n";
    tiny::Mat A2(3, 3);
    tiny::Mat b2(3, 1);

    A2(0, 0) = 1; A2(0, 1) = 2; A2(0, 2) = 1;
    A2(1, 0) = 2; A2(1, 1) = 0; A2(1, 2) = 3;
    A2(2, 0) = 3; A2(2, 1) = 2; A2(2, 2) = 1;

    b2(0, 0) = 9;
    b2(1, 0) = 8;
    b2(2, 0) = 7;

    std::cout << "Matrix A:\n";
    A2.print_matrix(true);
    std::cout << "Vector b:\n";
    b2.print_matrix(true);

    tiny::Mat solution2 = A2.solve(A2, b2);
    std::cout << "Solution x:\n";
    solution2.print_matrix(true);

    // D5.3: Solving a system where one row is all zeros
    std::cout << "\n[D5.3] Solving a System Where One Row is All Zeros (Expect Failure or Infinite Solutions)\n";
    tiny::Mat A3(3, 3);
    tiny::Mat b3(3, 1);

    A3(0, 0) = 1; A3(0, 1) = 2; A3(0, 2) = 3;
    A3(1, 0) = 0; A3(1, 1) = 0; A3(1, 2) = 0; // Zero row
    A3(2, 0) = 4; A3(2, 1) = 5; A3(2, 2) = 6;

    b3(0, 0) = 9;
    b3(1, 0) = 0; // Inconsistent, no solution should be possible
    b3(2, 0) = 15;

    std::cout << "Matrix A (has zero row):\n";
    A3.print_matrix(true);
    std::cout << "Vector b:\n";
    b3.print_matrix(true);

    tiny::Mat solution3 = A3.solve(A3, b3);
    std::cout << "Solution x:\n";
    solution3.print_matrix(true);

    // D5.4: Solving a system with zero determinant (singular matrix)
    std::cout << "\n[D5.4] Solving a System with Zero Determinant (Singular Matrix)\n";
    tiny::Mat A4(3, 3);
    tiny::Mat b4(3, 1);

    A4(0, 0) = 2; A4(0, 1) = 4; A4(0, 2) = 1;
    A4(1, 0) = 1; A4(1, 1) = 2; A4(1, 2) = 3;
    A4(2, 0) = 3; A4(2, 1) = 6; A4(2, 2) = 2; // The matrix is singular (row 2 = 2 * row 1)

    b4(0, 0) = 5;
    b4(1, 0) = 6;
    b4(2, 0) = 7;

    std::cout << "Matrix A (singular, determinant = 0):\n";
    A4.print_matrix(true);
    std::cout << "Vector b:\n";
    b4.print_matrix(true);

    tiny::Mat solution4 = A4.solve(A4, b4);
    std::cout << "Solution x:\n";
    solution4.print_matrix(true); // Expect no solution or an error message

    // D5.5: Solving a system with linearly dependent rows
    std::cout << "\n[D5.5] Solving a System with Linearly Dependent Rows (Expect Failure or Infinite Solutions)\n";
    tiny::Mat A5(3, 3);
    tiny::Mat b5(3, 1);

    A5(0, 0) = 1; A5(0, 1) = 1; A5(0, 2) = 1;
    A5(1, 0) = 2; A5(1, 1) = 2; A5(1, 2) = 2;
    A5(2, 0) = 3; A5(2, 1) = 3; A5(2, 2) = 3; // All rows are linearly dependent

    b5(0, 0) = 6;
    b5(1, 0) = 12;
    b5(2, 0) = 18;

    std::cout << "Matrix A (all rows linearly dependent):\n";
    A5.print_matrix(true);
    std::cout << "Vector b:\n";
    b5.print_matrix(true);

    tiny::Mat solution5 = A5.solve(A5, b5);
    std::cout << "Solution x:\n";
    solution5.print_matrix(true); // Expect an error message or infinite solutions

    // D5.6: Solving a larger 4x4 system
    std::cout << "\n[D5.6] Solving a Larger 4x4 System Ax = b\n";
    tiny::Mat A6(4, 4);
    tiny::Mat b6(4, 1);

    A6(0, 0) = 4; A6(0, 1) = 2; A6(0, 2) = 3; A6(0, 3) = 1;
    A6(1, 0) = 2; A6(1, 1) = 5; A6(1, 2) = 1; A6(1, 3) = 2;
    A6(2, 0) = 3; A6(2, 1) = 1; A6(2, 2) = 6; A6(2, 3) = 3;
    A6(3, 0) = 1; A6(3, 1) = 2; A6(3, 2) = 3; A6(3, 3) = 4;

    b6(0, 0) = 10;
    b6(1, 0) = 12;
    b6(2, 0) = 14;
    b6(3, 0) = 16;

    std::cout << "Matrix A:\n";
    A6.print_matrix(true);
    std::cout << "Vector b:\n";
    b6.print_matrix(true);

    tiny::Mat solution6 = A6.solve(A6, b6);
    std::cout << "Solution x:\n";
    solution6.print_matrix(true); // Should print the solution vector

    // D5.7: solve() - Boundary case - empty matrix
    std::cout << "\n[D5.7] solve() - Boundary Case - Empty Matrix\n";
    tiny::Mat empty_A(0, 0);
    tiny::Mat empty_b(0, 1);
    tiny::Mat solution_empty = empty_A.solve(empty_A, empty_b);
    // Error case should return empty matrix (0x0) or error state (data == nullptr or 1x1 error matrix)
    bool solve_empty_correct = (solution_empty.row == 0 && solution_empty.col == 0) || 
                               (solution_empty.data == nullptr) ||
                               (solution_empty.row == 1 && solution_empty.col == 1 && solution_empty.data != nullptr);
    std::cout << "Empty system solve: " << (solve_empty_correct ? "Empty matrix or error state (Expected)" : "Non-empty (Error)") 
              << " " << (solve_empty_correct ? "[PASS]" : "[FAIL]") << "\n";

    // D5.8: solve() - Error handling - dimension mismatch
    std::cout << "\n[D5.8] solve() - Error Handling - Dimension Mismatch\n";
    tiny::Mat A_mismatch(2, 2);
    tiny::Mat b_mismatch(3, 1);  // Different dimension
    tiny::Mat solution_mismatch = A_mismatch.solve(A_mismatch, b_mismatch);
    // Error case should return empty matrix (0x0) or error state (data == nullptr or 1x1 error matrix)
    // For dimension mismatch, expected solution size is 2x1, so 1x1 indicates error
    bool solve_mismatch_correct = (solution_mismatch.row == 0 && solution_mismatch.col == 0) || 
                                  (solution_mismatch.data == nullptr) ||
                                  (solution_mismatch.row == 1 && solution_mismatch.col == 1 && solution_mismatch.data != nullptr);
    std::cout << "Dimension mismatch solve: " << (solve_mismatch_correct ? "Empty matrix or error state (Expected)" : "Non-empty (Error)") 
              << " " << (solve_mismatch_correct ? "[PASS]" : "[FAIL]") << "\n";
}

// ============================================================================
// D6: Band Solve
// ============================================================================
void test_band_solve()
{
    std::cout << "\n[D6: Band Solve Tests]\n";

    // D6.1: Simple 3x3 Band Matrix
    std::cout << "\n[D6.1] Simple 3x3 Band Matrix\n";
    tiny::Mat A1(3, 3);
    tiny::Mat b1(3, 1);

    // Define the matrix A and vector b for the system Ax = b
    A1(0, 0) = 2; A1(0, 1) = 1; A1(0, 2) = 0;
    A1(1, 0) = 1; A1(1, 1) = 3; A1(1, 2) = 2;
    A1(2, 0) = 0; A1(2, 1) = 1; A1(2, 2) = 4;

    b1(0, 0) = 5;
    b1(1, 0) = 6;
    b1(2, 0) = 7;

    std::cout << "Matrix A:\n";
    A1.print_matrix(true);
    std::cout << "Vector b:\n";
    b1.print_matrix(true);

    // Solve Ax = b using band_solve
    tiny::Mat solution1 = A1.band_solve(A1, b1, 3);
    std::cout << "Solution x:\n";
    solution1.print_matrix(true);

    // D6.2: 4x4 Band Matrix with different right-hand side vector
    std::cout << "\n[D6.2] 4x4 Band Matrix\n";
    tiny::Mat A2(4, 4);
    tiny::Mat b2(4, 1);

    // Define the matrix A and vector b
    A2(0, 0) = 2; A2(0, 1) = 1; A2(0, 2) = 0; A2(0, 3) = 0;
    A2(1, 0) = 1; A2(1, 1) = 3; A2(1, 2) = 2; A2(1, 3) = 0;
    A2(2, 0) = 0; A2(2, 1) = 1; A2(2, 2) = 4; A2(2, 3) = 2;
    A2(3, 0) = 0; A2(3, 1) = 0; A2(3, 2) = 1; A2(3, 3) = 5;

    b2(0, 0) = 8;
    b2(1, 0) = 9;
    b2(2, 0) = 10;
    b2(3, 0) = 11;

    std::cout << "Matrix A:\n";
    A2.print_matrix(true);
    std::cout << "Vector b:\n";
    b2.print_matrix(true);

    // Solve Ax = b using band_solve
    tiny::Mat solution2 = A2.band_solve(A2, b2, 3);
    std::cout << "Solution x:\n";
    solution2.print_matrix(true);

    // D6.3: Incompatible dimensions (expect error)
    std::cout << "\n[D6.3] Incompatible Dimensions (Expect Error)\n";
    tiny::Mat A3(3, 3);
    tiny::Mat b3(2, 1);  // Incompatible dimension

    A3(0, 0) = 1; A3(0, 1) = 2; A3(0, 2) = 3;
    A3(1, 0) = 4; A3(1, 1) = 5; A3(1, 2) = 6;
    A3(2, 0) = 7; A3(2, 1) = 8; A3(2, 2) = 9;

    b3(0, 0) = 10;
    b3(1, 0) = 11;

    std::cout << "Matrix A (3x3):\n";
    A3.print_matrix(true);
    std::cout << "Vector b (2x1, incompatible):\n";
    b3.print_matrix(true);

    // This should print an error because of incompatible dimensions
    tiny::Mat solution3 = A3.band_solve(A3, b3, 3);
    std::cout << "Solution x:\n";
    solution3.print_matrix(true);

    // D6.4: Singular Matrix (Should fail)
    std::cout << "\n[D6.4] Singular Matrix (No Unique Solution)\n";
    tiny::Mat A4(3, 3);
    tiny::Mat b4(3, 1);

    // Define a singular matrix (linearly dependent rows)
    A4(0, 0) = 1; A4(0, 1) = 2; A4(0, 2) = 3;
    A4(1, 0) = 2; A4(1, 1) = 4; A4(1, 2) = 6;
    A4(2, 0) = 3; A4(2, 1) = 6; A4(2, 2) = 9;

    b4(0, 0) = 10;
    b4(1, 0) = 20;
    b4(2, 0) = 30;

    std::cout << "Matrix A (singular, linearly dependent rows):\n";
    A4.print_matrix(true);
    std::cout << "Vector b:\n";
    b4.print_matrix(true);

    // This should print an error as the matrix is singular and does not have a unique solution
    tiny::Mat solution4 = A4.band_solve(A4, b4, 3);
    std::cout << "Solution x:\n";
    solution4.print_matrix(true);

    // D6.5: band_solve() - Boundary case - empty matrix
    std::cout << "\n[D6.5] band_solve() - Boundary Case - Empty Matrix\n";
    tiny::Mat empty_A_band(0, 0);
    tiny::Mat empty_b_band(0, 1);
    tiny::Mat solution_empty_band = empty_A_band.band_solve(empty_A_band, empty_b_band, 0);
    // Error case should return empty matrix (0x0) or error state (data == nullptr or 1x1 error matrix)
    bool band_solve_empty_correct = (solution_empty_band.row == 0 && solution_empty_band.col == 0) || 
                                    (solution_empty_band.data == nullptr) ||
                                    (solution_empty_band.row == 1 && solution_empty_band.col == 1 && solution_empty_band.data != nullptr);
    std::cout << "Empty system band_solve: " << (band_solve_empty_correct ? "Empty matrix or error state (Expected)" : "Non-empty (Error)") 
              << " " << (band_solve_empty_correct ? "[PASS]" : "[FAIL]") << "\n";

    // D6.6: band_solve() - Error handling - invalid bandwidth
    std::cout << "\n[D6.6] band_solve() - Error Handling - Invalid Bandwidth\n";
    tiny::Mat A_band(3, 3);
    tiny::Mat b_band(3, 1);
    tiny::Mat solution_neg_k = A_band.band_solve(A_band, b_band, -1);
    // Error case should return empty matrix (0x0) or error state (data == nullptr or 1x1 error matrix)
    // For invalid bandwidth, expected solution size is 3x1, so 1x1 indicates error
    bool band_solve_neg_k_correct = (solution_neg_k.row == 0 && solution_neg_k.col == 0) || 
                                     (solution_neg_k.data == nullptr) ||
                                     (solution_neg_k.row == 1 && solution_neg_k.col == 1 && solution_neg_k.data != nullptr);
    std::cout << "band_solve with k=-1: " << (band_solve_neg_k_correct ? "Empty matrix or error state (Expected)" : "Non-empty (Error)") 
              << " " << (band_solve_neg_k_correct ? "[PASS]" : "[FAIL]") << "\n";
}

// ============================================================================
// D7: Roots
// ============================================================================
void test_roots()
{
    std::cout << "\n[D7: Roots Tests]\n";

    // D7.1: Simple 2x2 System
    std::cout << "\n[D7.1] Solving a Simple 2x2 System Ax = b\n";
    tiny::Mat A1(2, 2);
    tiny::Mat b1(2, 1);

    // Define the matrix A and vector b for the system Ax = b
    A1(0, 0) = 2; A1(0, 1) = 1;
    A1(1, 0) = 1; A1(1, 1) = 3;

    b1(0, 0) = 5;
    b1(1, 0) = 6;

    std::cout << "Matrix A:\n";
    A1.print_matrix(true);
    std::cout << "Vector b:\n";
    b1.print_matrix(true);

    // Solve Ax = b using roots
    tiny::Mat solution1 = A1.roots(A1, b1);
    std::cout << "Solution x:\n";
    solution1.print_matrix(true);

    // D7.2: 3x3 System
    std::cout << "\n[D7.2] Solving a 3x3 System Ax = b\n";
    tiny::Mat A2(3, 3);
    tiny::Mat b2(3, 1);

    A2(0, 0) = 1; A2(0, 1) = 2; A2(0, 2) = 1;
    A2(1, 0) = 2; A2(1, 1) = 0; A2(1, 2) = 3;
    A2(2, 0) = 3; A2(2, 1) = 2; A2(2, 2) = 1;

    b2(0, 0) = 9;
    b2(1, 0) = 8;
    b2(2, 0) = 7;

    std::cout << "Matrix A:\n";
    A2.print_matrix(true);
    std::cout << "Vector b:\n";
    b2.print_matrix(true);

    // Solve Ax = b using roots
    tiny::Mat solution2 = A2.roots(A2, b2);
    std::cout << "Solution x:\n";
    solution2.print_matrix(true);

    // D7.3: Singular Matrix
    std::cout << "\n[D7.3] Singular Matrix (No Unique Solution)\n";
    tiny::Mat A3(2, 2);
    tiny::Mat b3(2, 1);

    // Define a singular matrix (linearly dependent rows)
    A3(0, 0) = 1; A3(0, 1) = 2;
    A3(1, 0) = 2; A3(1, 1) = 4;

    b3(0, 0) = 5;
    b3(1, 0) = 6;

    std::cout << "Matrix A (singular, linearly dependent rows):\n";
    A3.print_matrix(true);
    std::cout << "Vector b:\n";
    b3.print_matrix(true);

    // This should print an error as the matrix is singular and does not have a unique solution
    tiny::Mat solution3 = A3.roots(A3, b3);
    std::cout << "Solution x:\n";
    solution3.print_matrix(true);

    // D7.4: Incompatible Dimensions (Expect Error)
    std::cout << "\n[D7.4] Incompatible Dimensions (Expect Error)\n";
    tiny::Mat A4(3, 3);
    tiny::Mat b4(2, 1);  // Incompatible dimension

    A4(0, 0) = 1; A4(0, 1) = 2; A4(0, 2) = 3;
    A4(1, 0) = 4; A4(1, 1) = 5; A4(1, 2) = 6;
    A4(2, 0) = 7; A4(2, 1) = 8; A4(2, 2) = 9;

    b4(0, 0) = 10;
    b4(1, 0) = 11;

    std::cout << "Matrix A (3x3):\n";
    A4.print_matrix(true);
    std::cout << "Vector b (2x1, incompatible):\n";
    b4.print_matrix(true);

    // This should print an error because of incompatible dimensions
    tiny::Mat solution4 = A4.roots(A4, b4);
    // Error case should return empty matrix (0x0) or error state (data == nullptr or 1x1 error matrix)
    // For dimension mismatch, expected solution size is 3x1, so 1x1 indicates error
    bool roots_mismatch_correct = (solution4.row == 0 && solution4.col == 0) || 
                                  (solution4.data == nullptr) ||
                                  (solution4.row == 1 && solution4.col == 1 && solution4.data != nullptr);
    std::cout << "Dimension mismatch roots: " << (roots_mismatch_correct ? "Empty matrix or error state (Expected)" : "Non-empty (Error)") 
              << " " << (roots_mismatch_correct ? "[PASS]" : "[FAIL]") << "\n";

    // D7.5: roots() - Boundary case - empty matrix
    std::cout << "\n[D7.5] roots() - Boundary Case - Empty Matrix\n";
    tiny::Mat empty_A_roots(0, 0);
    tiny::Mat empty_y_roots(0, 1);
    tiny::Mat solution_empty_roots = empty_A_roots.roots(empty_A_roots, empty_y_roots);
    // Error case should return empty matrix (0x0) or error state (data == nullptr or 1x1 error matrix)
    bool roots_empty_correct = (solution_empty_roots.row == 0 && solution_empty_roots.col == 0) || 
                                (solution_empty_roots.data == nullptr) ||
                                (solution_empty_roots.row == 1 && solution_empty_roots.col == 1 && solution_empty_roots.data != nullptr);
    std::cout << "Empty system roots: " << (roots_empty_correct ? "Empty matrix or error state (Expected)" : "Non-empty (Error)") 
              << " " << (roots_empty_correct ? "[PASS]" : "[FAIL]") << "\n";
}

// ============================================================================
// E: Advanced Linear Algebra
// ============================================================================
// Purpose: Advanced linear algebra operations for stable and efficient solving
// E1: Matrix Decomposition
// E2: Gram-Schmidt Orthogonalization

// ============================================================================
// E3: Eigenvalue Decomposition
// ============================================================================
// Purpose: Eigenvalue decomposition for SHM and modal analysis
// E3: Eigenvalue & Eigenvector

// ============================================================================
// F: Auxiliary Functions
// ============================================================================
// Purpose: Convenience functions and I/O operations
// F1: Stream Operators
// F2: Global Arithmetic Operators

// ============================================================================
// G: Quality Assurance
// ============================================================================
// Purpose: Ensure robustness, performance, and correctness
// G1: Boundary Conditions and Error Handling
// G2: Performance Benchmarks
// G3: Memory Layout

// ============================================================================
// F1: Stream Operators
// ============================================================================
void test_stream_operators()
{
    std::cout << "\n[F1: Stream Operators Tests]\n";

    // F1.1: Test stream insertion operator (<<) for Mat
    std::cout << "\n[F1.1] Stream Insertion Operator (<<) for Mat\n";
    tiny::Mat mat1(3, 3);
    mat1(0, 0) = 1; mat1(0, 1) = 2; mat1(0, 2) = 3;
    mat1(1, 0) = 4; mat1(1, 1) = 5; mat1(1, 2) = 6;
    mat1(2, 0) = 7; mat1(2, 1) = 8; mat1(2, 2) = 9;

    std::cout << "Matrix mat1:\n";
    std::cout << mat1 << std::endl; // Use the << operator to print mat1

    // F1.2: Test stream insertion operator (<<) for Mat::ROI
    std::cout << "\n[F1.2] Stream Insertion Operator (<<) for Mat::ROI\n";
    tiny::Mat::ROI roi(1, 2, 3, 4);
    // ROI constructor: ROI(pos_x, pos_y, width, height)
    // roi(1, 2, 3, 4) means: start at column 1, row 2, with width 3, height 4
    std::cout << "ROI created: ROI(pos_x=1, pos_y=2, width=3, height=4)\n";
    std::cout << "Expected output:\n";
    std::cout << "  row start: 2 (pos_y)\n";
    std::cout << "  col start: 1 (pos_x)\n";
    std::cout << "  row count: 4 (height)\n";
    std::cout << "  col count: 3 (width)\n";
    std::cout << "\nActual output:\n";
    std::cout << roi << std::endl; // Use the << operator to print roi

    // F1.3: Test stream extraction operator (>>) for Mat
    std::cout << "\n[F1.3] Stream Extraction Operator (>>) for Mat\n";
    tiny::Mat mat2(2, 2);
    // Use istringstream to simulate input (for automated testing)
    std::istringstream input1("10 20 30 40");
    std::cout << "Simulated input: \"10 20 30 40\"\n";
    input1 >> mat2; // Use the >> operator to read from string stream
    std::cout << "Matrix mat2 after input:\n";
    std::cout << mat2 << std::endl; // Use the << operator to print mat2
    std::cout << "Expected: [10, 20; 30, 40]\n";

    // F1.4: Test stream extraction operator (>>) for Mat (with different values)
    std::cout << "\n[F1.4] Stream Extraction Operator (>>) for Mat (2x3 matrix)\n";
    tiny::Mat mat3(2, 3);
    // Use istringstream to simulate input (for automated testing)
    std::istringstream input2("1.5 2.5 3.5 4.5 5.5 6.5");
    std::cout << "Simulated input: \"1.5 2.5 3.5 4.5 5.5 6.5\"\n";
    input2 >> mat3; // Use the >> operator to read from string stream
    std::cout << "Matrix mat3 after input:\n";
    std::cout << mat3 << std::endl; // Use the << operator to print mat3
    std::cout << "Expected: [1.5, 2.5, 3.5; 4.5, 5.5, 6.5]\n";
}

// ============================================================================
// F2: Global Arithmetic Operators
// ============================================================================
void test_matrix_operations()
{
    std::cout << "\n[F2: Global Arithmetic Operators Tests]\n";

    // F2.1: Matrix Addition (operator+)
    std::cout << "\n[F2.1] Matrix Addition (operator+)\n";
    tiny::Mat matA(2, 2);
    tiny::Mat matB(2, 2);

    matA(0, 0) = 1; matA(0, 1) = 2;
    matA(1, 0) = 3; matA(1, 1) = 4;

    matB(0, 0) = 5; matB(0, 1) = 6;
    matB(1, 0) = 7; matB(1, 1) = 8;

    std::cout << "Matrix A:\n";
    matA.print_matrix(true);
    std::cout << "Matrix B:\n";
    matB.print_matrix(true);

    tiny::Mat resultAdd = matA + matB;
    std::cout << "matA + matB:\n";
    std::cout << resultAdd << std::endl;  // Expected: [6, 8], [10, 12]

    // F2.2: Matrix Addition with Constant (operator+)
    std::cout << "\n[F2.2] Matrix Addition with Constant (operator+)\n";
    std::cout << "Matrix A:\n";
    matA.print_matrix(true);
    std::cout << "Constant: 5.0\n";
    tiny::Mat resultAddConst = matA + 5.0f;
    std::cout << "matA + 5.0f:\n";
    std::cout << resultAddConst << std::endl;  // Expected: [6, 7], [8, 9]

    // F2.3: Matrix Subtraction (operator-)
    std::cout << "\n[F2.3] Matrix Subtraction (operator-)\n";
    std::cout << "Matrix A:\n";
    matA.print_matrix(true);
    std::cout << "Matrix B:\n";
    matB.print_matrix(true);
    tiny::Mat resultSub = matA - matB;
    std::cout << "matA - matB:\n";
    std::cout << resultSub << std::endl;  // Expected: [-4, -4], [-4, -4]

    // F2.4: Matrix Subtraction with Constant (operator-)
    std::cout << "\n[F2.4] Matrix Subtraction with Constant (operator-)\n";
    std::cout << "Matrix A:\n";
    matA.print_matrix(true);
    std::cout << "Constant: 2.0\n";
    tiny::Mat resultSubConst = matA - 2.0f;
    std::cout << "matA - 2.0f:\n";
    std::cout << resultSubConst << std::endl;  // Expected: [-1, 0], [1, 2]

    // F2.5: Matrix Multiplication (operator*)
    std::cout << "\n[F2.5] Matrix Multiplication (operator*)\n";
    tiny::Mat matC(2, 3);
    tiny::Mat matD(3, 2);

    matC(0, 0) = 1; matC(0, 1) = 2; matC(0, 2) = 3;
    matC(1, 0) = 4; matC(1, 1) = 5; matC(1, 2) = 6;

    matD(0, 0) = 7; matD(0, 1) = 8;
    matD(1, 0) = 9; matD(1, 1) = 10;
    matD(2, 0) = 11; matD(2, 1) = 12;

    std::cout << "Matrix C (2x3):\n";
    matC.print_matrix(true);
    std::cout << "Matrix D (3x2):\n";
    matD.print_matrix(true);

    tiny::Mat resultMul = matC * matD;
    std::cout << "matC * matD:\n";
    std::cout << resultMul << std::endl;  // Expected: [58, 64], [139, 154]

    // F2.6: Matrix Multiplication with Constant (operator*)
    std::cout << "\n[F2.6] Matrix Multiplication with Constant (operator*)\n";
    std::cout << "Matrix A:\n";
    matA.print_matrix(true);
    std::cout << "Constant: 2.0\n";
    tiny::Mat resultMulConst = matA * 2.0f;
    std::cout << "matA * 2.0f:\n";
    std::cout << resultMulConst << std::endl;  // Expected: [2, 4], [6, 8]

    // F2.7: Matrix Division (operator/)
    std::cout << "\n[F2.7] Matrix Division (operator/)\n";
    std::cout << "Matrix A:\n";
    matA.print_matrix(true);
    std::cout << "Constant: 2.0\n";
    tiny::Mat resultDiv = matA / 2.0f;
    std::cout << "matA / 2.0f:\n";
    std::cout << resultDiv << std::endl;  // Expected: [0.5, 1], [1.5, 2]

    // F2.8: Matrix Division Element-wise (operator/)
    std::cout << "\n[F2.8] Matrix Division Element-wise (operator/)\n";
    std::cout << "Matrix A:\n";
    matA.print_matrix(true);
    std::cout << "Matrix B:\n";
    matB.print_matrix(true);
    tiny::Mat resultDivElem = matA / matB;
    std::cout << "matA / matB:\n";
    std::cout << resultDivElem << std::endl;  // Expected: [0.2, 0.333], [0.428, 0.5]

    // F2.9: Matrix Comparison (operator==)
    std::cout << "\n[F2.9] Matrix Comparison (operator==)\n";
    tiny::Mat matE(2, 2);
    matE(0, 0) = 1; matE(0, 1) = 2;
    matE(1, 0) = 3; matE(1, 1) = 4;

    tiny::Mat matF(2, 2);
    matF(0, 0) = 1; matF(0, 1) = 2;
    matF(1, 0) = 3; matF(1, 1) = 4;

    std::cout << "Matrix E:\n";
    matE.print_matrix(true);
    std::cout << "Matrix F:\n";
    matF.print_matrix(true);

    bool isEqual = (matE == matF);
    std::cout << "matE == matF: " << (isEqual ? "True" : "False") << std::endl;  // Expected: True

    matF(0, 0) = 5;  // Modify matF
    std::cout << "\nAfter modifying matF(0,0) = 5:\n";
    std::cout << "Matrix E:\n";
    matE.print_matrix(true);
    std::cout << "Matrix F:\n";
    matF.print_matrix(true);
    isEqual = (matE == matF);
    std::cout << "matE == matF after modification: " << (isEqual ? "True" : "False") << std::endl;  // Expected: False
}

// ============================================================================
// G1: Quality Assurance - Boundary Conditions and Error Handling Tests
// ============================================================================
// Purpose: Test error handling and edge cases - ensure robustness
void test_boundary_conditions()
{
    std::cout << "\n[G1: Quality Assurance - Boundary Conditions and Error Handling Tests]\n";

    // G1.1: Null pointer handling in print functions
    std::cout << "\n[G1.1] Null Pointer Handling in print_matrix\n";
    tiny::Mat null_mat;
    null_mat.data = nullptr;  // Simulate null pointer
    null_mat.print_matrix(true);  // Should handle gracefully

    // G1.2: Null pointer handling in operator<<
    std::cout << "\n[G1.2] Null Pointer Handling in operator<<\n";
    tiny::Mat null_mat2;
    null_mat2.data = nullptr;
    std::cout << null_mat2 << std::endl;  // Should handle gracefully

    // G1.3: Invalid block parameters
    std::cout << "\n[G1.3] Invalid Block Parameters\n";
    tiny::Mat mat(3, 3);
    for (int i = 0; i < 3; ++i)
        for (int j = 0; j < 3; ++j)
            mat(i, j) = i * 3 + j + 1;

    // Negative start position
    tiny::Mat block1 = mat.block(-1, 0, 2, 2);
    std::cout << "block(-1, 0, 2, 2): " << (block1.data == nullptr ? "Empty (correct)" : "Error") << "\n";

    // Block exceeds boundaries
    tiny::Mat block2 = mat.block(2, 2, 2, 2);
    std::cout << "block(2, 2, 2, 2) on 3x3 matrix: " << (block2.data == nullptr ? "Empty (correct)" : "Error") << "\n";

    // Zero or negative block size
    tiny::Mat block3 = mat.block(0, 0, 0, 2);
    std::cout << "block(0, 0, 0, 2): " << (block3.data == nullptr ? "Empty (correct)" : "Error") << "\n";

    // G1.4: Invalid swap_rows parameters
    std::cout << "\n[G1.4] Invalid swap_rows Parameters\n";
    tiny::Mat mat2(3, 3);
    for (int i = 0; i < 3; ++i)
        for (int j = 0; j < 3; ++j)
            mat2(i, j) = i * 3 + j + 1;

    std::cout << "Before invalid swap_rows:\n";
    mat2.print_matrix(true);

    // Negative index
    mat2.swap_rows(-1, 1);
    std::cout << "After swap_rows(-1, 1):\n";
    mat2.print_matrix(true);

    // Index out of range
    mat2.swap_rows(0, 5);
    std::cout << "After swap_rows(0, 5):\n";
    mat2.print_matrix(true);

    // G1.5: Invalid swap_cols parameters
    std::cout << "\n[G1.5] Invalid swap_cols Parameters\n";
    tiny::Mat mat2_cols(3, 3);
    for (int i = 0; i < 3; ++i)
        for (int j = 0; j < 3; ++j)
            mat2_cols(i, j) = i * 3 + j + 1;

    std::cout << "Before invalid swap_cols:\n";
    mat2_cols.print_matrix(true);

    // Negative index
    mat2_cols.swap_cols(-1, 1);
    std::cout << "After swap_cols(-1, 1):\n";
    mat2_cols.print_matrix(true);

    // Index out of range
    mat2_cols.swap_cols(0, 5);
    std::cout << "After swap_cols(0, 5):\n";
    mat2_cols.print_matrix(true);

    // G1.6: Division by zero
    std::cout << "\n[G1.6] Division by Zero\n";
    tiny::Mat mat3(2, 2);
    mat3(0, 0) = 1; mat3(0, 1) = 2;
    mat3(1, 0) = 3; mat3(1, 1) = 4;

    tiny::Mat result = mat3 / 0.0f;
    std::cout << "mat3 / 0.0f: " << (result.data == nullptr ? "Empty (correct)" : "Error") << "\n";

    // G1.7: Matrix division with zero elements
    std::cout << "\n[G1.7] Matrix Division with Zero Elements\n";
    tiny::Mat mat4(2, 2);
    mat4(0, 0) = 1; mat4(0, 1) = 2;
    mat4(1, 0) = 3; mat4(1, 1) = 4;

    tiny::Mat divisor(2, 2);
    divisor(0, 0) = 1; divisor(0, 1) = 0;  // Contains zero
    divisor(1, 0) = 3; divisor(1, 1) = 4;

    mat4 /= divisor;
    std::cout << "mat4 /= divisor (with zero):\n";
    mat4.print_matrix(true);

    // G1.8: Empty matrix operations
    std::cout << "\n[G1.8] Empty Matrix Operations\n";
    tiny::Mat empty1(0, 0), empty2(0, 0);  // True empty matrices (0x0)
    tiny::Mat empty_sum = empty1 + empty2;
    // Empty matrix addition should return empty matrix (0x0) or error state
    bool empty_sum_correct = (empty_sum.row == 0 && empty_sum.col == 0) || 
                             (empty_sum.data == nullptr) ||
                             (empty_sum.row == 1 && empty_sum.col == 1 && empty_sum.data != nullptr);
    std::cout << "Empty matrix addition: " << (empty_sum_correct ? "Empty matrix or error state (Expected)" : "Non-empty (Error)") 
              << " " << (empty_sum_correct ? "[PASS]" : "[FAIL]") << "\n";
}

// ============================================================================
// G2: Quality Assurance - Performance Benchmarks Tests
// ============================================================================
// Purpose: Test performance characteristics - critical for real-time applications
void test_performance_benchmarks()
{
    std::cout << "\n[G2: Quality Assurance - Performance Benchmarks Tests]\n";

    // Ensure current task is added to watchdog before starting performance tests
    #if MCU_PLATFORM_SELECTED == MCU_PLATFORM_ESP32
    ensure_task_wdt_added();
    #endif

    // G2.1: Matrix Addition Performance (reduced size to prevent timeout)
    std::cout << "\n[G2.1] Matrix Addition Performance\n";
    tiny::Mat A(50, 50);  // Reduced from 100x100 to 50x50
    tiny::Mat B(50, 50);
    for (int i = 0; i < 50; ++i)
    {
        for (int j = 0; j < 50; ++j)
        {
            A(i, j) = static_cast<float>(i * 50 + j);
            B(i, j) = static_cast<float>(i * 50 + j + 1);
        }
    }
    TIME_REPEATED_OPERATION(tiny::Mat C = A + B;, PERFORMANCE_TEST_ITERATIONS, "50x50 Matrix Addition");

    // G2.2: Matrix Multiplication Performance (reduced size)
    std::cout << "\n[G2.2] Matrix Multiplication Performance\n";
    tiny::Mat D(30, 30);  // Reduced from 50x50 to 30x30
    tiny::Mat E(30, 30);
    for (int i = 0; i < 30; ++i)
    {
        for (int j = 0; j < 30; ++j)
        {
            D(i, j) = static_cast<float>(i * 30 + j);
            E(i, j) = static_cast<float>(i * 30 + j + 1);
        }
    }
    TIME_REPEATED_OPERATION(tiny::Mat F = D * E;, PERFORMANCE_TEST_ITERATIONS, "30x30 Matrix Multiplication");

    // G2.3: Matrix Transpose Performance (reduced size)
    std::cout << "\n[G2.3] Matrix Transpose Performance\n";
    tiny::Mat G(50, 30);  // Reduced from 100x50 to 50x30
    for (int i = 0; i < 50; ++i)
        for (int j = 0; j < 30; ++j)
            G(i, j) = static_cast<float>(i * 30 + j);
    TIME_REPEATED_OPERATION(tiny::Mat H = G.transpose();, PERFORMANCE_TEST_ITERATIONS, "50x30 Matrix Transpose");

    // G2.4: Determinant Performance Comparison
    // Note: Determinant calculation now has multiple methods:
    //   - Laplace expansion: O(n!) - for small matrices (n <= 4)
    //   - LU decomposition: O(n³) - for large matrices (n > 4, auto-selected)
    //   - Gaussian elimination: O(n³) - alternative for large matrices
    std::cout << "\n[G2.4] Determinant Calculation Performance Comparison\n";

    // G2.4.1: Small Matrix (4x4) - Laplace Expansion
        std::cout << "\n[G2.4.1] Small Matrix (4x4) - Laplace Expansion\n";
    tiny::Mat I4(4, 4);
    for (int i = 0; i < 4; ++i)
        for (int j = 0; j < 4; ++j)
            I4(i, j) = static_cast<float>(i * 4 + j + 1);

    feed_watchdog();
    TinyTimeMark_t det4_t0 = tiny_get_running_time();
    for (int i = 0; i < PERFORMANCE_TEST_ITERATIONS_HEAVY; ++i)
    {
        feed_watchdog();
        float det = I4.determinant_laplace();
        (void)det;
        feed_watchdog();
    }
    TinyTimeMark_t det4_t1 = tiny_get_running_time();
    double det4_dt_total_us = (double)(det4_t1 - det4_t0);
    double det4_dt_avg_us = det4_dt_total_us / PERFORMANCE_TEST_ITERATIONS_HEAVY;
    std::cout << "[Performance] 4x4 Determinant (Laplace, " << PERFORMANCE_TEST_ITERATIONS_HEAVY << " iterations): "
              << std::fixed << std::setprecision(2) << det4_dt_total_us << " us total, "
              << det4_dt_avg_us << " us avg\n";

    // G2.4.2: Large Matrix (8x8) - LU Decomposition
        std::cout << "\n[G2.4.2] Large Matrix (8x8) - LU Decomposition\n";
    tiny::Mat I8(8, 8);
    // Create a non-singular matrix (diagonally dominant matrix) for performance testing
    for (int i = 0; i < 8; ++i)
    {
        for (int j = 0; j < 8; ++j)
        {
            if (i == j)
                I8(i, j) = static_cast<float>(10 + i + 1);  // Diagonal dominance
            else
                I8(i, j) = static_cast<float>((i + 1) * (j + 1) * 0.1f);  // Off-diagonal elements
        }
    }

    feed_watchdog();
    TinyTimeMark_t det8_lu_t0 = tiny_get_running_time();
    for (int i = 0; i < PERFORMANCE_TEST_ITERATIONS_HEAVY; ++i)
    {
        feed_watchdog();
        float det = I8.determinant_lu();
        (void)det;
        feed_watchdog();
    }
    TinyTimeMark_t det8_lu_t1 = tiny_get_running_time();
    double det8_lu_dt_total_us = (double)(det8_lu_t1 - det8_lu_t0);
    double det8_lu_dt_avg_us = det8_lu_dt_total_us / PERFORMANCE_TEST_ITERATIONS_HEAVY;
    std::cout << "[Performance] 8x8 Determinant (LU, " << PERFORMANCE_TEST_ITERATIONS_HEAVY << " iterations): "
              << std::fixed << std::setprecision(2) << det8_lu_dt_total_us << " us total, "
              << det8_lu_dt_avg_us << " us avg\n";

    // G2.4.3: Large Matrix (8x8) - Gaussian Elimination
        std::cout << "\n[G2.4.3] Large Matrix (8x8) - Gaussian Elimination\n";
    feed_watchdog();
    TinyTimeMark_t det8_gauss_t0 = tiny_get_running_time();
    for (int i = 0; i < PERFORMANCE_TEST_ITERATIONS_HEAVY; ++i)
    {
        feed_watchdog();
        float det = I8.determinant_gaussian();
        (void)det;
        feed_watchdog();
    }
    TinyTimeMark_t det8_gauss_t1 = tiny_get_running_time();
    double det8_gauss_dt_total_us = (double)(det8_gauss_t1 - det8_gauss_t0);
    double det8_gauss_dt_avg_us = det8_gauss_dt_total_us / PERFORMANCE_TEST_ITERATIONS_HEAVY;
    std::cout << "[Performance] 8x8 Determinant (Gaussian, " << PERFORMANCE_TEST_ITERATIONS_HEAVY << " iterations): "
              << std::fixed << std::setprecision(2) << det8_gauss_dt_total_us << " us total, "
              << det8_gauss_dt_avg_us << " us avg\n";

    // G2.4.4: Auto-select Method (8x8) - Should use LU
        std::cout << "\n[G2.4.4] Large Matrix (8x8) - Auto-select Method\n";
    feed_watchdog();
    TinyTimeMark_t det8_auto_t0 = tiny_get_running_time();
    for (int i = 0; i < PERFORMANCE_TEST_ITERATIONS_HEAVY; ++i)
    {
        feed_watchdog();
        float det = I8.determinant();  // Auto-selects LU for n > 4
        (void)det;
        feed_watchdog();
    }
    TinyTimeMark_t det8_auto_t1 = tiny_get_running_time();
    double det8_auto_dt_total_us = (double)(det8_auto_t1 - det8_auto_t0);
    double det8_auto_dt_avg_us = det8_auto_dt_total_us / PERFORMANCE_TEST_ITERATIONS_HEAVY;
    std::cout << "[Performance] 8x8 Determinant (auto-select, " << PERFORMANCE_TEST_ITERATIONS_HEAVY << " iterations): "
              << std::fixed << std::setprecision(2) << det8_auto_dt_total_us << " us total, "
              << det8_auto_dt_avg_us << " us avg\n";

    std::cout << "\n[Note] Performance Summary:\n";
    std::cout << "  - Laplace expansion (O(n!)): Suitable only for small matrices (n <= 4)\n";
    std::cout << "  - LU decomposition (O(n³)): Efficient for large matrices, auto-selected for n > 4\n";
    std::cout << "  - Gaussian elimination (O(n³)): Alternative efficient method for large matrices\n";
    std::cout << "  - Auto-select: Automatically chooses the best method based on matrix size\n";

    // G2.5: Matrix Copy Performance (with padding, reduced size)
    std::cout << "\n[G2.5] Matrix Copy with Padding Performance\n";
    float data[80] = {0};  // Reduced from 150 to 80
    for (int i = 0; i < 80; ++i) data[i] = static_cast<float>(i);
    tiny::Mat J(data, 8, 8, 10);  // Reduced from 10x10 stride 15 to 8x8 stride 10
    TIME_REPEATED_OPERATION(tiny::Mat K = J.copy_roi(0, 0, 8, 8);, PERFORMANCE_TEST_ITERATIONS, "8x8 Copy ROI (with padding)");

    // G2.6: Element Access Performance (reduced size)
    std::cout << "\n[G2.6] Element Access Performance\n";
    tiny::Mat L(50, 50);  // Reduced from 100x100 to 50x50
    for (int i = 0; i < 50; ++i)
        for (int j = 0; j < 50; ++j)
            L(i, j) = static_cast<float>(i * 50 + j);

    // G2.6 continued: Element Access Performance (custom implementation for multi-line operation)
    float sum = 0.0f;
    std::cout << "[Performance] Computing element access (warmup)...\n";
    feed_watchdog();  // Feed watchdog before starting
    for (int w = 0; w < PERFORMANCE_TEST_WARMUP; ++w)
    {
        feed_watchdog();  // Feed watchdog before each warmup
        sum = 0.0f;
        for (int i = 0; i < 50; ++i)
            for (int j = 0; j < 50; ++j)
                sum += L(i, j);
        feed_watchdog();  // Feed watchdog after each warmup
    }

    TinyTimeMark_t elem_t0 = tiny_get_running_time();
    for (int i = 0; i < PERFORMANCE_TEST_ITERATIONS; ++i)
    {
        if (i % 20 == 0) feed_watchdog();  // Feed watchdog every 20 iterations (element access is fast)
        sum = 0.0f;
        for (int row = 0; row < 50; ++row)
            for (int col = 0; col < 50; ++col)
                sum += L(row, col);
    }
    feed_watchdog();  // Final feed after loop
    TinyTimeMark_t elem_t1 = tiny_get_running_time();
    double elem_dt_total_us = (double)(elem_t1 - elem_t0);
    double dt_avg_us = elem_dt_total_us / PERFORMANCE_TEST_ITERATIONS;
    std::cout << "[Performance] 50x50 Element Access (all elements) (" << PERFORMANCE_TEST_ITERATIONS << " iterations): "
              << std::fixed << std::setprecision(2) << elem_dt_total_us << " us total, "
              << dt_avg_us << " us avg\n";
}

// ============================================================================
// G3: Quality Assurance - Memory Layout Tests (Padding and Stride)
// ============================================================================
// Purpose: Test memory layout handling - important for performance and compatibility
void test_memory_layout()
{
    std::cout << "\n[G3: Quality Assurance - Memory Layout Tests (Padding and Stride)]\n";

    // G3.1: Contiguous memory (pad=0, step=1)
    std::cout << "\n[G3.1] Contiguous Memory (no padding)\n";
    tiny::Mat mat1(3, 4);
    for (int i = 0; i < 3; ++i)
        for (int j = 0; j < 4; ++j)
            mat1(i, j) = static_cast<float>(i * 4 + j);
    std::cout << "Matrix 3x4 (stride=4, pad=0):\n";
    mat1.print_info();
    mat1.print_matrix(true);

    // G3.2: Padded memory (stride > col)
    std::cout << "\n[G3.2] Padded Memory (stride > col)\n";
    float data[15] = {0, 1, 2, 3, 0, 4, 5, 6, 7, 0, 8, 9, 10, 11, 0};
    tiny::Mat mat2(data, 3, 4, 5);
    std::cout << "Matrix 3x4 (stride=5, pad=1):\n";
    mat2.print_info();
    mat2.print_matrix(true);

    // G3.3: Operations with padded matrices
    std::cout << "\n[G3.3] Addition with Padded Matrices\n";
    float data1[15] = {1, 2, 3, 4, 0, 5, 6, 7, 8, 0, 9, 10, 11, 12, 0};
    float data2[15] = {10, 20, 30, 40, 0, 50, 60, 70, 80, 0, 90, 100, 110, 120, 0};
    tiny::Mat mat3(data1, 3, 4, 5);
    tiny::Mat mat4(data2, 3, 4, 5);
    tiny::Mat mat5 = mat3 + mat4;
    std::cout << "Result of padded matrix addition:\n";
    mat5.print_info();
    mat5.print_matrix(true);

    // G3.4: ROI operations with padded matrices
    std::cout << "\n[G3.4] ROI Operations with Padded Matrices\n";
    tiny::Mat roi = mat2.view_roi(1, 1, 2, 2);
    std::cout << "ROI (1,1,2,2) from padded matrix:\n";
    roi.print_info();
    roi.print_matrix(true);

    // G3.5: Copy operations preserve stride
    std::cout << "\n[G3.5] Copy Operations Preserve Stride\n";
    tiny::Mat copied = mat2.copy_roi(0, 0, 3, 4);
    std::cout << "Copied matrix (should have stride=4, no padding):\n";
    copied.print_info();
    copied.print_matrix(true);
}

// ============================================================================
// E1: Matrix Decomposition
// ============================================================================
void test_matrix_decomposition()
{
    std::cout << "\n[E1: Matrix Decomposition Tests]\n";

    // E1.1: is_positive_definite() - Basic functionality
    std::cout << "\n[E1.1] is_positive_definite() - Basic Functionality\n";

    // E1.11: Positive definite matrix
    {
        std::cout << "\n[E1.11] Positive Definite 3x3 Matrix\n";
        tiny::Mat pd_mat(3, 3);
        pd_mat(0, 0) = 4.0f; pd_mat(0, 1) = 1.0f; pd_mat(0, 2) = 0.0f;
        pd_mat(1, 0) = 1.0f; pd_mat(1, 1) = 3.0f; pd_mat(1, 2) = 0.0f;
        pd_mat(2, 0) = 0.0f; pd_mat(2, 1) = 0.0f; pd_mat(2, 2) = 2.0f;
        std::cout << "Matrix:\n";
        pd_mat.print_matrix(true);

        bool is_pd = pd_mat.is_positive_definite(1e-6f);
        std::cout << "Is positive definite: " << (is_pd ? "True" : "False") 
                  << " (Expected: True) " << (is_pd ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E1.12: Non-positive definite matrix
    {
        std::cout << "\n[E1.12] Non-Positive Definite Matrix\n";
        tiny::Mat non_pd(2, 2);
        non_pd(0, 0) = 1.0f; non_pd(0, 1) = 2.0f;
        non_pd(1, 0) = 2.0f; non_pd(1, 1) = 1.0f;  // Has negative eigenvalue
        std::cout << "Matrix:\n";
        non_pd.print_matrix(true);

        bool is_pd = non_pd.is_positive_definite(1e-6f);
        std::cout << "Is positive definite: " << (is_pd ? "True" : "False") 
                  << " (Expected: False) " << (!is_pd ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E1.13: max_minors_to_check parameter
    {
        std::cout << "\n[E1.13] max_minors_to_check Parameter Testing\n";
        tiny::Mat pd_mat(4, 4);
        // Create a 4x4 positive definite matrix
        pd_mat(0, 0) = 4.0f; pd_mat(0, 1) = 1.0f; pd_mat(0, 2) = 0.0f; pd_mat(0, 3) = 0.0f;
        pd_mat(1, 0) = 1.0f; pd_mat(1, 1) = 3.0f; pd_mat(1, 2) = 0.0f; pd_mat(1, 3) = 0.0f;
        pd_mat(2, 0) = 0.0f; pd_mat(2, 1) = 0.0f; pd_mat(2, 2) = 2.0f; pd_mat(2, 3) = 0.5f;
        pd_mat(3, 0) = 0.0f; pd_mat(3, 1) = 0.0f; pd_mat(3, 2) = 0.5f; pd_mat(3, 3) = 1.5f;

        // Test with max_minors_to_check = -1 (check all minors)
        bool is_pd_all = pd_mat.is_positive_definite(1e-6f, -1);
        std::cout << "max_minors_to_check = -1 (check all): " << (is_pd_all ? "True" : "False") 
                  << " (Expected: True) " << (is_pd_all ? "[PASS]" : "[FAIL]") << "\n";

        // Test with max_minors_to_check = 3 (check first 3 minors)
        bool is_pd_partial = pd_mat.is_positive_definite(1e-6f, 3);
        std::cout << "max_minors_to_check = 3 (check first 3): " << (is_pd_partial ? "True" : "False") 
                  << " (Expected: True) " << (is_pd_partial ? "[PASS]" : "[FAIL]") << "\n";

        // Test with max_minors_to_check = 0 (should return false/error)
        bool is_pd_zero = pd_mat.is_positive_definite(1e-6f, 0);
        std::cout << "max_minors_to_check = 0 (invalid): " << (is_pd_zero ? "True" : "False") 
                  << " (Expected: False) " << (!is_pd_zero ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E1.14: Parameter validation - negative tolerance
    {
        std::cout << "\n[E1.14] Parameter Validation - Negative Tolerance\n";
        tiny::Mat pd_mat(2, 2);
        pd_mat(0, 0) = 2.0f; pd_mat(0, 1) = 0.0f;
        pd_mat(1, 0) = 0.0f; pd_mat(1, 1) = 2.0f;

        // Test with tolerance < 0 (should return false/error)
        bool is_pd_neg = pd_mat.is_positive_definite(-1e-6f);
        std::cout << "tolerance = -1e-6 (invalid): " << (is_pd_neg ? "True" : "False") 
                  << " (Expected: False) " << (!is_pd_neg ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E1.15: Boundary case - empty matrix
    {
        std::cout << "\n[E1.15] Boundary Case - Empty Matrix (0x0)\n";
        tiny::Mat empty_mat(0, 0);

        // Empty matrix cannot be positive definite (data is null or invalid dimensions)
        bool is_pd_empty = empty_mat.is_positive_definite(1e-6f);
        std::cout << "Empty matrix (0x0): " << (is_pd_empty ? "True" : "False") 
                  << " (Expected: False, empty matrix is invalid) " << (!is_pd_empty ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E1.16: Boundary case - invalid dimensions
    {
        std::cout << "\n[E1.16] Boundary Case - Invalid Dimensions\n";
        tiny::Mat invalid_mat(2, 3);  // Non-square matrix

        // Non-square matrix cannot be positive definite
        bool is_pd_invalid = invalid_mat.is_positive_definite(1e-6f);
        std::cout << "Non-square matrix (2x3): " << (is_pd_invalid ? "True" : "False") 
                  << " (Expected: False) " << (!is_pd_invalid ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E1.2: LU Decomposition
    std::cout << "\n[E1.2] LU Decomposition\n";

    // E1.21: Simple 3x3 matrix with pivoting
    {
        std::cout << "\n[E1.21] 3x3 Matrix - LU Decomposition with Pivoting\n";
        tiny::Mat A(3, 3);
        A(0, 0) = 2.0f; A(0, 1) = 1.0f; A(0, 2) = 1.0f;
        A(1, 0) = 4.0f; A(1, 1) = 3.0f; A(1, 2) = 3.0f;
        A(2, 0) = 2.0f; A(2, 1) = 1.0f; A(2, 2) = 2.0f;
        std::cout << "Matrix A:\n";
        A.print_matrix(true);

        tiny::Mat::LUDecomposition lu = A.lu_decompose(true);
        std::cout << "\n[Results]\n";
        std::cout << "Status: " << (lu.status == TINY_OK ? "OK" : "Error") << "\n";
        if (lu.status == TINY_OK)
        {
            std::cout << "L matrix (lower triangular):\n";
            lu.L.print_matrix(true);
            std::cout << "U matrix (upper triangular):\n";
            lu.U.print_matrix(true);
            if (lu.pivoted)
            {
                std::cout << "P matrix (permutation):\n";
                lu.P.print_matrix(true);
            }

            // Verify: P * A = L * U
            tiny::Mat PA = lu.P * A;
            tiny::Mat LU = lu.L * lu.U;
            std::cout << "\n[Verification] P * A should equal L * U\n";
            float diff = 0.0f;
            for (int i = 0; i < 3; ++i)
            {
                for (int j = 0; j < 3; ++j)
                {
                    diff += fabsf(PA(i, j) - LU(i, j));
                }
            }
            std::cout << "Total difference: " << diff << (diff < 0.01f ? " [PASS]" : " [FAIL]") << "\n";
        }
    }

    // E1.22: Solve using LU decomposition
    {
        std::cout << "\n[E1.22] Solve Linear System using LU Decomposition\n";
        tiny::Mat A(3, 3);
        A(0, 0) = 2.0f; A(0, 1) = 1.0f; A(0, 2) = 1.0f;
        A(1, 0) = 4.0f; A(1, 1) = 3.0f; A(1, 2) = 3.0f;
        A(2, 0) = 2.0f; A(2, 1) = 1.0f; A(2, 2) = 2.0f;
        tiny::Mat b(3, 1);
        b(0, 0) = 1.0f;
        b(1, 0) = 2.0f;
        b(2, 0) = 3.0f;

        std::cout << "System: A * x = b\n";
        std::cout << "A:\n";
        A.print_matrix(true);
        std::cout << "b:\n";
        b.print_matrix(true);

        tiny::Mat::LUDecomposition lu = A.lu_decompose(true);
        tiny::Mat x = tiny::Mat::solve_lu(lu, b);

        std::cout << "\n[Results]\n";
        std::cout << "Solution x:\n";
        x.print_matrix(true);

        // Verify: A * x = b
        tiny::Mat Ax = A * x;
        float error = 0.0f;
        for (int i = 0; i < 3; ++i)
        {
            error += fabsf(Ax(i, 0) - b(i, 0));
        }
        std::cout << "Verification error: " << error << (error < 0.01f ? " [PASS]" : " [FAIL]") << "\n";
    }

    // E1.26: solve_lu() - Boundary case - empty matrix
    {
        std::cout << "\n[E1.26] solve_lu() - Boundary Case - Empty Matrix\n";
        tiny::Mat empty_A(0, 0);
        tiny::Mat empty_b(0, 1);

        tiny::Mat::LUDecomposition lu_empty = empty_A.lu_decompose(true);
        tiny::Mat x_empty = tiny::Mat::solve_lu(lu_empty, empty_b);
        // Error case should return empty matrix (0x0) or error state (1x1 error matrix)
        bool empty_correct = (x_empty.row == 0 && x_empty.col == 0) || 
                            (x_empty.data == nullptr) ||
                            (x_empty.row == 1 && x_empty.col == 1 && x_empty.data != nullptr);
        std::cout << "Empty system: x rows = " << x_empty.row 
                  << " (Expected: 0 or error state) " << (empty_correct ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E1.27: solve_lu() - Invalid LU decomposition
    {
        std::cout << "\n[E1.27] solve_lu() - Invalid LU Decomposition\n";
        tiny::Mat::LUDecomposition invalid_lu;
        invalid_lu.status = TINY_ERR_INVALID_ARG;  // Simulate invalid decomposition

        tiny::Mat b(3, 1);
        b(0, 0) = 1.0f; b(1, 0) = 2.0f; b(2, 0) = 3.0f;

        tiny::Mat x_invalid = tiny::Mat::solve_lu(invalid_lu, b);
        // Error case should return empty matrix (0x0) or error state (1x1 error matrix)
        bool invalid_correct = (x_invalid.row == 0 && x_invalid.col == 0) || 
                               (x_invalid.data == nullptr) ||
                               (x_invalid.row == 1 && x_invalid.col == 1 && x_invalid.data != nullptr);
        std::cout << "Invalid LU decomposition: x rows = " << x_invalid.row 
                  << " (Expected: 0 or error state) " << (invalid_correct ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E1.23: Boundary case - empty matrix
    {
        std::cout << "\n[E1.23] Boundary Case - Empty Matrix (0x0)\n";
        tiny::Mat empty_mat(0, 0);

        tiny::Mat::LUDecomposition lu_empty = empty_mat.lu_decompose(true);
        // Error case: empty matrix should return error status, L may be 0x0 or 1x1 error matrix
        bool empty_correct = (lu_empty.status != TINY_OK) && 
                            ((lu_empty.L.row == 0 && lu_empty.L.col == 0) || 
                             (lu_empty.L.data == nullptr) ||
                             (lu_empty.L.row == 1 && lu_empty.L.col == 1 && lu_empty.L.data != nullptr));
        std::cout << "Empty matrix: Status = " << (lu_empty.status == TINY_OK ? "OK" : "Error") 
                  << ", L rows = " << lu_empty.L.row 
                  << " (Expected: Error status, L is 0x0 or error state) " << (empty_correct ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E1.24: lu_decompose() - without pivoting
    {
        std::cout << "\n[E1.24] LU Decomposition without Pivoting\n";
        tiny::Mat A(3, 3);
        A(0, 0) = 2.0f; A(0, 1) = 1.0f; A(0, 2) = 1.0f;
        A(1, 0) = 4.0f; A(1, 1) = 3.0f; A(1, 2) = 3.0f;
        A(2, 0) = 2.0f; A(2, 1) = 1.0f; A(2, 2) = 2.0f;

        tiny::Mat::LUDecomposition lu_no_pivot = A.lu_decompose(false);
        std::cout << "Status: " << (lu_no_pivot.status == TINY_OK ? "OK" : "Error") << "\n";
        std::cout << "Pivoted: " << (lu_no_pivot.pivoted ? "Yes" : "No (Expected)") 
                  << " " << (!lu_no_pivot.pivoted ? "[PASS]" : "[FAIL]") << "\n";
        if (lu_no_pivot.status == TINY_OK && !lu_no_pivot.pivoted)
        {
            // Verify: A = L * U (no permutation)
            tiny::Mat LU = lu_no_pivot.L * lu_no_pivot.U;
            float diff = 0.0f;
            for (int i = 0; i < 3; ++i)
            {
                for (int j = 0; j < 3; ++j)
                {
                    diff += fabsf(LU(i, j) - A(i, j));
                }
            }
            std::cout << "Verification (A = L * U): difference = " << diff 
                      << (diff < 0.01f ? " [PASS]" : " [FAIL]") << "\n";
        }
    }

    // E1.25: lu_decompose() - Error handling - non-square matrix
    {
        std::cout << "\n[E1.25] lu_decompose() - Error Handling - Non-Square Matrix\n";
        tiny::Mat non_square(2, 3);
        tiny::Mat::LUDecomposition lu_non_square = non_square.lu_decompose(true);
        std::cout << "Non-square matrix (2x3): Status = " << (lu_non_square.status == TINY_OK ? "OK" : "Error (Expected)") 
                  << " " << (lu_non_square.status != TINY_OK ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E1.3: Cholesky Decomposition
    std::cout << "\n[E1.3] Cholesky Decomposition\n";

    // E1.31: Symmetric positive definite matrix
    {
        std::cout << "\n[E1.31] SPD Matrix - Cholesky Decomposition\n";
        tiny::Mat spd(3, 3);
        spd(0, 0) = 4.0f; spd(0, 1) = 2.0f; spd(0, 2) = 0.0f;
        spd(1, 0) = 2.0f; spd(1, 1) = 5.0f; spd(1, 2) = 1.0f;
        spd(2, 0) = 0.0f; spd(2, 1) = 1.0f; spd(2, 2) = 3.0f;
        std::cout << "Matrix A (SPD):\n";
        spd.print_matrix(true);

        tiny::Mat::CholeskyDecomposition chol = spd.cholesky_decompose();
        std::cout << "\n[Results]\n";
        std::cout << "Status: " << (chol.status == TINY_OK ? "OK" : "Error") << "\n";
        if (chol.status == TINY_OK)
        {
            std::cout << "L matrix (lower triangular):\n";
            chol.L.print_matrix(true);

            // Verify: A = L * L^T
            tiny::Mat LLT = chol.L * chol.L.transpose();
            std::cout << "\n[Verification] L * L^T should equal A\n";
            float diff = 0.0f;
            for (int i = 0; i < 3; ++i)
            {
                for (int j = 0; j < 3; ++j)
                {
                    diff += fabsf(LLT(i, j) - spd(i, j));
                }
            }
            std::cout << "Total difference: " << diff << (diff < 0.01f ? " [PASS]" : " [FAIL]") << "\n";
        }
    }

    // E1.32: Solve using Cholesky decomposition
    {
        std::cout << "\n[E1.32] Solve Linear System using Cholesky Decomposition\n";
        tiny::Mat A(3, 3);
        A(0, 0) = 4.0f; A(0, 1) = 2.0f; A(0, 2) = 0.0f;
        A(1, 0) = 2.0f; A(1, 1) = 5.0f; A(1, 2) = 1.0f;
        A(2, 0) = 0.0f; A(2, 1) = 1.0f; A(2, 2) = 3.0f;
        tiny::Mat b(3, 1);
        b(0, 0) = 2.0f;
        b(1, 0) = 3.0f;
        b(2, 0) = 1.0f;

        tiny::Mat::CholeskyDecomposition chol = A.cholesky_decompose();
        tiny::Mat x = tiny::Mat::solve_cholesky(chol, b);

        std::cout << "Solution x:\n";
        x.print_matrix(true);

        // Verify: A * x = b
        tiny::Mat Ax = A * x;
        float error = 0.0f;
        for (int i = 0; i < 3; ++i)
        {
            error += fabsf(Ax(i, 0) - b(i, 0));
        }
        std::cout << "Verification error: " << error << (error < 0.01f ? " [PASS]" : " [FAIL]") << "\n";
    }

    // E1.35: solve_cholesky() - Boundary case - empty matrix
    {
        std::cout << "\n[E1.35] solve_cholesky() - Boundary Case - Empty Matrix\n";
        tiny::Mat empty_A(0, 0);
        tiny::Mat empty_b(0, 1);

        tiny::Mat::CholeskyDecomposition chol_empty = empty_A.cholesky_decompose();
        tiny::Mat x_empty = tiny::Mat::solve_cholesky(chol_empty, empty_b);
        // Error case should return empty matrix (0x0) or error state (1x1 error matrix)
        bool empty_correct = (x_empty.row == 0 && x_empty.col == 0) || 
                            (x_empty.data == nullptr) ||
                            (x_empty.row == 1 && x_empty.col == 1 && x_empty.data != nullptr);
        std::cout << "Empty system: x rows = " << x_empty.row 
                  << " (Expected: 0 or error state) " << (empty_correct ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E1.36: solve_cholesky() - Invalid Cholesky decomposition
    {
        std::cout << "\n[E1.36] solve_cholesky() - Invalid Cholesky Decomposition\n";
        tiny::Mat::CholeskyDecomposition invalid_chol;
        invalid_chol.status = TINY_ERR_INVALID_ARG;  // Simulate invalid decomposition

        tiny::Mat b(3, 1);
        b(0, 0) = 1.0f; b(1, 0) = 2.0f; b(2, 0) = 3.0f;

        tiny::Mat x_invalid = tiny::Mat::solve_cholesky(invalid_chol, b);
        // Error case should return empty matrix (0x0) or error state (1x1 error matrix)
        bool invalid_correct = (x_invalid.row == 0 && x_invalid.col == 0) || 
                               (x_invalid.data == nullptr) ||
                               (x_invalid.row == 1 && x_invalid.col == 1 && x_invalid.data != nullptr);
        std::cout << "Invalid Cholesky decomposition: x rows = " << x_invalid.row 
                  << " (Expected: 0 or error state) " << (invalid_correct ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E1.33: Boundary case - empty matrix
    {
        std::cout << "\n[E1.33] Boundary Case - Empty Matrix (0x0)\n";
        tiny::Mat empty_mat(0, 0);

        tiny::Mat::CholeskyDecomposition chol_empty = empty_mat.cholesky_decompose();
        // Error case: empty matrix should return error status, L may be 0x0 or 1x1 error matrix
        bool empty_correct = (chol_empty.status != TINY_OK) && 
                            ((chol_empty.L.row == 0 && chol_empty.L.col == 0) || 
                             (chol_empty.L.data == nullptr) ||
                             (chol_empty.L.row == 1 && chol_empty.L.col == 1 && chol_empty.L.data != nullptr));
        std::cout << "Empty matrix: Status = " << (chol_empty.status == TINY_OK ? "OK" : "Error") 
                  << ", L rows = " << chol_empty.L.row 
                  << " (Expected: Error status, L is 0x0 or error state) " << (empty_correct ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E1.34: Non-symmetric matrix (should fail)
    {
        std::cout << "\n[E1.34] Non-Symmetric Matrix (Should Fail)\n";
        tiny::Mat non_sym(2, 2);
        non_sym(0, 0) = 1.0f; non_sym(0, 1) = 2.0f;
        non_sym(1, 0) = 3.0f; non_sym(1, 1) = 4.0f;  // Non-symmetric

        tiny::Mat::CholeskyDecomposition chol_non_sym = non_sym.cholesky_decompose();
        std::cout << "Non-symmetric matrix: Status = " << (chol_non_sym.status == TINY_OK ? "OK" : "Error (Expected)") 
                  << " " << (chol_non_sym.status != TINY_OK ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E1.37: solve_cholesky() - Error handling - dimension mismatch
    {
        std::cout << "\n[E1.37] solve_cholesky() - Error Handling - Dimension Mismatch\n";
        tiny::Mat A(3, 3);
        A(0, 0) = 4.0f; A(0, 1) = 2.0f; A(0, 2) = 0.0f;
        A(1, 0) = 2.0f; A(1, 1) = 5.0f; A(1, 2) = 1.0f;
        A(2, 0) = 0.0f; A(2, 1) = 1.0f; A(2, 2) = 3.0f;
        tiny::Mat b(4, 1);  // Wrong dimension
        tiny::Mat::CholeskyDecomposition chol = A.cholesky_decompose();
        if (chol.status == TINY_OK)
        {
            tiny::Mat x_mismatch = tiny::Mat::solve_cholesky(chol, b);
            // Error case should return empty matrix (0x0) or error state (1x1 error matrix)
            // For dimension mismatch, expected solution size is 3x1, so 1x1 indicates error
            bool solve_mismatch_correct = (x_mismatch.row == 0 && x_mismatch.col == 0) || 
                                         (x_mismatch.data == nullptr) ||
                                         (x_mismatch.row == 1 && x_mismatch.col == 1 && x_mismatch.data != nullptr);
            std::cout << "Dimension mismatch solve_cholesky: " << (solve_mismatch_correct ? "Empty matrix or error state (Expected)" : "Non-empty (Error)") 
                      << " " << (solve_mismatch_correct ? "[PASS]" : "[FAIL]") << "\n";
        }
    }

    // E1.4: QR Decomposition
    std::cout << "\n[E1.4] QR Decomposition\n";

    // E1.41: General matrix
    {
        std::cout << "\n[E1.41] General 3x3 Matrix - QR Decomposition\n";
        tiny::Mat A(3, 3);
        A(0, 0) = 1.0f; A(0, 1) = 2.0f; A(0, 2) = 3.0f;
        A(1, 0) = 4.0f; A(1, 1) = 5.0f; A(1, 2) = 6.0f;
        A(2, 0) = 7.0f; A(2, 1) = 8.0f; A(2, 2) = 9.0f;
        std::cout << "Matrix A:\n";
        A.print_matrix(true);

        tiny::Mat::QRDecomposition qr = A.qr_decompose();
        std::cout << "\n[Results]\n";
        std::cout << "Status: " << (qr.status == TINY_OK ? "OK" : "Error") << "\n";
        if (qr.status == TINY_OK)
        {
            std::cout << "Q matrix (orthogonal):\n";
            qr.Q.print_matrix(true);
            std::cout << "R matrix (upper triangular):\n";
            qr.R.print_matrix(true);

            // Verify: A = Q * R
            tiny::Mat QR = qr.Q * qr.R;
            std::cout << "\n[Verification] Q * R should equal A\n";
            float diff = 0.0f;
            for (int i = 0; i < 3; ++i)
            {
                for (int j = 0; j < 3; ++j)
                {
                    diff += fabsf(QR(i, j) - A(i, j));
                }
            }
            std::cout << "Total difference: " << diff << (diff < 0.1f ? " [PASS]" : " [FAIL]") << "\n";

            // Verify Q is orthogonal: Q^T * Q = I
            tiny::Mat QtQ = qr.Q.transpose() * qr.Q;
            tiny::Mat I = tiny::Mat::eye(3);
            float ortho_diff = 0.0f;
            for (int i = 0; i < 3; ++i)
            {
                for (int j = 0; j < 3; ++j)
                {
                    ortho_diff += fabsf(QtQ(i, j) - I(i, j));
                }
            }
            std::cout << "Q orthogonality error: " << ortho_diff << (ortho_diff < 0.1f ? " [PASS]" : " [FAIL]") << "\n";
        }
    }

    // E1.42: Solve using QR decomposition (least squares)
    {
        std::cout << "\n[E1.42] Least Squares Solution using QR Decomposition\n";
        tiny::Mat A(3, 2);  // Overdetermined system
        A(0, 0) = 1.0f; A(0, 1) = 1.0f;
        A(1, 0) = 1.0f; A(1, 1) = 2.0f;
        A(2, 0) = 1.0f; A(2, 1) = 3.0f;
        tiny::Mat b(3, 1);
        b(0, 0) = 2.0f;
        b(1, 0) = 3.0f;
        b(2, 0) = 4.0f;

        std::cout << "Overdetermined system: A * x ≈ b\n";
        std::cout << "A:\n";
        A.print_matrix(true);
        std::cout << "b:\n";
        b.print_matrix(true);

        tiny::Mat::QRDecomposition qr = A.qr_decompose();
        tiny::Mat x = tiny::Mat::solve_qr(qr, b);

        std::cout << "\n[Results]\n";
        std::cout << "Least squares solution x:\n";
        x.print_matrix(true);

        // Compute residual: ||A * x - b||
        tiny::Mat Ax = A * x;
        tiny::Mat residual = Ax - b;
        float residual_norm = 0.0f;
        for (int i = 0; i < 3; ++i)
        {
            residual_norm += residual(i, 0) * residual(i, 0);
        }
        residual_norm = sqrtf(residual_norm);
        std::cout << "Residual norm ||A*x - b||: " << residual_norm << "\n";
    }

    // E1.46: solve_qr() - Boundary case - empty matrix
    {
        std::cout << "\n[E1.46] solve_qr() - Boundary Case - Empty Matrix\n";
        tiny::Mat empty_A(0, 0);
        tiny::Mat empty_b(0, 1);

        tiny::Mat::QRDecomposition qr_empty = empty_A.qr_decompose();
        tiny::Mat x_empty = tiny::Mat::solve_qr(qr_empty, empty_b);
        // Error case should return empty matrix (0x0) or error state (1x1 error matrix)
        bool empty_correct = (x_empty.row == 0 && x_empty.col == 0) || 
                            (x_empty.data == nullptr) ||
                            (x_empty.row == 1 && x_empty.col == 1 && x_empty.data != nullptr);
        std::cout << "Empty system: x rows = " << x_empty.row 
                  << " (Expected: 0 or error state) " << (empty_correct ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E1.47: solve_qr() - Invalid QR decomposition
    {
        std::cout << "\n[E1.47] solve_qr() - Invalid QR Decomposition\n";
        tiny::Mat::QRDecomposition invalid_qr;
        invalid_qr.status = TINY_ERR_INVALID_ARG;  // Simulate invalid decomposition

        tiny::Mat b(3, 1);
        b(0, 0) = 1.0f; b(1, 0) = 2.0f; b(2, 0) = 3.0f;

        tiny::Mat x_invalid = tiny::Mat::solve_qr(invalid_qr, b);
        // Error case should return empty matrix (0x0) or error state (1x1 error matrix)
        bool invalid_correct = (x_invalid.row == 0 && x_invalid.col == 0) || 
                               (x_invalid.data == nullptr) ||
                               (x_invalid.row == 1 && x_invalid.col == 1 && x_invalid.data != nullptr);
        std::cout << "Invalid QR decomposition: x rows = " << x_invalid.row 
                  << " (Expected: 0 or error state) " << (invalid_correct ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E1.43: Boundary case - empty matrix
    {
        std::cout << "\n[E1.43] Boundary Case - Empty Matrix (0x0)\n";
        tiny::Mat empty_mat(0, 0);

        tiny::Mat::QRDecomposition qr_empty = empty_mat.qr_decompose();
        // Error case: empty matrix should return error status, Q may be 0x0 or 1x1 error matrix
        bool empty_correct = (qr_empty.status != TINY_OK) && 
                            ((qr_empty.Q.row == 0 && qr_empty.Q.col == 0) || 
                             (qr_empty.Q.data == nullptr) ||
                             (qr_empty.Q.row == 1 && qr_empty.Q.col == 1 && qr_empty.Q.data != nullptr));
        std::cout << "Empty matrix: Status = " << (qr_empty.status == TINY_OK ? "OK" : "Error") 
                  << ", Q rows = " << qr_empty.Q.row 
                  << " (Expected: Error status, Q is 0x0 or error state) " << (empty_correct ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E1.44: Boundary case - m=0 or n=0
    {
        std::cout << "\n[E1.44] Boundary Case - Zero Rows or Columns\n";
        tiny::Mat zero_rows(0, 3);
        tiny::Mat zero_cols(3, 0);

        tiny::Mat::QRDecomposition qr_zero_rows = zero_rows.qr_decompose();
        // Zero rows/cols should return error status (invalid matrix)
        std::cout << "Matrix with 0 rows (0x3): Status = " << (qr_zero_rows.status == TINY_OK ? "OK" : "Error") 
                  << " " << (qr_zero_rows.status != TINY_OK ? "[PASS]" : "[FAIL]") << "\n";

        tiny::Mat::QRDecomposition qr_zero_cols = zero_cols.qr_decompose();
        // Zero rows/cols should return error status (invalid matrix)
        std::cout << "Matrix with 0 cols (3x0): Status = " << (qr_zero_cols.status == TINY_OK ? "OK" : "Error") 
                  << " " << (qr_zero_cols.status != TINY_OK ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E1.45: solve_qr() - Error handling - dimension mismatch
    {
        std::cout << "\n[E1.45] solve_qr() - Error Handling - Dimension Mismatch\n";
        tiny::Mat A(3, 2);
        tiny::Mat b(4, 1);  // Wrong dimension
        tiny::Mat::QRDecomposition qr = A.qr_decompose();
        if (qr.status == TINY_OK)
        {
            tiny::Mat x_mismatch = tiny::Mat::solve_qr(qr, b);
            // Error case should return empty matrix (0x0) or error state (1x1 error matrix)
            // For dimension mismatch, expected solution size is 2x1, so 1x1 indicates error
            bool solve_mismatch_correct = (x_mismatch.row == 0 && x_mismatch.col == 0) || 
                                         (x_mismatch.data == nullptr) ||
                                         (x_mismatch.row == 1 && x_mismatch.col == 1 && x_mismatch.data != nullptr);
            std::cout << "Dimension mismatch solve_qr: " << (solve_mismatch_correct ? "Empty matrix or error state (Expected)" : "Non-empty (Error)") 
                      << " " << (solve_mismatch_correct ? "[PASS]" : "[FAIL]") << "\n";
        }
    }

    // E1.5: SVD Decomposition
    std::cout << "\n[E1.5] Singular Value Decomposition (SVD)\n";

    // E1.51: General matrix
    {
        std::cout << "\n[E1.51] General 3x3 Matrix - SVD Decomposition\n";
        tiny::Mat A(3, 3);
        A(0, 0) = 1.0f; A(0, 1) = 2.0f; A(0, 2) = 3.0f;
        A(1, 0) = 4.0f; A(1, 1) = 5.0f; A(1, 2) = 6.0f;
        A(2, 0) = 7.0f; A(2, 1) = 8.0f; A(2, 2) = 9.0f;
        std::cout << "Matrix A:\n";
        A.print_matrix(true);

        tiny::Mat::SVDDecomposition svd = A.svd_decompose(100, 1e-6f);
        std::cout << "\n[Results]\n";
        std::cout << "Status: " << (svd.status == TINY_OK ? "OK" : "Error") << "\n";
        if (svd.status == TINY_OK)
        {
            std::cout << "Singular values:\n";
            svd.S.print_matrix(true);
            std::cout << "Numerical rank: " << svd.rank << "\n";
            std::cout << "Iterations: " << svd.iterations << "\n";

            // Verify: A ≈ U * S * V^T (for first rank columns)
            if (svd.rank > 0)
            {
                tiny::Mat US(svd.U.row, svd.rank);
                for (int i = 0; i < svd.U.row; ++i)
                {
                    for (int j = 0; j < svd.rank; ++j)
                    {
                        US(i, j) = svd.U(i, j) * svd.S(j, 0);
                    }
                }
                tiny::Mat Vt(svd.rank, svd.V.row);
                for (int i = 0; i < svd.rank; ++i)
                {
                    for (int j = 0; j < svd.V.row; ++j)
                    {
                        Vt(i, j) = svd.V(j, i);  // V^T
                    }
                }
                tiny::Mat USVt = US * Vt;

                float diff = 0.0f;
                for (int i = 0; i < 3; ++i)
                {
                    for (int j = 0; j < 3; ++j)
                    {
                        diff += fabsf(USVt(i, j) - A(i, j));
                    }
                }
                std::cout << "Reconstruction error: " << diff << (diff < 0.5f ? " [PASS]" : " [FAIL]") << "\n";
            }
        }
    }

    // E1.52: Pseudo-inverse using SVD
    {
        std::cout << "\n[E1.52] Pseudo-inverse using SVD\n";
        tiny::Mat A(3, 2);  // Non-square matrix
        A(0, 0) = 1.0f; A(0, 1) = 2.0f;
        A(1, 0) = 3.0f; A(1, 1) = 4.0f;
        A(2, 0) = 5.0f; A(2, 1) = 6.0f;

        std::cout << "Matrix A (3x2):\n";
        A.print_matrix(true);

        tiny::Mat::SVDDecomposition svd = A.svd_decompose(100, 1e-6f);
        tiny::Mat A_plus = tiny::Mat::pseudo_inverse(svd, 1e-6f);

        std::cout << "\n[Results]\n";
        std::cout << "Pseudo-inverse A^+ (2x3):\n";
        A_plus.print_matrix(true);

        // Verify: A * A^+ * A ≈ A
        tiny::Mat AAplusA = A * A_plus * A;
        float diff = 0.0f;
        for (int i = 0; i < 3; ++i)
        {
            for (int j = 0; j < 2; ++j)
            {
                diff += fabsf(AAplusA(i, j) - A(i, j));
            }
        }
        std::cout << "Verification error (A * A^+ * A ≈ A): " << diff << (diff < 0.1f ? " [PASS]" : " [FAIL]") << "\n";
    }

    // E1.57: pseudo_inverse() - Parameter validation - tolerance < 0
    {
        std::cout << "\n[E1.57] pseudo_inverse() - Parameter Validation - tolerance < 0\n";
        tiny::Mat test_mat(2, 2);
        test_mat(0, 0) = 1.0f; test_mat(0, 1) = 2.0f;
        test_mat(1, 0) = 3.0f; test_mat(1, 1) = 4.0f;

        tiny::Mat::SVDDecomposition svd = test_mat.svd_decompose(100, 1e-6f);
        if (svd.status == TINY_OK)
        {
            tiny::Mat A_plus_neg = tiny::Mat::pseudo_inverse(svd, -1e-6f);
            // Error case should return empty matrix (0x0) or error state (1x1 error matrix)
            bool neg_tol_correct = (A_plus_neg.row == 0 && A_plus_neg.col == 0) || 
                                  (A_plus_neg.data == nullptr) ||
                                  (A_plus_neg.row == 1 && A_plus_neg.col == 1 && A_plus_neg.data != nullptr);
            std::cout << "tolerance = -1e-6: A_plus rows = " << A_plus_neg.row 
                      << " (Expected: 0 or error state) " << (neg_tol_correct ? "[PASS]" : "[FAIL]") << "\n";
        }
    }

    // E1.58: pseudo_inverse() - Invalid SVD decomposition
    {
        std::cout << "\n[E1.58] pseudo_inverse() - Invalid SVD Decomposition\n";
        tiny::Mat::SVDDecomposition invalid_svd;
        invalid_svd.status = TINY_ERR_INVALID_ARG;  // Simulate invalid decomposition

        tiny::Mat A_plus_invalid = tiny::Mat::pseudo_inverse(invalid_svd, 1e-6f);
        // Error case should return empty matrix (0x0) or error state (1x1 error matrix)
        bool pseudo_inv_invalid_correct = (A_plus_invalid.row == 0 && A_plus_invalid.col == 0) || 
                                          (A_plus_invalid.data == nullptr) ||
                                          (A_plus_invalid.row == 1 && A_plus_invalid.col == 1 && A_plus_invalid.data != nullptr);
        std::cout << "Invalid SVD decomposition: A_plus rows = " << A_plus_invalid.row 
                  << " (Expected: 0 or error state) " << (pseudo_inv_invalid_correct ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E1.53: Parameter validation - max_iter <= 0
    {
        std::cout << "\n[E1.53] Parameter Validation - max_iter <= 0\n";
        tiny::Mat test_mat(2, 2);
        test_mat(0, 0) = 1.0f; test_mat(0, 1) = 2.0f;
        test_mat(1, 0) = 3.0f; test_mat(1, 1) = 4.0f;

        tiny::Mat::SVDDecomposition result_zero = test_mat.svd_decompose(0, 1e-6f);
        std::cout << "max_iter = 0: Status = " << (result_zero.status == TINY_OK ? "OK" : "Error (Expected)") 
                  << " " << (result_zero.status != TINY_OK ? "[PASS]" : "[FAIL]") << "\n";

        tiny::Mat::SVDDecomposition result_neg = test_mat.svd_decompose(-1, 1e-6f);
        std::cout << "max_iter = -1: Status = " << (result_neg.status == TINY_OK ? "OK" : "Error (Expected)") 
                  << " " << (result_neg.status != TINY_OK ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E1.54: Parameter validation - tolerance < 0
    {
        std::cout << "\n[E1.54] Parameter Validation - tolerance < 0\n";
        tiny::Mat test_mat(2, 2);
        test_mat(0, 0) = 1.0f; test_mat(0, 1) = 2.0f;
        test_mat(1, 0) = 3.0f; test_mat(1, 1) = 4.0f;

        tiny::Mat::SVDDecomposition result_neg = test_mat.svd_decompose(100, -1e-6f);
        std::cout << "tolerance = -1e-6: Status = " << (result_neg.status == TINY_OK ? "OK" : "Error (Expected)") 
                  << " " << (result_neg.status != TINY_OK ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E1.55: Boundary case - empty matrix (m=0 or n=0)
    {
        std::cout << "\n[E1.55] Boundary Case - Empty Matrix (m=0 or n=0)\n";
        tiny::Mat zero_rows(0, 3);
        tiny::Mat zero_cols(3, 0);

        tiny::Mat::SVDDecomposition svd_zero_rows = zero_rows.svd_decompose(100, 1e-6f);
        // Zero rows/cols should return error status (invalid matrix)
        std::cout << "Matrix with 0 rows (0x3): Status = " << (svd_zero_rows.status == TINY_OK ? "OK" : "Error") 
                  << " " << (svd_zero_rows.status != TINY_OK ? "[PASS]" : "[FAIL]") << "\n";

        tiny::Mat::SVDDecomposition svd_zero_cols = zero_cols.svd_decompose(100, 1e-6f);
        // Zero rows/cols should return error status (invalid matrix)
        std::cout << "Matrix with 0 cols (3x0): Status = " << (svd_zero_cols.status == TINY_OK ? "OK" : "Error") 
                  << " " << (svd_zero_cols.status != TINY_OK ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E1.56: pseudo_inverse() - Error handling - invalid SVD decomposition
    {
        std::cout << "\n[E1.56] pseudo_inverse() - Error Handling - Invalid SVD Decomposition\n";
        tiny::Mat::SVDDecomposition invalid_svd;
        invalid_svd.status = TINY_ERR_INVALID_ARG;  // Simulate invalid decomposition

        tiny::Mat A_plus_invalid = tiny::Mat::pseudo_inverse(invalid_svd, 1e-6f);
        // Error case should return empty matrix (0x0) or error state (1x1 error matrix)
        bool pseudo_inv_invalid_correct = (A_plus_invalid.row == 0 && A_plus_invalid.col == 0) || 
                                          (A_plus_invalid.data == nullptr) ||
                                          (A_plus_invalid.row == 1 && A_plus_invalid.col == 1 && A_plus_invalid.data != nullptr);
        std::cout << "Invalid SVD decomposition: A_plus rows = " << A_plus_invalid.row 
                  << " (Expected: 0 or error state) " << (pseudo_inv_invalid_correct ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E1.6: Performance Tests
    std::cout << "\n[E1.6] Matrix Decomposition Performance Tests\n";

    tiny::Mat perf_mat(4, 4);
    perf_mat(0, 0) = 4.0f; perf_mat(0, 1) = 2.0f; perf_mat(0, 2) = 1.0f; perf_mat(0, 3) = 0.0f;
    perf_mat(1, 0) = 2.0f; perf_mat(1, 1) = 5.0f; perf_mat(1, 2) = 1.0f; perf_mat(1, 3) = 0.0f;
    perf_mat(2, 0) = 1.0f; perf_mat(2, 1) = 1.0f; perf_mat(2, 2) = 3.0f; perf_mat(2, 3) = 1.0f;
    perf_mat(3, 0) = 0.0f; perf_mat(3, 1) = 0.0f; perf_mat(3, 2) = 1.0f; perf_mat(3, 3) = 2.0f;

    // E1.61: LU decomposition performance
    std::cout << "\n[E1.61] LU Decomposition Performance\n";
    TIME_OPERATION(
        tiny::Mat::LUDecomposition perf_lu = perf_mat.lu_decompose(true);
        (void)perf_lu;
    , "LU Decomposition (4x4 matrix)");

    // E1.62: Cholesky decomposition performance
    std::cout << "\n[E1.62] Cholesky Decomposition Performance\n";
    TIME_OPERATION(
        tiny::Mat::CholeskyDecomposition perf_chol = perf_mat.cholesky_decompose();
        (void)perf_chol;
    , "Cholesky Decomposition (4x4 SPD matrix)");

    // E1.63: QR decomposition performance
    std::cout << "\n[E1.63] QR Decomposition Performance\n";
    TIME_OPERATION(
        tiny::Mat::QRDecomposition perf_qr = perf_mat.qr_decompose();
        (void)perf_qr;
    , "QR Decomposition (4x4 matrix)");

    // E1.64: SVD decomposition performance
    std::cout << "\n[E1.64] SVD Decomposition Performance\n";
    TIME_OPERATION(
        tiny::Mat::SVDDecomposition perf_svd = perf_mat.svd_decompose(50, 1e-5f);
        (void)perf_svd;
    , "SVD Decomposition (4x4 matrix)");

    std::cout << "\n[Matrix Decomposition Tests Complete]\n";
}

// ============================================================================
// ============================================================================
// E2: Gram-Schmidt Orthogonalization
// ============================================================================
void test_gram_schmidt_orthogonalize()
{
    std::cout << "\n[E2: Gram-Schmidt Orthogonalization Tests]\n";

    // E2.1: Basic orthogonalization of linearly independent vectors
    {
        std::cout << "\n[E2.1] Basic Orthogonalization - Linearly Independent Vectors\n";
        tiny::Mat vectors(3, 3);
        // Create three linearly independent vectors
        vectors(0, 0) = 1.0f; vectors(0, 1) = 1.0f; vectors(0, 2) = 0.0f;
        vectors(1, 0) = 0.0f; vectors(1, 1) = 1.0f; vectors(1, 2) = 1.0f;
        vectors(2, 0) = 1.0f; vectors(2, 1) = 0.0f; vectors(2, 2) = 1.0f;

        std::cout << "Input vectors (each column is a vector):\n";
        vectors.print_matrix(true);

        tiny::Mat Q, R;
        bool success = tiny::Mat::gram_schmidt_orthogonalize(vectors, Q, R, 1e-6f);

        std::cout << "\n[Results]\n";
        std::cout << "Status: " << (success ? "OK" : "Error") << "\n";
        if (success)
        {
            std::cout << "Orthogonalized vectors Q (each column is orthogonal):\n";
            Q.print_matrix(true);
            std::cout << "Coefficients R (upper triangular):\n";
            R.print_matrix(true);

            // Verify orthogonality: Q^T * Q should be identity (or close to it)
            tiny::Mat QtQ = Q.transpose() * Q;
            tiny::Mat I = tiny::Mat::eye(3);
            float ortho_error = 0.0f;
            for (int i = 0; i < 3; ++i)
            {
                for (int j = 0; j < 3; ++j)
                {
                    ortho_error += fabsf(QtQ(i, j) - I(i, j));
                }
            }
            std::cout << "\n[Verification] Q^T * Q should be identity\n";
            std::cout << "Orthogonality error: " << ortho_error 
                      << (ortho_error < 0.1f ? " [PASS]" : " [FAIL]") << "\n";

            // Verify normalization: each column of Q should be unit vector
            std::cout << "\n[Verification] Each column of Q should be normalized\n";
            bool all_normalized = true;
            for (int j = 0; j < 3; ++j)
            {
                float norm = 0.0f;
                for (int i = 0; i < 3; ++i)
                {
                    norm += Q(i, j) * Q(i, j);
                }
                norm = sqrtf(norm);
                float norm_error = fabsf(norm - 1.0f);
                std::cout << "  Column " << j << " norm: " << norm 
                          << " (error: " << norm_error << ")";
                if (norm_error > 0.01f)
                {
                    all_normalized = false;
                    std::cout << " [FAIL]";
                }
                else
                {
                    std::cout << " [PASS]";
                }
                std::cout << "\n";
            }

            // Verify reconstruction: vectors should equal Q * R (approximately)
            tiny::Mat QR = Q * R;
            float recon_error = 0.0f;
            for (int i = 0; i < 3; ++i)
            {
                for (int j = 0; j < 3; ++j)
                {
                    recon_error += fabsf(QR(i, j) - vectors(i, j));
                }
            }
            std::cout << "\n[Verification] Q * R should reconstruct original vectors\n";
            std::cout << "Reconstruction error: " << recon_error 
                      << (recon_error < 0.1f ? " [PASS]" : " [FAIL]") << "\n";
        }
    }

    // E2.2: Orthogonalization with near-linear-dependent vectors
    {
        std::cout << "\n[E2.2] Orthogonalization - Near-Linear-Dependent Vectors\n";
        tiny::Mat vectors(3, 3);
        // Create vectors where third is almost a linear combination of first two
        vectors(0, 0) = 1.0f; vectors(0, 1) = 0.0f; vectors(0, 2) = 1.0f;
        vectors(1, 0) = 0.0f; vectors(1, 1) = 1.0f; vectors(1, 2) = 1.0f;
        vectors(2, 0) = 0.0f; vectors(2, 1) = 0.0f; vectors(2, 2) = 0.001f;  // Very small third component

        std::cout << "Input vectors (third vector is nearly linear dependent):\n";
        vectors.print_matrix(true);

        tiny::Mat Q, R;
        bool success = tiny::Mat::gram_schmidt_orthogonalize(vectors, Q, R, 1e-6f);

        std::cout << "\n[Results]\n";
        std::cout << "Status: " << (success ? "OK" : "Error") << "\n";
        if (success)
        {
            std::cout << "Orthogonalized vectors Q:\n";
            Q.print_matrix(true);
            std::cout << "Coefficients R:\n";
            R.print_matrix(true);

            // Check if third column was handled correctly (should be zero or orthogonal)
            float third_col_norm = 0.0f;
            for (int i = 0; i < 3; ++i)
            {
                third_col_norm += Q(i, 2) * Q(i, 2);
            }
            third_col_norm = sqrtf(third_col_norm);
            std::cout << "\n[Note] Third column norm: " << third_col_norm 
                      << " (should be 0 if linearly dependent, or 1 if orthogonalized)\n";
        }
    }

    // E2.3: Orthogonalization of 2D vectors
    {
        std::cout << "\n[E2.3] Orthogonalization - 2D Vectors (2x2)\n";
        tiny::Mat vectors(2, 2);
        vectors(0, 0) = 3.0f; vectors(0, 1) = 1.0f;
        vectors(1, 0) = 1.0f; vectors(1, 1) = 2.0f;

        std::cout << "Input vectors:\n";
        vectors.print_matrix(true);

        tiny::Mat Q, R;
        bool success = tiny::Mat::gram_schmidt_orthogonalize(vectors, Q, R, 1e-6f);

        std::cout << "\n[Results]\n";
        std::cout << "Status: " << (success ? "OK" : "Error") << "\n";
        if (success)
        {
            std::cout << "Orthogonalized vectors Q:\n";
            Q.print_matrix(true);
            std::cout << "Coefficients R:\n";
            R.print_matrix(true);

            // Verify orthogonality
            float dot_product = 0.0f;
            for (int i = 0; i < 2; ++i)
            {
                dot_product += Q(i, 0) * Q(i, 1);
            }
            std::cout << "\n[Verification] Dot product of Q columns: " << dot_product 
                      << " (should be ~0 for orthogonal) " 
                      << (fabsf(dot_product) < 0.01f ? "[PASS]" : "[FAIL]") << "\n";
        }
    }

    // E2.4: Error handling - invalid input
    {
        std::cout << "\n[E2.4] Error Handling - Invalid Input\n";
        tiny::Mat empty_mat(0, 0);  // True empty matrix (0x0)
        tiny::Mat Q, R;
        bool success = tiny::Mat::gram_schmidt_orthogonalize(empty_mat, Q, R, 1e-6f);
        std::cout << "Empty matrix test: " << (success ? "FAIL (should return false)" : "PASS (correctly rejected)") << "\n";
    }

    // E2.5: gram_schmidt_orthogonalize() - Parameter validation - negative tolerance
    {
        std::cout << "\n[E2.5] gram_schmidt_orthogonalize() - Parameter Validation - Negative Tolerance\n";
        tiny::Mat vectors(2, 2);
        vectors(0, 0) = 1.0f; vectors(0, 1) = 0.0f;
        vectors(1, 0) = 0.0f; vectors(1, 1) = 1.0f;
        tiny::Mat Q, R;
        bool success_neg = tiny::Mat::gram_schmidt_orthogonalize(vectors, Q, R, -1e-6f);
        std::cout << "tolerance = -1e-6: " << (success_neg ? "FAIL (should return false)" : "PASS (correctly rejected)") << "\n";
    }

    // E2.6: gram_schmidt_orthogonalize() - Boundary case - zero rows
    {
        std::cout << "\n[E2.6] gram_schmidt_orthogonalize() - Boundary Case - Zero Rows\n";
        tiny::Mat zero_rows(0, 2);
        tiny::Mat Q, R;
        bool success_zero_rows = tiny::Mat::gram_schmidt_orthogonalize(zero_rows, Q, R, 1e-6f);
        std::cout << "Zero rows (0x2): " << (success_zero_rows ? "FAIL (should return false)" : "PASS (correctly rejected)") << "\n";
    }

    // E2.7: gram_schmidt_orthogonalize() - Boundary case - zero columns
    {
        std::cout << "\n[E2.7] gram_schmidt_orthogonalize() - Boundary Case - Zero Columns\n";
        tiny::Mat zero_cols(2, 0);
        tiny::Mat Q, R;
        bool success_zero_cols = tiny::Mat::gram_schmidt_orthogonalize(zero_cols, Q, R, 1e-6f);
        std::cout << "Zero columns (2x0): " << (success_zero_cols ? "FAIL (should return false)" : "PASS (correctly rejected)") << "\n";
    }
}

// ============================================================================
// ============================================================================
// E3: Eigenvalue Decomposition
// ============================================================================
void test_eigenvalue_decomposition()
{
    std::cout << "\n[E3: Eigenvalue Decomposition Tests]\n";

    // E3.1: is_symmetric() - Basic functionality
    std::cout << "\n[E3.1] is_symmetric() - Basic Functionality\n";

    // E3.11: Symmetric matrix
    {
        std::cout << "[E3.11] Symmetric 3x3 Matrix\n";
        tiny::Mat sym_mat1(3, 3);
        sym_mat1(0, 0) = 4.0f; sym_mat1(0, 1) = 1.0f; sym_mat1(0, 2) = 2.0f;
        sym_mat1(1, 0) = 1.0f; sym_mat1(1, 1) = 3.0f; sym_mat1(1, 2) = 0.0f;
        sym_mat1(2, 0) = 2.0f; sym_mat1(2, 1) = 0.0f; sym_mat1(2, 2) = 5.0f;
        bool is_sym1 = sym_mat1.is_symmetric(1e-5f);
        std::cout << "Matrix:\n";
        sym_mat1.print_matrix(true);
        std::cout << "Is symmetric: " << (is_sym1 ? "True" : "False") << " (Expected: True)\n";
    }

    // E3.12: Non-symmetric matrix (keep for later tests)
    tiny::Mat non_sym_mat(3, 3);
    {
        std::cout << "\n[E3.12] Non-Symmetric 3x3 Matrix\n";
        non_sym_mat(0, 0) = 1.0f; non_sym_mat(0, 1) = 2.0f; non_sym_mat(0, 2) = 3.0f;
        non_sym_mat(1, 0) = 4.0f; non_sym_mat(1, 1) = 5.0f; non_sym_mat(1, 2) = 6.0f;
        non_sym_mat(2, 0) = 7.0f; non_sym_mat(2, 1) = 8.0f; non_sym_mat(2, 2) = 9.0f;
        bool is_sym2 = non_sym_mat.is_symmetric(1e-5f);
        std::cout << "Matrix:\n";
        non_sym_mat.print_matrix(true);
        std::cout << "Is symmetric: " << (is_sym2 ? "True" : "False") << " (Expected: False)\n";
    }

    // E3.13: Non-square matrix
    {
        std::cout << "\n[E3.13] Non-Square Matrix (2x3)\n";
        tiny::Mat rect_mat(2, 3);
        bool is_sym3 = rect_mat.is_symmetric(1e-5f);
        std::cout << "Is symmetric: " << (is_sym3 ? "True" : "False") << " (Expected: False)\n";
    }

    // E3.14: Symmetric matrix with small numerical errors
    {
        std::cout << "\n[E3.14] Symmetric Matrix with Small Numerical Errors\n";
        tiny::Mat sym_mat2(2, 2);
        // Use 1e-5 error which is within float precision (float has ~7 significant digits)
        // For 2.0, we can represent 2.00001 accurately
        float error_value = 1e-5f;
        sym_mat2(0, 0) = 1.0f; 
        sym_mat2(0, 1) = 2.0f + error_value;
        sym_mat2(1, 0) = 2.0f; 
        sym_mat2(1, 1) = 3.0f;
        std::cout << "Matrix with error " << error_value << ":\n";
        sym_mat2.print_matrix(true);
        float diff = fabsf(sym_mat2(0, 1) - sym_mat2(1, 0));
        std::cout << "Difference: |A(0,1) - A(1,0)| = ";
        // Use scientific notation for small values
        if (diff < 1e-3f)
        {
            std::cout << std::scientific << std::setprecision(6) << diff << std::fixed;
        }
        else
        {
            std::cout << std::setprecision(6) << diff;
        }
        std::cout << " (Expected: " << error_value << ")\n";

        // Verify the difference is actually stored
        float stored_value = sym_mat2(0, 1);
        float expected_stored = 2.0f + error_value;
        std::cout << "A(0,1) stored value: " << std::setprecision(8) << stored_value 
                  << " (Expected: " << expected_stored << ")\n";

        bool is_sym4 = sym_mat2.is_symmetric(1e-4f); // tolerance > error, should pass
        std::cout << "Is symmetric (tolerance=1e-4): " << (is_sym4 ? "True" : "False") 
                  << " (Expected: True, tolerance > error) ";
        std::cout << (is_sym4 ? "[PASS]" : "[FAIL]") << "\n";

        bool is_sym5 = sym_mat2.is_symmetric(1e-6f); // tolerance < error, should fail
        std::cout << "Is symmetric (tolerance=1e-6): " << (is_sym5 ? "True" : "False") 
                  << " (Expected: False, tolerance < error) ";
        bool correct_result = !is_sym5; // Should be False (not symmetric)
        std::cout << (correct_result ? "[PASS]" : "[FAIL]") << "\n";

        // Additional check: verify the difference is close to expected
        float diff_error = fabsf(diff - error_value);
        std::cout << "Difference accuracy: |actual_diff - expected_diff| = " 
                  << std::scientific << std::setprecision(2) << diff_error << std::fixed;
        bool diff_accurate = (diff_error < error_value * 0.1f); // Within 10% of error value
        std::cout << " " << (diff_accurate ? "[PASS - difference stored correctly]" : "[FAIL - float precision issue]") << "\n";
    }

    // E3.15: Parameter validation - negative tolerance
    {
        std::cout << "\n[E3.15] Parameter Validation - Negative Tolerance\n";
        tiny::Mat sym_mat(2, 2);
        sym_mat(0, 0) = 1.0f; sym_mat(0, 1) = 2.0f;
        sym_mat(1, 0) = 2.0f; sym_mat(1, 1) = 3.0f;

        // Test with tolerance < 0 (should return false/error)
        bool is_sym_neg = sym_mat.is_symmetric(-1e-6f);
        std::cout << "tolerance = -1e-6 (invalid): " << (is_sym_neg ? "True" : "False") 
                  << " (Expected: False) " << (!is_sym_neg ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E3.16: Boundary case - empty matrix
    {
        std::cout << "\n[E3.16] Boundary Case - Empty Matrix (0x0)\n";
        tiny::Mat empty_mat(0, 0);

        // Empty matrix cannot be checked for symmetry (data is null or invalid)
        bool is_sym_empty = empty_mat.is_symmetric(1e-6f);
        std::cout << "Empty matrix (0x0): " << (is_sym_empty ? "True" : "False") 
                  << " (Expected: False, empty matrix is invalid) " << (!is_sym_empty ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E3.2: power_iteration() - Dominant eigenvalue
    std::cout << "\n[E3.2] power_iteration() - Dominant Eigenvalue\n";

    // E3.21: Simple 2x2 symmetric matrix (known eigenvalues)
    tiny::Mat mat2x2(2, 2);
    {
        std::cout << "\n[E3.21] Simple 2x2 Matrix\n";
        mat2x2(0, 0) = 2.0f; mat2x2(0, 1) = 1.0f;
        mat2x2(1, 0) = 1.0f; mat2x2(1, 1) = 2.0f;
        std::cout << "Matrix:\n";
        mat2x2.print_matrix(true);

        // Expected values: eigenvalues are 3 and 1 (for matrix [2,1; 1,2])
        // Characteristic equation: det([2-λ, 1; 1, 2-λ]) = (2-λ)² - 1 = λ² - 4λ + 3 = 0
        // Solutions: λ = (4 ± √(16-12))/2 = (4 ± 2)/2 = 3 or 1
        std::cout << "\n[Expected Results]\n";
        std::cout << "  Expected eigenvalues: 3.0 (largest), 1.0 (smallest)\n";
        std::cout << "  Expected dominant eigenvector (for λ=3): approximately [0.707, 0.707] or [-0.707, -0.707] (normalized)\n";
        std::cout << "  Expected dominant eigenvector (for λ=1): approximately [0.707, -0.707] or [-0.707, 0.707] (normalized)\n";

        tiny::Mat::EigenPair result_power = mat2x2.power_iteration(1000, 1e-6f);
        std::cout << "\n[Actual Results]\n";
        std::cout << "  Dominant eigenvalue: " << result_power.eigenvalue 
                  << " (Expected: 3.0, largest eigenvalue)\n";
        std::cout << "  Iterations: " << result_power.iterations << "\n";
        std::cout << "  Status: " << (result_power.status == TINY_OK ? "OK" : "Error") << "\n";
        std::cout << "  Dominant eigenvector:\n";
        result_power.eigenvector.print_matrix(true);

        // Check if result matches expected
        float error = fabsf(result_power.eigenvalue - 3.0f);
        std::cout << "  Error from expected (3.0): " << error << (error < 0.01f ? " [PASS]" : " [FAIL]") << "\n";
    }

    // E3.22: 3x3 matrix (SHM-like stiffness matrix) - keep for later tests
    tiny::Mat stiffness(3, 3);
    {
        std::cout << "\n[E3.22] 3x3 Stiffness Matrix (SHM Application)\n";
        stiffness(0, 0) = 2.0f; stiffness(0, 1) = -1.0f; stiffness(0, 2) = 0.0f;
        stiffness(1, 0) = -1.0f; stiffness(1, 1) = 2.0f; stiffness(1, 2) = -1.0f;
        stiffness(2, 0) = 0.0f; stiffness(2, 1) = -1.0f; stiffness(2, 2) = 2.0f;
        std::cout << "Stiffness Matrix:\n";
        stiffness.print_matrix(true);

        // Expected values for 3x3 tridiagonal symmetric matrix [2,-1,0; -1,2,-1; 0,-1,2]
        // This is a standard tridiagonal matrix with known eigenvalues
        // Approximate eigenvalues: λ₁ ≈ 3.414, λ₂ ≈ 2.000, λ₃ ≈ 0.586
        std::cout << "\n[Expected Results]\n";
        std::cout << "  Expected eigenvalues (approximate): 3.414 (largest), 2.000, 0.586 (smallest)\n";
        std::cout << "  Expected primary frequency: sqrt(3.414) ≈ 1.848 rad/s\n";

        tiny::Mat::EigenPair result_stiff = stiffness.power_iteration(500, 1e-6f);
        std::cout << "\n[Actual Results]\n";
        std::cout << "  Dominant eigenvalue (primary frequency squared): " << result_stiff.eigenvalue << "\n";
        std::cout << "  Primary frequency: " << sqrtf(result_stiff.eigenvalue) << " rad/s (Expected: ~1.848 rad/s)\n";
        std::cout << "  Iterations: " << result_stiff.iterations << "\n";
        std::cout << "  Status: " << (result_stiff.status == TINY_OK ? "OK" : "Error") << "\n";

        float expected_eigen = 3.414f;
        float error = fabsf(result_stiff.eigenvalue - expected_eigen);
        std::cout << "  Error from expected (" << expected_eigen << "): " << error << (error < 0.1f ? " [PASS]" : " [FAIL]") << "\n";
    }

    // E3.23: Non-square matrix (should fail)
    {
        std::cout << "\n[E3.23] Non-Square Matrix (Expect Error)\n";
        tiny::Mat non_square(2, 3);
        tiny::Mat::EigenPair result_error = non_square.power_iteration(100, 1e-6f);
        std::cout << "Status: " << (result_error.status == TINY_OK ? "OK" : "Error (Expected)") << "\n";
    }

    // E3.25: Parameter validation - max_iter <= 0
    {
        std::cout << "\n[E3.25] Parameter Validation - max_iter <= 0\n";
        tiny::Mat test_mat(2, 2);
        test_mat(0, 0) = 2.0f; test_mat(0, 1) = 1.0f;
        test_mat(1, 0) = 1.0f; test_mat(1, 1) = 2.0f;

        tiny::Mat::EigenPair result_zero = test_mat.power_iteration(0, 1e-6f);
        std::cout << "max_iter = 0: Status = " << (result_zero.status == TINY_OK ? "OK" : "Error (Expected)") 
                  << " " << (result_zero.status != TINY_OK ? "[PASS]" : "[FAIL]") << "\n";

        tiny::Mat::EigenPair result_neg = test_mat.power_iteration(-1, 1e-6f);
        std::cout << "max_iter = -1: Status = " << (result_neg.status == TINY_OK ? "OK" : "Error (Expected)") 
                  << " " << (result_neg.status != TINY_OK ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E3.26: Parameter validation - tolerance < 0
    {
        std::cout << "\n[E3.26] Parameter Validation - tolerance < 0\n";
        tiny::Mat test_mat(2, 2);
        test_mat(0, 0) = 2.0f; test_mat(0, 1) = 1.0f;
        test_mat(1, 0) = 1.0f; test_mat(1, 1) = 2.0f;

        tiny::Mat::EigenPair result_neg = test_mat.power_iteration(100, -1e-6f);
        std::cout << "tolerance = -1e-6: Status = " << (result_neg.status == TINY_OK ? "OK" : "Error (Expected)") 
                  << " " << (result_neg.status != TINY_OK ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E3.27: Boundary case - empty matrix
    {
        std::cout << "\n[E3.27] Boundary Case - Empty Matrix (0x0)\n";
        tiny::Mat empty_mat(0, 0);

        tiny::Mat::EigenPair result_empty = empty_mat.power_iteration(100, 1e-6f);
        // Empty matrix should return error status
        bool empty_correct = (result_empty.status != TINY_OK);
        std::cout << "Empty matrix: Status = " << (result_empty.status == TINY_OK ? "OK" : "Error") 
                  << ", eigenvalue = " << result_empty.eigenvalue 
                  << " (Expected: Error status) " << (empty_correct ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E3.24: inverse_power_iteration() - Smallest eigenvalue (Critical for System Identification)
    std::cout << "\n[E3.24] inverse_power_iteration() - Smallest Eigenvalue (System Identification)\n";

    // E3.28: Simple 2x2 symmetric matrix (known eigenvalues)
    {
        std::cout << "\n[E3.28] Simple 2x2 Matrix - Smallest Eigenvalue\n";
        std::cout << "Matrix (same as E3.21):\n";
        mat2x2.print_matrix(true);

        // Expected values: eigenvalues are 3 and 1 (for matrix [2,1; 1,2])
        // Power iteration finds λ_max = 3, inverse power iteration should find λ_min = 1
        std::cout << "\n[Expected Results]\n";
        std::cout << "  Expected eigenvalues: 3.0 (largest), 1.0 (smallest)\n";
        std::cout << "  Expected smallest eigenvalue: 1.0\n";
        std::cout << "  Expected smallest eigenvector (for λ=1): approximately [0.707, -0.707] or [-0.707, 0.707] (normalized)\n";
        std::cout << "  Note: This is critical for system identification - smallest eigenvalue = fundamental frequency\n";

        tiny::Mat::EigenPair result_inv_power = mat2x2.inverse_power_iteration(1000, 1e-6f);
        std::cout << "\n[Actual Results]\n";
        std::cout << "  Smallest eigenvalue: " << result_inv_power.eigenvalue 
                  << " (Expected: 1.0, smallest eigenvalue)\n";
        std::cout << "  Iterations: " << result_inv_power.iterations << "\n";
        std::cout << "  Status: " << (result_inv_power.status == TINY_OK ? "OK" : "Error") << "\n";
        std::cout << "  Smallest eigenvector:\n";
        result_inv_power.eigenvector.print_matrix(true);

        // Check if result matches expected
        float error = fabsf(result_inv_power.eigenvalue - 1.0f);
        std::cout << "  Error from expected (1.0): " << error << (error < 0.01f ? " [PASS]" : " [FAIL]") << "\n";

        // Compare with power iteration results (recompute for comparison)
        tiny::Mat::EigenPair result_power_compare = mat2x2.power_iteration(1000, 1e-6f);
        std::cout << "\n[Comparison] Power vs Inverse Power Iteration:\n";
        std::cout << "  Power iteration (λ_max): " << result_power_compare.eigenvalue << "\n";
        std::cout << "  Inverse power iteration (λ_min): " << result_inv_power.eigenvalue << "\n";
        std::cout << "  Ratio (λ_max/λ_min): " << (result_power_compare.eigenvalue / result_inv_power.eigenvalue) 
                  << " (Expected: ~3.0) " << (fabsf(result_power_compare.eigenvalue / result_inv_power.eigenvalue - 3.0f) < 0.1f ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E3.29: 3x3 stiffness matrix - Smallest eigenvalue (SHM Application)
    {
        std::cout << "\n[E3.29] 3x3 Stiffness Matrix - Smallest Eigenvalue (SHM Application)\n";
        std::cout << "Stiffness Matrix (same as E3.22):\n";
        stiffness.print_matrix(true);

        // Expected values for 3x3 tridiagonal symmetric matrix [2,-1,0; -1,2,-1; 0,-1,2]
        // Approximate eigenvalues: λ₁ ≈ 3.414 (largest), λ₂ ≈ 2.000, λ₃ ≈ 0.586 (smallest)
        std::cout << "\n[Expected Results]\n";
        std::cout << "  Expected eigenvalues (approximate): 3.414 (largest), 2.000, 0.586 (smallest)\n";
        std::cout << "  Expected smallest eigenvalue: ~0.586 (fundamental frequency squared)\n";
        std::cout << "  Expected fundamental frequency: sqrt(0.586) ≈ 0.765 rad/s\n";
        std::cout << "  Note: Smallest eigenvalue is critical for system identification - represents fundamental mode\n";

        tiny::Mat::EigenPair result_inv_stiff = stiffness.inverse_power_iteration(500, 1e-6f);
        std::cout << "\n[Actual Results]\n";
        std::cout << "  Smallest eigenvalue (fundamental frequency squared): " << result_inv_stiff.eigenvalue << "\n";
        std::cout << "  Fundamental frequency: " << sqrtf(result_inv_stiff.eigenvalue) << " rad/s (Expected: ~0.765 rad/s)\n";
        std::cout << "  Iterations: " << result_inv_stiff.iterations << "\n";
        std::cout << "  Status: " << (result_inv_stiff.status == TINY_OK ? "OK" : "Error") << "\n";
        std::cout << "  Smallest eigenvector (fundamental mode shape):\n";
        result_inv_stiff.eigenvector.print_matrix(true);

        float expected_eigen = 0.586f;
        float error = fabsf(result_inv_stiff.eigenvalue - expected_eigen);
        std::cout << "  Error from expected (" << expected_eigen << "): " << error << (error < 0.1f ? " [PASS]" : " [FAIL]") << "\n";

        // Compare with power iteration (recompute for comparison)
        tiny::Mat::EigenPair result_stiff_compare = stiffness.power_iteration(500, 1e-6f);
        std::cout << "\n[Comparison] Power vs Inverse Power Iteration for SHM:\n";
        std::cout << "  Power iteration (primary frequency²): " << result_stiff_compare.eigenvalue 
                  << " → frequency: " << sqrtf(result_stiff_compare.eigenvalue) << " rad/s\n";
        std::cout << "  Inverse power iteration (fundamental frequency²): " << result_inv_stiff.eigenvalue 
                  << " → frequency: " << sqrtf(result_inv_stiff.eigenvalue) << " rad/s\n";
        std::cout << "  Frequency ratio: " << (sqrtf(result_stiff_compare.eigenvalue) / sqrtf(result_inv_stiff.eigenvalue))
                  << " (Expected: ~2.4, ratio of highest to lowest mode)\n";
    }

    // E3.210: Non-square matrix (should fail)
    {
        std::cout << "\n[E3.210] Non-Square Matrix (Expect Error)\n";
        tiny::Mat non_square(2, 3);
        tiny::Mat::EigenPair result_error = non_square.inverse_power_iteration(100, 1e-6f);
        std::cout << "Status: " << (result_error.status == TINY_OK ? "OK" : "Error (Expected)") << "\n";
        bool correct = (result_error.status != TINY_OK);
        std::cout << "Error handling: " << (correct ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E3.211: Near-singular matrix (should handle gracefully)
    {
        std::cout << "\n[E3.211] Near-Singular Matrix (Edge Case)\n";
        tiny::Mat near_singular(3, 3);
        // Create a matrix that is close to singular but still invertible
        near_singular(0, 0) = 1.0f; near_singular(0, 1) = 0.0f; near_singular(0, 2) = 0.0f;
        near_singular(1, 0) = 0.0f; near_singular(1, 1) = 1.0f; near_singular(1, 2) = 0.001f;
        near_singular(2, 0) = 0.0f; near_singular(2, 1) = 0.001f; near_singular(2, 2) = 1.0f;
        std::cout << "Matrix (near-singular but invertible):\n";
        near_singular.print_matrix(true);

        tiny::Mat::EigenPair result_near_sing = near_singular.inverse_power_iteration(500, 1e-5f);
        std::cout << "\n[Results]\n";
        std::cout << "  Status: " << (result_near_sing.status == TINY_OK ? "OK" : "Error") << "\n";
        if (result_near_sing.status == TINY_OK)
        {
            std::cout << "  Smallest eigenvalue: " << result_near_sing.eigenvalue << "\n";
            std::cout << "  Iterations: " << result_near_sing.iterations << "\n";
            std::cout << "  Note: Successfully handled near-singular matrix [PASS]\n";
        }
        else
        {
            std::cout << "  Note: Correctly detected problematic matrix [PASS]\n";
        }
    }

    // E3.212: Parameter validation - max_iter <= 0
    {
        std::cout << "\n[E3.212] Parameter Validation - max_iter <= 0\n";
        tiny::Mat test_mat(2, 2);
        test_mat(0, 0) = 2.0f; test_mat(0, 1) = 1.0f;
        test_mat(1, 0) = 1.0f; test_mat(1, 1) = 2.0f;

        tiny::Mat::EigenPair result_zero = test_mat.inverse_power_iteration(0, 1e-6f);
        std::cout << "max_iter = 0: Status = " << (result_zero.status == TINY_OK ? "OK" : "Error (Expected)") 
                  << " " << (result_zero.status != TINY_OK ? "[PASS]" : "[FAIL]") << "\n";

        tiny::Mat::EigenPair result_neg = test_mat.inverse_power_iteration(-1, 1e-6f);
        std::cout << "max_iter = -1: Status = " << (result_neg.status == TINY_OK ? "OK" : "Error (Expected)") 
                  << " " << (result_neg.status != TINY_OK ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E3.213: Parameter validation - tolerance < 0
    {
        std::cout << "\n[E3.213] Parameter Validation - tolerance < 0\n";
        tiny::Mat test_mat(2, 2);
        test_mat(0, 0) = 2.0f; test_mat(0, 1) = 1.0f;
        test_mat(1, 0) = 1.0f; test_mat(1, 1) = 2.0f;

        tiny::Mat::EigenPair result_neg = test_mat.inverse_power_iteration(100, -1e-6f);
        std::cout << "tolerance = -1e-6: Status = " << (result_neg.status == TINY_OK ? "OK" : "Error (Expected)") 
                  << " " << (result_neg.status != TINY_OK ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E3.214: Boundary case - empty matrix
    {
        std::cout << "\n[E3.214] Boundary Case - Empty Matrix (0x0)\n";
        tiny::Mat empty_mat(0, 0);

        tiny::Mat::EigenPair result_empty = empty_mat.inverse_power_iteration(100, 1e-6f);
        // Empty matrix should return error status
        bool empty_correct = (result_empty.status != TINY_OK);
        std::cout << "Empty matrix: Status = " << (result_empty.status == TINY_OK ? "OK" : "Error") 
                  << ", eigenvalue = " << result_empty.eigenvalue 
                  << " (Expected: Error status) " << (empty_correct ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E3.215: Singular matrix (should fail)
    {
        std::cout << "\n[E3.215] Singular Matrix (Should Fail)\n";
        tiny::Mat singular(2, 2);
        singular(0, 0) = 1.0f; singular(0, 1) = 2.0f;
        singular(1, 0) = 2.0f; singular(1, 1) = 4.0f;  // Second row is 2x first row (singular)

        tiny::Mat::EigenPair result_sing = singular.inverse_power_iteration(100, 1e-6f);
        // Note: Some implementations may handle singular matrices differently
        // Check if status is Error OR if eigenvalue is valid (implementation-dependent)
        // For now, accept either Error status or valid result (some algorithms can handle singular matrices)
        bool singular_correct = (result_sing.status != TINY_OK) || 
                               (result_sing.status == TINY_OK && (result_sing.eigenvalue == 0.0f || fabsf(result_sing.eigenvalue) < 1e-5f));
        std::cout << "Singular matrix: Status = " << (result_sing.status == TINY_OK ? "OK" : "Error") 
                  << " (Expected: Error or OK with eigenvalue ≈ 0) " << (singular_correct ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E3.3: eigendecompose_jacobi() - Symmetric matrix decomposition
    std::cout << "\n[E3.3] eigendecompose_jacobi() - Symmetric Matrix Decomposition\n";

    // E3.31: Simple 2x2 symmetric matrix
    {
        std::cout << "\n[E3.31] 2x2 Symmetric Matrix - Complete Decomposition\n";
        std::cout << "[Expected Results]\n";
        std::cout << "  Expected eigenvalues: 3.0, 1.0 (in any order)\n";
        std::cout << "  Expected eigenvectors (for λ=3): [0.707, 0.707] or [-0.707, -0.707] (normalized)\n";
        std::cout << "  Expected eigenvectors (for λ=1): [0.707, -0.707] or [-0.707, 0.707] (normalized)\n";

        tiny::Mat::EigenDecomposition result_jacobi1 = mat2x2.eigendecompose_jacobi(1e-6f, 100);
        std::cout << "\n[Actual Results]\n";
        std::cout << "Eigenvalues:\n";
        result_jacobi1.eigenvalues.print_matrix(true);
        std::cout << "Eigenvectors (each column is an eigenvector):\n";
        result_jacobi1.eigenvectors.print_matrix(true);
        std::cout << "Iterations: " << result_jacobi1.iterations << "\n";
        std::cout << "Status: " << (result_jacobi1.status == TINY_OK ? "OK" : "Error") << "\n";

        // Check eigenvalues
        float ev1 = result_jacobi1.eigenvalues(0, 0);
        float ev2 = result_jacobi1.eigenvalues(1, 0);
        bool ev_check = ((fabsf(ev1 - 3.0f) < 0.01f && fabsf(ev2 - 1.0f) < 0.01f) ||
                         (fabsf(ev1 - 1.0f) < 0.01f && fabsf(ev2 - 3.0f) < 0.01f));
        std::cout << "Eigenvalue check (should be 3.0 and 1.0): " << (ev_check ? "[PASS]" : "[FAIL]") << "\n";

        // Verify: A * v = lambda * v
        std::cout << "\n[Verification] Check A * v = lambda * v for first eigenvector:\n";
        tiny::Mat Av = mat2x2 * result_jacobi1.eigenvectors.block(0, 0, 2, 1);
        tiny::Mat lambda_v = result_jacobi1.eigenvalues(0, 0) * result_jacobi1.eigenvectors.block(0, 0, 2, 1);
        std::cout << "A * v:\n";
        Av.print_matrix(true);
        std::cout << "lambda * v:\n";
        lambda_v.print_matrix(true);
        bool verify1 = matrices_approximately_equal(Av, lambda_v, 1e-4f);
        std::cout << "Verification (A*v = λ*v): " << (verify1 ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E3.32: 3x3 symmetric matrix (SHM stiffness matrix)
    {
        std::cout << "\n[E3.32] 3x3 Stiffness Matrix (SHM Application)\n";
        std::cout << "[Expected Results]\n";
        std::cout << "  Expected eigenvalues (approximate): 3.414, 2.000, 0.586\n";
        std::cout << "  Expected natural frequencies: 1.848, 1.414, 0.765 rad/s\n";
        std::cout << "  Note: Eigenvalues may appear in any order\n";

        tiny::Mat::EigenDecomposition result_jacobi2 = stiffness.eigendecompose_jacobi(1e-5f, 100);
        std::cout << "\n[Actual Results]\n";
        std::cout << "Eigenvalues (natural frequencies squared):\n";
        result_jacobi2.eigenvalues.print_matrix(true);
        std::cout << "Natural frequencies (rad/s):\n";
        float expected_freqs[3] = {1.848f, 1.414f, 0.765f};
        for (int i = 0; i < result_jacobi2.eigenvalues.row; ++i)
        {
            float freq = sqrtf(result_jacobi2.eigenvalues(i, 0));
            std::cout << "  Mode " << i << ": " << freq << " rad/s";
            // Check if frequency matches any expected value
            bool matched = false;
            for (int j = 0; j < 3; ++j)
            {
                if (fabsf(freq - expected_freqs[j]) < 0.1f)
                {
                    std::cout << " (Expected: ~" << expected_freqs[j] << " rad/s) [PASS]";
                    matched = true;
                    break;
                }
            }
            if (!matched) std::cout << " [CHECK]";
            std::cout << "\n";
        }
        std::cout << "Eigenvectors (mode shapes):\n";
        result_jacobi2.eigenvectors.print_matrix(true);
        std::cout << "Iterations: " << result_jacobi2.iterations << "\n";
        std::cout << "Status: " << (result_jacobi2.status == TINY_OK ? "OK" : "Error") << "\n";
    }

    // E3.33: Diagonal matrix (trivial case)
    {
        std::cout << "\n[E3.33] Diagonal Matrix (Eigenvalues on diagonal)\n";
        tiny::Mat diag_mat(3, 3);
        diag_mat(0, 0) = 5.0f; diag_mat(0, 1) = 0.0f; diag_mat(0, 2) = 0.0f;
        diag_mat(1, 0) = 0.0f; diag_mat(1, 1) = 3.0f; diag_mat(1, 2) = 0.0f;
        diag_mat(2, 0) = 0.0f; diag_mat(2, 1) = 0.0f; diag_mat(2, 2) = 1.0f;
        std::cout << "Matrix:\n";
        diag_mat.print_matrix(true);
        std::cout << "\n[Expected Results]\n";
        std::cout << "  Expected eigenvalues: 5.0, 3.0, 1.0 (diagonal elements, may be in any order)\n";
        std::cout << "  Expected eigenvectors: standard basis vectors [1,0,0], [0,1,0], [0,0,1] (or their negatives)\n";
        std::cout << "  Expected iterations: 1 (diagonal matrix should converge immediately)\n";

        tiny::Mat::EigenDecomposition result_diag = diag_mat.eigendecompose_jacobi(1e-6f, 10);
        std::cout << "\n[Actual Results]\n";
        std::cout << "Eigenvalues:\n";
        result_diag.eigenvalues.print_matrix(true);
        std::cout << "Eigenvectors:\n";
        result_diag.eigenvectors.print_matrix(true);
        std::cout << "Iterations: " << result_diag.iterations << " (Expected: 1)\n";

        // Check eigenvalues
        float ev1 = result_diag.eigenvalues(0, 0);
        float ev2 = result_diag.eigenvalues(1, 0);
        float ev3 = result_diag.eigenvalues(2, 0);
        bool ev_check = ((fabsf(ev1 - 5.0f) < 0.01f || fabsf(ev1 - 3.0f) < 0.01f || fabsf(ev1 - 1.0f) < 0.01f) &&
                         (fabsf(ev2 - 5.0f) < 0.01f || fabsf(ev2 - 3.0f) < 0.01f || fabsf(ev2 - 1.0f) < 0.01f) &&
                         (fabsf(ev3 - 5.0f) < 0.01f || fabsf(ev3 - 3.0f) < 0.01f || fabsf(ev3 - 1.0f) < 0.01f));
        std::cout << "Eigenvalue check (should be 5.0, 3.0, 1.0): " << (ev_check ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E3.34: Parameter validation - tolerance < 0
    {
        std::cout << "\n[E3.34] Parameter Validation - tolerance < 0\n";
        tiny::Mat test_mat(2, 2);
        test_mat(0, 0) = 2.0f; test_mat(0, 1) = 1.0f;
        test_mat(1, 0) = 1.0f; test_mat(1, 1) = 2.0f;

        tiny::Mat::EigenDecomposition result_neg = test_mat.eigendecompose_jacobi(-1e-6f, 100);
        std::cout << "tolerance = -1e-6: Status = " << (result_neg.status == TINY_OK ? "OK" : "Error (Expected)") 
                  << " " << (result_neg.status != TINY_OK ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E3.35: Parameter validation - max_iter <= 0
    {
        std::cout << "\n[E3.35] Parameter Validation - max_iter <= 0\n";
        tiny::Mat test_mat(2, 2);
        test_mat(0, 0) = 2.0f; test_mat(0, 1) = 1.0f;
        test_mat(1, 0) = 1.0f; test_mat(1, 1) = 2.0f;

        tiny::Mat::EigenDecomposition result_zero = test_mat.eigendecompose_jacobi(1e-6f, 0);
        std::cout << "max_iter = 0: Status = " << (result_zero.status == TINY_OK ? "OK" : "Error (Expected)") 
                  << " " << (result_zero.status != TINY_OK ? "[PASS]" : "[FAIL]") << "\n";

        tiny::Mat::EigenDecomposition result_neg = test_mat.eigendecompose_jacobi(1e-6f, -1);
        std::cout << "max_iter = -1: Status = " << (result_neg.status == TINY_OK ? "OK" : "Error (Expected)") 
                  << " " << (result_neg.status != TINY_OK ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E3.36: Boundary case - empty matrix
    {
        std::cout << "\n[E3.36] Boundary Case - Empty Matrix (0x0)\n";
        tiny::Mat empty_mat(0, 0);

        tiny::Mat::EigenDecomposition result_empty = empty_mat.eigendecompose_jacobi(1e-6f, 100);
        // Error case: empty matrix should return error status, eigenvalues may be 0x0 or 1x1 error matrix
        bool empty_correct = (result_empty.status != TINY_OK) && 
                            ((result_empty.eigenvalues.row == 0 && result_empty.eigenvalues.col == 0) || 
                             (result_empty.eigenvalues.data == nullptr) ||
                             (result_empty.eigenvalues.row == 1 && result_empty.eigenvalues.col == 1 && result_empty.eigenvalues.data != nullptr));
        std::cout << "Empty matrix: Status = " << (result_empty.status == TINY_OK ? "OK" : "Error") 
                  << ", eigenvalues rows = " << result_empty.eigenvalues.row 
                  << " (Expected: Error status, eigenvalues is 0x0 or error state) " << (empty_correct ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E3.4: eigendecompose_qr() - General matrix decomposition
    std::cout << "\n[E3.4] eigendecompose_qr() - General Matrix Decomposition\n";

    // E3.41: General 2x2 matrix
    {
        std::cout << "\n[E3.41] General 2x2 Matrix\n";
        tiny::Mat gen_mat(2, 2);
        gen_mat(0, 0) = 1.0f; gen_mat(0, 1) = 2.0f;
        gen_mat(1, 0) = 3.0f; gen_mat(1, 1) = 4.0f;
        std::cout << "Matrix:\n";
        gen_mat.print_matrix(true);

        // Expected values for matrix [1,2; 3,4]
        // Characteristic equation: det([1-λ, 2; 3, 4-λ]) = (1-λ)(4-λ) - 6 = λ² - 5λ - 2 = 0
        // Solutions: λ = (5 ± √(25+8))/2 = (5 ± √33)/2 ≈ 5.372, -0.372
        std::cout << "\n[Expected Results]\n";
        std::cout << "  Expected eigenvalues: (5+√33)/2 ≈ 5.372, (5-√33)/2 ≈ -0.372\n";
        std::cout << "  Note: This is a non-symmetric matrix, eigenvalues are real but may have complex eigenvectors\n";

        tiny::Mat::EigenDecomposition result_qr1 = gen_mat.eigendecompose_qr(100, 1e-5f);
        std::cout << "\n[Actual Results]\n";
        std::cout << "Eigenvalues:\n";
        result_qr1.eigenvalues.print_matrix(true);
        std::cout << "Eigenvectors:\n";
        result_qr1.eigenvectors.print_matrix(true);
        std::cout << "Iterations: " << result_qr1.iterations << "\n";
        std::cout << "Status: " << (result_qr1.status == TINY_OK ? "OK" : "Error") << "\n";

        // Check eigenvalues with detailed error reporting
        float ev1 = result_qr1.eigenvalues(0, 0);
        float ev2 = result_qr1.eigenvalues(1, 0);
        float expected_ev1 = 5.372f;
        float expected_ev2 = -0.372f;

        // Match eigenvalues to expected values
        float error1a = fabsf(ev1 - expected_ev1);
        float error1b = fabsf(ev1 - expected_ev2);
        float error2a = fabsf(ev2 - expected_ev1);
        float error2b = fabsf(ev2 - expected_ev2);

        bool match1 = (error1a < error1b); // ev1 matches expected_ev1 better
        float matched_ev1 = match1 ? expected_ev1 : expected_ev2;
        float matched_ev2 = match1 ? expected_ev2 : expected_ev1;
        float actual_error1 = match1 ? error1a : error1b;
        float actual_error2 = match1 ? error2b : error2a;
        float rel_error1 = actual_error1 / fabsf(matched_ev1);
        float rel_error2 = actual_error2 / fabsf(matched_ev2);

        std::cout << "Eigenvalue 1: " << ev1 << " (Expected: " << matched_ev1 << ", Error: " << actual_error1 
                  << ", Rel Error: " << (rel_error1 * 100.0f) << "%) ";
        bool pass1 = (rel_error1 < 0.05f); // 5% relative error tolerance
        std::cout << (pass1 ? "[PASS]" : "[FAIL - error too large]") << "\n";

        std::cout << "Eigenvalue 2: " << ev2 << " (Expected: " << matched_ev2 << ", Error: " << actual_error2 
                  << ", Rel Error: " << (rel_error2 * 100.0f) << "%) ";
        bool pass2 = (rel_error2 < 0.05f); // 5% relative error tolerance
        std::cout << (pass2 ? "[PASS]" : "[FAIL - error too large]") << "\n";

        bool ev_check = pass1 && pass2;
        std::cout << "Overall eigenvalue check: " << (ev_check ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E3.42: Non-symmetric 3x3 matrix
    {
        std::cout << "\n[E3.42] Non-Symmetric 3x3 Matrix\n";
        std::cout << "Matrix [1,2,3; 4,5,6; 7,8,9]:\n";
        non_sym_mat.print_matrix(true);

        // Expected values for matrix [1,2,3; 4,5,6; 7,8,9]
        // Characteristic equation: λ³ - 15λ² - 18λ = 0
        // Solutions: λ(λ² - 15λ - 18) = 0
        // λ₁ = 0, λ₂,₃ = (15 ± √(225+72))/2 = (15 ± √297)/2 ≈ 16.12, -1.12
        // However, QR algorithm may have numerical errors, especially for non-symmetric matrices
        std::cout << "\n[Expected Results]\n";
        std::cout << "  Expected eigenvalues (theoretical): 16.12, -1.12, 0.00\n";
        std::cout << "  Note: This matrix is rank-deficient (determinant = 0), so one eigenvalue is 0\n";
        std::cout << "  Note: QR algorithm may have numerical errors, especially for non-symmetric matrices\n";
        std::cout << "  Acceptable range: largest eigenvalue ~15-18, smallest eigenvalue near 0\n";

        tiny::Mat::EigenDecomposition result_qr2 = non_sym_mat.eigendecompose_qr(100, 1e-5f);
        std::cout << "\n[Actual Results]\n";
        std::cout << "Eigenvalues:\n";
        result_qr2.eigenvalues.print_matrix(true);
        std::cout << "Eigenvectors:\n";
        result_qr2.eigenvectors.print_matrix(true);
        std::cout << "Iterations: " << result_qr2.iterations << "\n";
        std::cout << "Status: " << (result_qr2.status == TINY_OK ? "OK" : "Error") << "\n";

        // Check results with detailed error reporting
        float expected_evs[3] = {16.12f, -1.12f, 0.0f};
        bool matched[3] = {false, false, false};
        float errors[3] = {0.0f, 0.0f, 0.0f};
        float rel_errors[3] = {0.0f, 0.0f, 0.0f};

        // Match each computed eigenvalue to the closest expected value
        for (int i = 0; i < result_qr2.eigenvalues.row; ++i)
        {
            float ev = result_qr2.eigenvalues(i, 0);
            float min_error = 1e10f;
            int best_match = -1;

            // Find closest expected eigenvalue
            for (int j = 0; j < 3; ++j)
            {
                if (!matched[j])
                {
                    float error = fabsf(ev - expected_evs[j]);
                    if (error < min_error)
                    {
                        min_error = error;
                        best_match = j;
                    }
                }
            }

            if (best_match >= 0)
            {
                matched[best_match] = true;
                errors[best_match] = min_error;
                float expected = expected_evs[best_match];
                rel_errors[best_match] = (fabsf(expected) > 1e-6f) ? (min_error / fabsf(expected)) : min_error;

                std::cout << "Eigenvalue " << i << ": " << ev << " (Expected: " << expected 
                          << ", Error: " << min_error << ", Rel Error: " << (rel_errors[best_match] * 100.0f) << "%) ";

                // For zero eigenvalue, use absolute tolerance; for others, use relative tolerance
                bool pass = (fabsf(expected) < 0.1f) ? (min_error < 0.1f) : (rel_errors[best_match] < 0.15f); // 15% tolerance for QR
                std::cout << (pass ? "[PASS]" : "[FAIL - error too large]") << "\n";
            }
        }

        // Overall check
        bool overall_pass = true;
        for (int i = 0; i < 3; ++i)
        {
            bool pass = (fabsf(expected_evs[i]) < 0.1f) ? (errors[i] < 0.1f) : (rel_errors[i] < 0.15f);
            if (!pass) overall_pass = false;
        }
        std::cout << "Overall eigenvalue check: " << (overall_pass ? "[PASS]" : "[FAIL - some eigenvalues have large errors]") << "\n";
    }

    // E3.43: Parameter validation - max_iter <= 0
    {
        std::cout << "\n[E3.43] Parameter Validation - max_iter <= 0\n";
        tiny::Mat test_mat(2, 2);
        test_mat(0, 0) = 1.0f; test_mat(0, 1) = 2.0f;
        test_mat(1, 0) = 3.0f; test_mat(1, 1) = 4.0f;

        tiny::Mat::EigenDecomposition result_zero = test_mat.eigendecompose_qr(0, 1e-6f);
        std::cout << "max_iter = 0: Status = " << (result_zero.status == TINY_OK ? "OK" : "Error (Expected)") 
                  << " " << (result_zero.status != TINY_OK ? "[PASS]" : "[FAIL]") << "\n";

        tiny::Mat::EigenDecomposition result_neg = test_mat.eigendecompose_qr(-1, 1e-6f);
        std::cout << "max_iter = -1: Status = " << (result_neg.status == TINY_OK ? "OK" : "Error (Expected)") 
                  << " " << (result_neg.status != TINY_OK ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E3.44: Parameter validation - tolerance < 0
    {
        std::cout << "\n[E3.44] Parameter Validation - tolerance < 0\n";
        tiny::Mat test_mat(2, 2);
        test_mat(0, 0) = 1.0f; test_mat(0, 1) = 2.0f;
        test_mat(1, 0) = 3.0f; test_mat(1, 1) = 4.0f;

        tiny::Mat::EigenDecomposition result_neg = test_mat.eigendecompose_qr(100, -1e-6f);
        std::cout << "tolerance = -1e-6: Status = " << (result_neg.status == TINY_OK ? "OK" : "Error (Expected)") 
                  << " " << (result_neg.status != TINY_OK ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E3.45: Boundary case - empty matrix
    {
        std::cout << "\n[E3.45] Boundary Case - Empty Matrix (0x0)\n";
        tiny::Mat empty_mat(0, 0);

        tiny::Mat::EigenDecomposition result_empty = empty_mat.eigendecompose_qr(100, 1e-6f);
        // Error case: empty matrix should return error status, eigenvalues may be 0x0 or 1x1 error matrix
        bool empty_correct = (result_empty.status != TINY_OK) && 
                            ((result_empty.eigenvalues.row == 0 && result_empty.eigenvalues.col == 0) || 
                             (result_empty.eigenvalues.data == nullptr) ||
                             (result_empty.eigenvalues.row == 1 && result_empty.eigenvalues.col == 1 && result_empty.eigenvalues.data != nullptr));
        std::cout << "Empty matrix: Status = " << (result_empty.status == TINY_OK ? "OK" : "Error") 
                  << ", eigenvalues rows = " << result_empty.eigenvalues.row 
                  << " (Expected: Error status, eigenvalues is 0x0 or error state) " << (empty_correct ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E3.5: eigendecompose() - Automatic method selection
    std::cout << "\n[E3.5] eigendecompose() - Automatic Method Selection\n";

    // E3.51: Symmetric matrix (should use Jacobi)
    {
        std::cout << "\n[E3.51] Symmetric Matrix (Auto-select: Jacobi)\n";
        tiny::Mat sym_mat1(3, 3);
        sym_mat1(0, 0) = 4.0f; sym_mat1(0, 1) = 1.0f; sym_mat1(0, 2) = 2.0f;
        sym_mat1(1, 0) = 1.0f; sym_mat1(1, 1) = 3.0f; sym_mat1(1, 2) = 0.0f;
        sym_mat1(2, 0) = 2.0f; sym_mat1(2, 1) = 0.0f; sym_mat1(2, 2) = 5.0f;
        std::cout << "Matrix:\n";
        sym_mat1.print_matrix(true);
        std::cout << "\n[Expected Results]\n";
        std::cout << "  Method: Should automatically use Jacobi (symmetric matrix detected)\n";
        std::cout << "  Expected eigenvalues (approximate): 6.67, 3.48, 1.85\n";
        std::cout << "  Note: Eigenvalues may appear in any order\n";

        tiny::Mat::EigenDecomposition result_auto1 = sym_mat1.eigendecompose(1e-5f);
        std::cout << "\n[Actual Results]\n";
        std::cout << "Eigenvalues:\n";
        result_auto1.eigenvalues.print_matrix(true);
        std::cout << "Iterations: " << result_auto1.iterations << "\n";
        std::cout << "Status: " << (result_auto1.status == TINY_OK ? "OK" : "Error") << "\n";
        std::cout << "Method used: Jacobi (auto-selected for symmetric matrix)\n";
    }

    // E3.52: Non-symmetric matrix (should use QR)
    {
        std::cout << "\n[E3.52] Non-Symmetric Matrix (Auto-select: QR)\n";
        std::cout << "[Expected Results]\n";
        std::cout << "  Method: Should automatically use QR (non-symmetric matrix detected)\n";
        std::cout << "  Expected eigenvalues (theoretical): 16.12, -1.12, 0.00\n";
        std::cout << "  Note: One eigenvalue should be near 0 (rank-deficient matrix)\n";
        std::cout << "  Note: QR algorithm may have numerical errors for non-symmetric matrices\n";
        std::cout << "  Acceptable: largest ~15-18, smallest near 0, one near -1 to -3\n";

        tiny::Mat::EigenDecomposition result_auto2 = non_sym_mat.eigendecompose(1e-5f);
        std::cout << "\n[Actual Results]\n";
        std::cout << "Eigenvalues:\n";
        result_auto2.eigenvalues.print_matrix(true);
        std::cout << "Iterations: " << result_auto2.iterations << "\n";
        std::cout << "Status: " << (result_auto2.status == TINY_OK ? "OK" : "Error") << "\n";
        std::cout << "Method used: QR (auto-selected for non-symmetric matrix)\n";

        // Check results with detailed error reporting
        float expected_evs[3] = {16.12f, -1.12f, 0.0f};
        bool matched[3] = {false, false, false};
        float errors[3] = {0.0f, 0.0f, 0.0f};
        float rel_errors[3] = {0.0f, 0.0f, 0.0f};

        for (int i = 0; i < result_auto2.eigenvalues.row; ++i)
        {
            float ev = result_auto2.eigenvalues(i, 0);
            float min_error = 1e10f;
            int best_match = -1;

            for (int j = 0; j < 3; ++j)
            {
                if (!matched[j])
                {
                    float error = fabsf(ev - expected_evs[j]);
                    if (error < min_error)
                    {
                        min_error = error;
                        best_match = j;
                    }
                }
            }

            if (best_match >= 0)
            {
                matched[best_match] = true;
                errors[best_match] = min_error;
                float expected = expected_evs[best_match];
                rel_errors[best_match] = (fabsf(expected) > 1e-6f) ? (min_error / fabsf(expected)) : min_error;

                std::cout << "Eigenvalue " << i << ": " << ev << " (Expected: " << expected 
                          << ", Error: " << min_error << ", Rel Error: " << (rel_errors[best_match] * 100.0f) << "%) ";

                bool pass = (fabsf(expected) < 0.1f) ? (min_error < 0.1f) : (rel_errors[best_match] < 0.15f);
                std::cout << (pass ? "[PASS]" : "[FAIL - error too large]") << "\n";
            }
        }

        bool overall_pass = true;
        for (int i = 0; i < 3; ++i)
        {
            bool pass = (fabsf(expected_evs[i]) < 0.1f) ? (errors[i] < 0.1f) : (rel_errors[i] < 0.15f);
            if (!pass) overall_pass = false;
        }
        std::cout << "Overall eigenvalue check: " << (overall_pass ? "[PASS]" : "[FAIL - some eigenvalues have large errors]") << "\n";
    }

    // E3.53: Parameter validation - tolerance < 0
    {
        std::cout << "\n[E3.53] Parameter Validation - tolerance < 0\n";
        tiny::Mat test_mat(2, 2);
        test_mat(0, 0) = 2.0f; test_mat(0, 1) = 1.0f;
        test_mat(1, 0) = 1.0f; test_mat(1, 1) = 2.0f;

        tiny::Mat::EigenDecomposition result_neg = test_mat.eigendecompose(-1e-6f);
        std::cout << "tolerance = -1e-6: Status = " << (result_neg.status == TINY_OK ? "OK" : "Error (Expected)") 
                  << " " << (result_neg.status != TINY_OK ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E3.54: eigendecompose() - Boundary case - empty matrix
    {
        std::cout << "\n[E3.54] eigendecompose() - Boundary Case - Empty Matrix (0x0)\n";
        tiny::Mat empty_mat(0, 0);

        tiny::Mat::EigenDecomposition result_empty = empty_mat.eigendecompose(1e-6f);
        // Error case: empty matrix should return error status, eigenvalues may be 0x0 or 1x1 error matrix
        bool empty_correct = (result_empty.status != TINY_OK) && 
                            ((result_empty.eigenvalues.row == 0 && result_empty.eigenvalues.col == 0) || 
                             (result_empty.eigenvalues.data == nullptr) ||
                             (result_empty.eigenvalues.row == 1 && result_empty.eigenvalues.col == 1 && result_empty.eigenvalues.data != nullptr));
        std::cout << "Empty matrix: Status = " << (result_empty.status == TINY_OK ? "OK" : "Error") 
                  << ", eigenvalues rows = " << result_empty.eigenvalues.row 
                  << " (Expected: Error status, eigenvalues is 0x0 or error state) " << (empty_correct ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E3.55: eigendecompose() - Error handling - non-square matrix
    {
        std::cout << "\n[E3.55] eigendecompose() - Error Handling - Non-Square Matrix\n";
        tiny::Mat non_square(2, 3);
        tiny::Mat::EigenDecomposition result_non_square = non_square.eigendecompose(1e-6f);
        std::cout << "Non-square matrix (2x3): Status = " << (result_non_square.status == TINY_OK ? "OK" : "Error (Expected)") 
                  << " " << (result_non_square.status != TINY_OK ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E3.6: SHM Application Scenario - Structural Dynamics
    std::cout << "\n[E3.6] SHM Application - Structural Dynamics Analysis\n";

    // Create a simple 4-DOF structural system (mass-spring system)
    {
        std::cout << "\n[E3.61] 4-DOF Mass-Spring System\n";
        tiny::Mat K(4, 4);  // Stiffness matrix
        K(0, 0) = 2.0f; K(0, 1) = -1.0f; K(0, 2) = 0.0f; K(0, 3) = 0.0f;
        K(1, 0) = -1.0f; K(1, 1) = 2.0f; K(1, 2) = -1.0f; K(1, 3) = 0.0f;
        K(2, 0) = 0.0f; K(2, 1) = -1.0f; K(2, 2) = 2.0f; K(2, 3) = -1.0f;
        K(3, 0) = 0.0f; K(3, 1) = 0.0f; K(3, 2) = -1.0f; K(3, 3) = 1.0f;

        std::cout << "Stiffness Matrix K:\n";
        K.print_matrix(true);
        std::cout << "Is symmetric: " << (K.is_symmetric(1e-6f) ? "Yes" : "No") << "\n";

        // Quick frequency identification using power iteration
        std::cout << "\n[Quick Analysis] Primary frequency using power_iteration():\n";
        std::cout << "[Expected Results]\n";
        std::cout << "  Expected primary eigenvalue: ~3.53 (largest eigenvalue)\n";
        std::cout << "  Expected primary frequency: sqrt(3.53) ≈ 1.88 rad/s\n";

        tiny::Mat::EigenPair primary = K.power_iteration(500, 1e-6f);
        std::cout << "\n[Actual Results]\n";
        std::cout << "  Primary eigenvalue: " << primary.eigenvalue << " (Expected: ~3.53)\n";
        std::cout << "  Primary frequency: " << sqrtf(primary.eigenvalue) << " rad/s (Expected: ~1.88 rad/s)\n";
        std::cout << "  Iterations: " << primary.iterations << "\n";
        float error_primary = fabsf(primary.eigenvalue - 3.53f);
        std::cout << "  Error from expected: " << error_primary << (error_primary < 0.2f ? " [PASS]" : " [FAIL]") << "\n";

        // Complete modal analysis using Jacobi
        std::cout << "\n[Complete Analysis] Full modal analysis using eigendecompose_jacobi():\n";
        std::cout << "[Expected Results]\n";
        std::cout << "  Expected eigenvalues (approximate): 3.53, 2.35, 1.00, 0.12\n";
        std::cout << "  Expected natural frequencies: 1.88, 1.53, 1.00, 0.35 rad/s\n";
        std::cout << "  Note: These are approximate values for the 4-DOF system\n";

        tiny::Mat::EigenDecomposition modal = K.eigendecompose_jacobi(1e-5f, 100);
        std::cout << "\n[Actual Results]\n";
        std::cout << "All eigenvalues (natural frequencies squared):\n";
        modal.eigenvalues.print_matrix(true);
        std::cout << "Natural frequencies (rad/s):\n";
        float expected_freqs_4dof[4] = {1.88f, 1.53f, 1.00f, 0.35f};
        for (int i = 0; i < modal.eigenvalues.row; ++i)
        {
            float freq = sqrtf(modal.eigenvalues(i, 0));
            std::cout << "  Mode " << i << ": " << freq << " rad/s";
            // Check if frequency matches any expected value
            bool matched = false;
            for (int j = 0; j < 4; ++j)
            {
                if (fabsf(freq - expected_freqs_4dof[j]) < 0.15f)
                {
                    std::cout << " (Expected: ~" << expected_freqs_4dof[j] << " rad/s) [PASS]";
                    matched = true;
                    break;
                }
            }
            if (!matched) std::cout << " [CHECK]";
            std::cout << "\n";
        }
        std::cout << "Mode shapes (eigenvectors):\n";
        modal.eigenvectors.print_matrix(true);
        std::cout << "Total iterations: " << modal.iterations << "\n";
    }

    // E3.7: Edge Cases and Error Handling
    std::cout << "\n[E3.7] Edge Cases and Error Handling\n";

    // E3.71: 1x1 matrix
    {
        std::cout << "\n[E3.71] 1x1 Matrix\n";
        tiny::Mat mat1x1(1, 1);
        mat1x1(0, 0) = 5.0f;
        std::cout << "Matrix: [5.0]\n";
        std::cout << "[Expected Results]\n";
        std::cout << "  Expected eigenvalue: 5.0 (the matrix element itself)\n";
        std::cout << "  Expected eigenvector: [1.0] (normalized)\n";

        tiny::Mat::EigenDecomposition result_1x1 = mat1x1.eigendecompose(1e-6f);
        std::cout << "\n[Actual Results]\n";
        std::cout << "Eigenvalue: " << result_1x1.eigenvalues(0, 0) << " (Expected: 5.0)\n";
        std::cout << "Eigenvector:\n";
        result_1x1.eigenvectors.print_matrix(true);
        float error = fabsf(result_1x1.eigenvalues(0, 0) - 5.0f);
        std::cout << "Error from expected: " << error << (error < 0.01f ? " [PASS]" : " [FAIL]") << "\n";
    }

    // E3.72: Zero matrix
    {
        std::cout << "\n[E3.72] Zero Matrix\n";
        tiny::Mat zero_mat(3, 3);
        zero_mat.clear();
        tiny::Mat::EigenPair result_zero = zero_mat.power_iteration(100, 1e-6f);
        std::cout << "Status: " << (result_zero.status == TINY_OK ? "OK" : "Error (Expected)") << "\n";
    }

    // E3.73: Identity matrix
    {
        std::cout << "\n[E3.73] Identity Matrix\n";
        tiny::Mat I = tiny::Mat::eye(3);
        std::cout << "Matrix (3x3 Identity):\n";
        I.print_matrix(true);
        std::cout << "\n[Expected Results]\n";
        std::cout << "  Expected eigenvalues: 1.0, 1.0, 1.0 (all eigenvalues are 1)\n";
        std::cout << "  Expected eigenvectors: Any orthonormal basis (e.g., standard basis vectors)\n";
        std::cout << "  Expected iterations: 1 (should converge immediately)\n";

        tiny::Mat::EigenDecomposition result_I = I.eigendecompose_jacobi(1e-6f, 10);
        std::cout << "\n[Actual Results]\n";
        std::cout << "Eigenvalues (should all be 1.0):\n";
        result_I.eigenvalues.print_matrix(true);
        std::cout << "Eigenvectors:\n";
        result_I.eigenvectors.print_matrix(true);
        std::cout << "Iterations: " << result_I.iterations << " (Expected: 1)\n";

        // Check all eigenvalues are 1.0
        bool all_one = true;
        for (int i = 0; i < result_I.eigenvalues.row; ++i)
        {
            if (fabsf(result_I.eigenvalues(i, 0) - 1.0f) > 0.01f)
            {
                all_one = false;
                break;
            }
        }
        std::cout << "All eigenvalues = 1.0: " << (all_one ? "[PASS]" : "[FAIL]") << "\n";
    }

    // E3.8: Performance Test for SHM Applications
    std::cout << "\n[E3.8] Performance Test for SHM Applications\n";

    // E3.81: Power iteration performance (fast method for dominant eigenvalue)
    std::cout << "\n[E3.81] Power Iteration Performance (Real-time SHM - Dominant Eigenvalue)\n";
    TIME_OPERATION(
        tiny::Mat::EigenPair perf_result = stiffness.power_iteration(500, 1e-6f);
        (void)perf_result;
    , "Power Iteration (3x3 matrix)");

    // E3.82: Inverse power iteration performance (system identification - smallest eigenvalue)
    std::cout << "\n[E3.82] Inverse Power Iteration Performance (System Identification - Smallest Eigenvalue)\n";
    TIME_OPERATION(
        tiny::Mat::EigenPair perf_inv_result = stiffness.inverse_power_iteration(500, 1e-6f);
        (void)perf_inv_result;
    , "Inverse Power Iteration (3x3 matrix)");

    // E3.83: Jacobi method performance (complete eigendecomposition for symmetric matrices)
    std::cout << "\n[E3.83] Jacobi Method Performance (Complete Eigendecomposition - Symmetric Matrices)\n";
    TIME_OPERATION(
        tiny::Mat::EigenDecomposition perf_jacobi = stiffness.eigendecompose_jacobi(1e-5f, 100);
        (void)perf_jacobi;
    , "Jacobi Decomposition (3x3 symmetric matrix)");

    // E3.84: QR method performance (complete eigendecomposition for general matrices)
    std::cout << "\n[E3.84] QR Method Performance (Complete Eigendecomposition - General Matrices)\n";
    TIME_OPERATION(
        tiny::Mat::EigenDecomposition perf_qr = non_sym_mat.eigendecompose_qr(100, 1e-5f);
        (void)perf_qr;
    , "QR Decomposition (3x3 general matrix)");

    std::cout << "\n[Eigenvalue Decomposition Tests Complete]\n";
}

void tiny_matrix_test()
{
    std::cout << "============ [tiny_matrix_test start] ============\n";
    std::cout << "\n[Test Organization: Application-Oriented Logic]\n";
    std::cout << "  Foundation → Basic Ops → Properties → Linear Systems → Decompositions → Applications → Quality\n\n";

    // ========================================================================
    // Phase 1: Object Foundation (A)
    // ========================================================================
    // Purpose: Learn to create and manipulate matrix objects
    // A1: Constructor & Destructor
    // test_constructor_destructor();

    // A2: Element Access
    // test_element_access();

    // A3: ROI Operations
    // test_roi_operations();

    // ========================================================================
    // Phase 2: Basic Operations (B)
    // ========================================================================
    // Purpose: Learn basic arithmetic operations
    // B1-B8: Arithmetic Operators
    // test_assignment_operator();      // B1
    // test_matrix_addition();         // B2
    // test_constant_addition();       // B3
    // test_matrix_subtraction();      // B4
    // test_constant_subtraction();    // B5
    // test_matrix_division();          // B6
    // test_constant_division();       // B7
    // test_matrix_exponentiation();    // B8

    // ========================================================================
    // Phase 3: Matrix Properties (C)
    // ========================================================================
    // Purpose: Understand matrix properties and basic linear algebra
    // C1-C8: Matrix Properties
    // test_matrix_transpose();        // C1
    // test_matrix_cofactor();         // C2
    // test_matrix_determinant();       // C3
    // test_matrix_adjoint();           // C4
    // test_matrix_normalize();         // C5
    // test_matrix_norm();              // C6
    // test_inverse_adjoint_adjoint();  // C7
    // test_matrix_utilities();         // C8

    // ========================================================================
    // Phase 4: Linear System Solving (D)
    // ========================================================================
    // Purpose: Core application - solving linear systems Ax = b
    // D1-D7: Linear System Solving
    // test_gaussian_eliminate();       // D1
    // test_row_reduce_from_gaussian(); // D2
    // test_inverse_gje();             // D3
    // test_dotprod();                 // D4
    // test_solve();                   // D5
    // test_band_solve();              // D6
    // test_roots();                   // D7

    // ========================================================================
    // Phase 5: Advanced Linear Algebra (E1+2)
    // ========================================================================
    // Purpose: Advanced linear algebra operations for stable and efficient solving
    // E1: Matrix Decomposition
    // test_matrix_decomposition();

    // E2: Gram-Schmidt Orthogonalization
    // test_gram_schmidt_orthogonalize();

    // ========================================================================
    // Phase 6: System Identification Applications (E3)
    // ========================================================================
    // Purpose: Eigenvalue decomposition for SHM and modal analysis
    // E3: Eigenvalue Decomposition
    // test_eigenvalue_decomposition();

    // ========================================================================
    // Phase 7: Auxiliary Functions (F)
    // ========================================================================
    // Purpose: Convenience functions and I/O operations
    // F1: Stream Operators
    // test_stream_operators();

    // F2: Global Arithmetic Operators
    // test_matrix_operations();

    // ========================================================================
    // Phase 8: Quality Assurance (G)
    // ========================================================================
    // Purpose: Ensure robustness, performance, and correctness
    // G1: Boundary Conditions and Error Handling
    test_boundary_conditions();

    // G2: Performance Benchmarks
    test_performance_benchmarks();

    // G3: Memory Layout
    test_memory_layout();

    std::cout << "============ [tiny_matrix_test end] ============\n";

    // Remove current task from watchdog after all tests complete
    // This prevents watchdog timeout after app_main() returns
#if MCU_PLATFORM_SELECTED == MCU_PLATFORM_ESP32
    if (task_wdt_added)
    {
        esp_task_wdt_delete(NULL);  // Remove current task from watchdog
        task_wdt_added = false;
    }
#endif
}

TEST OUTPUTS

Phase 1: Object Foundation (A)

[Test Organization: Application-Oriented Logic]
  Foundation  Basic Ops  Properties  Linear Systems  Decompositions  Applications  Quality


[A1: Constructor & Destructor Tests]
[A1.1] Default Constructor
Matrix Info >>>
rows            1
cols            1
elements        1
paddings        0
stride          1
memory          1
data pointer    0x3fce9a78
temp pointer    0
ext_buff        0
sub_matrix      0
<<< Matrix Info
Matrix Elements >>>
           0       |
<<< Matrix Elements

[A1.2] Constructor with Rows and Cols
Matrix Info >>>
rows            3
cols            4
elements        12
paddings        0
stride          4
memory          12
data pointer    0x3fce9a9c
temp pointer    0
ext_buff        0
sub_matrix      0
<<< Matrix Info
Matrix Elements >>>
           0            0            0            0       |
           0            0            0            0       |
           0            0            0            0       |
<<< Matrix Elements

[A1.3] Constructor with Rows, Cols and Stride
Matrix Info >>>
rows            3
cols            4
elements        12
paddings        1
stride          5
memory          15
data pointer    0x3fce9ad0
temp pointer    0
ext_buff        0
sub_matrix      0
<<< Matrix Info
Matrix Elements >>>
           0            0            0            0       |      0 
           0            0            0            0       |      0 
           0            0            0            0       |      0 
<<< Matrix Elements

[A1.4] Constructor with External Data
Matrix Info >>>
rows            3
cols            4
elements        12
paddings        0
stride          4
memory          12
data pointer    0x3fc9a49c
temp pointer    0
ext_buff        1   (External buffer or View)
sub_matrix      0
<<< Matrix Info
Matrix Elements >>>
           0            1            2            3       |
           4            5            6            7       |
           8            9           10           11       |
<<< Matrix Elements

[A1.5] Constructor with External Data and Stride
Matrix Info >>>
rows            3
cols            4
elements        12
paddings        1
stride          5
memory          15
data pointer    0x3fc9a4f0
temp pointer    0
ext_buff        1   (External buffer or View)
sub_matrix      0
<<< Matrix Info
Matrix Elements >>>
           0            1            2            3       |      0 
           4            5            6            7       |      0 
           8            9           10           11       |      0 
<<< Matrix Elements

[A1.6] Copy Constructor
Matrix Info >>>
rows            3
cols            4
elements        12
paddings        1
stride          5
memory          15
data pointer    0x3fce9bd8
temp pointer    0
ext_buff        0
sub_matrix      0
<<< Matrix Info
Matrix Elements >>>
           0            1            2            3       |2.10195e-44 
           4            5            6            7       |1.61399 
           8            9           10           11       |1.61413 
<<< Matrix Elements


[A2: Element Access Tests]
[A2.1] Non-const Access
Matrix Info >>>
rows            2
cols            3
elements        6
paddings        0
stride          3
memory          6
data pointer    0x3fce9a9c
temp pointer    0
ext_buff        0
sub_matrix      0
<<< Matrix Info
Matrix Elements >>>
         1.1          2.2          3.3       |
         4.4          5.5          6.6       |
<<< Matrix Elements

[A2.2] Const Access
const_mat(0, 0): 1.1

[A3: ROI Operations Tests]
[Material Matrices]
matA:
Matrix Info >>>
rows            2
cols            3
elements        6
paddings        0
stride          3
memory          6
data pointer    0x3fce9a9c
temp pointer    0
ext_buff        0
sub_matrix      0
<<< Matrix Info
Matrix Elements >>>
         0.1          0.2          0.3       |
         0.4          0.5          0.6       |
<<< Matrix Elements

matB:
Matrix Info >>>
rows            3
cols            4
elements        12
paddings        1
stride          5
memory          15
data pointer    0x3fc9a284
temp pointer    0
ext_buff        1   (External buffer or View)
sub_matrix      0
<<< Matrix Info
Matrix Elements >>>
           0            1            2            3       |      0 
           4            5            6            7       |      0 
           8            9           10           11       |      0 
<<< Matrix Elements

matC:
Matrix Info >>>
rows            1
cols            1
elements        1
paddings        0
stride          1
memory          1
data pointer    0x3fce9a78
temp pointer    0
ext_buff        0
sub_matrix      0
<<< Matrix Info
Matrix Elements >>>
           0       |
<<< Matrix Elements

[A3.1] Copy ROI - Over Range Case
[Error] copy_paste: source matrix exceeds destination column boundary: col_pos=2, src.cols=3, dest.cols=4
matB after copy_paste matA at (1, 2):
Matrix Elements >>>
           0            1            2            3       |      0 
           4            5            6            7       |      0 
           8            9           10           11       |      0 
<<< Matrix Elements

nothing changed.
[A3.2] Copy ROI - Suitable Range Case
matB after copy_paste matA at (1, 1):
Matrix Info >>>
rows            3
cols            4
elements        12
paddings        1
stride          5
memory          15
data pointer    0x3fc9a284
temp pointer    0
ext_buff        1   (External buffer or View)
sub_matrix      0
<<< Matrix Info
Matrix Elements >>>
           0            1            2            3       |      0 
           4          0.1          0.2          0.3       |      0 
           8          0.4          0.5          0.6       |      0 
<<< Matrix Elements

successfully copied.
[A3.3] Copy Head
matC after copy_head matB:
Matrix Info >>>
rows            3
cols            4
elements        12
paddings        1
stride          5
memory          15
data pointer    0x3fc9a284
temp pointer    0
ext_buff        1   (External buffer or View)
sub_matrix      0
<<< Matrix Info
Matrix Elements >>>
           0            1            2            3       |      0 
           4          0.1          0.2          0.3       |      0 
           8          0.4          0.5          0.6       |      0 
<<< Matrix Elements

[A3.4] Copy Head - Memory Sharing Check
matB(0, 0) = 99.99f

[A3.5] copy_paste() - Error Handling - Negative Position
[Error] copy_paste: invalid position: row_pos=-1, col_pos=0 (must be non-negative)
copy_paste with row_pos=-1: error = 258 (Expected: TINY_ERR_INVALID_ARG) [PASS]
[Error] copy_paste: invalid position: row_pos=0, col_pos=-1 (must be non-negative)
copy_paste with col_pos=-1: error = 258 (Expected: TINY_ERR_INVALID_ARG) [PASS]

[A3.6] copy_paste() - Error Handling - Out of Bounds
[Error] copy_paste: source matrix exceeds destination row boundary: row_pos=0, src.rows=3, dest.rows=2
copy_paste 3x3 into 2x2 at (0,0): error = 258 (Expected: TINY_ERR_INVALID_ARG) [PASS]
[Error] copy_paste: source matrix exceeds destination row boundary: row_pos=1, src.rows=2, dest.rows=2
copy_paste 2x2 into 2x2 at (1,1): error = 258 (Expected: TINY_ERR_INVALID_ARG) [PASS]

[A3.7] copy_paste() - Boundary Case - Empty Source Matrix
[>>> Error ! <<<] Memory allocation failed in alloc_mem()
[Error] copy_paste: source matrix data pointer is null
copy_paste empty matrix: error = 258 (Expected: TINY_ERR_INVALID_ARG) [PASS]

[A3.8] copy_head() - Error Handling - Source Owns Its Memory
[Error] copy_head: source matrix owns its memory (ext_buff=false). Cannot share pointer - would cause double-free. Use copy assignment or copy constructor instead.
copy_head from matrix with owned memory: error = 258 (Expected: TINY_ERR_INVALID_ARG) [PASS]
matC (should be unchanged):
Matrix Info >>>
rows            3
cols            4
elements        12
paddings        1
stride          5
memory          15
data pointer    0x3fc9a284
temp pointer    0
ext_buff        1   (External buffer or View)
sub_matrix      0
<<< Matrix Info
Matrix Elements >>>
       99.99            1            2            3       |      0 
           4          0.1          0.2          0.3       |      0 
           8          0.4          0.5          0.6       |      0 
<<< Matrix Elements

[A3.9] Get a View of ROI - Low Level Function
get a view of ROI with overrange dimensions - rows:
[Error] view_roi: ROI exceeds row boundary: start_row=1, roi_rows=3, source.rows=3
get a view of ROI with overrange dimensions - cols:
[Error] view_roi: ROI exceeds column boundary: start_col=1, roi_cols=4, source.cols=4
get a view of ROI with suitable dimensions:
roi3:
Matrix Info >>>
rows            2
cols            2
elements        4
paddings        3
stride          5
memory          10
data pointer    0x3fc9a29c
temp pointer    0
ext_buff        1   (External buffer or View)
sub_matrix      1   (This is a Sub-Matrix View)
<<< Matrix Info
Matrix Elements >>>
         0.1          0.2       |    0.3            0            8 
         0.4          0.5       |    0.6            0   4.2039e-45 
<<< Matrix Elements

[A3.10] Get a View of ROI - Using ROI Structure
Matrix Info >>>
rows            2
cols            2
elements        4
paddings        3
stride          5
memory          10
data pointer    0x3fc9a29c
temp pointer    0
ext_buff        1   (External buffer or View)
sub_matrix      1   (This is a Sub-Matrix View)
<<< Matrix Info
Matrix Elements >>>
         0.1          0.2       |    0.3            0            8 
         0.4          0.5       |    0.6            0   4.2039e-45 
<<< Matrix Elements

[A3.11] Copy ROI - Low Level Function
Matrix Info >>>
rows            2
cols            2
elements        4
paddings        0
stride          2
memory          4
data pointer    0x3fce9ca8
temp pointer    0
ext_buff        0
sub_matrix      0
<<< Matrix Info
Matrix Elements >>>
         0.1          0.2       |
         0.4          0.5       |
<<< Matrix Elements

[A3.12] Copy ROI - Using ROI Structure
time for copy_roi using ROI structure: 46 ms
Matrix Info >>>
rows            2
cols            2
elements        4
paddings        0
stride          2
memory          4
data pointer    0x3fce9cbc
temp pointer    0
ext_buff        0
sub_matrix      0
<<< Matrix Info
Matrix Elements >>>
         0.1          0.2       |
         0.4          0.5       |
<<< Matrix Elements


[A3.13] ROI resize_roi() Function
Initial ROI: pos_x=0, pos_y=0, width=2, height=2
After resize_roi(1, 1, 3, 3): pos_x=1, pos_y=1, width=3, height=3
ROI resize test: [PASS]

[A3.14] ROI area_roi() Function
ROI(0, 0, 3, 4) area: 12 (Expected: 12) [PASS]
ROI(1, 2, 5, 6) area: 30 (Expected: 30) [PASS]
[A3.15] Block
time for block: 50 ms
Matrix Info >>>
rows            2
cols            2
elements        4
paddings        0
stride          2
memory          4
data pointer    0x3fce9cd0
temp pointer    0
ext_buff        0
sub_matrix      0
<<< Matrix Info
Matrix Elements >>>
         0.1          0.2       |
         0.4          0.5       |
<<< Matrix Elements

[A3.16] Swap Rows
matB before swap rows:
Matrix Info >>>
rows            3
cols            4
elements        12
paddings        1
stride          5
memory          15
data pointer    0x3fc9a284
temp pointer    0
ext_buff        1   (External buffer or View)
sub_matrix      0
<<< Matrix Info
Matrix Elements >>>
       99.99            1            2            3       |      0 
           4          0.1          0.2          0.3       |      0 
           8          0.4          0.5          0.6       |      0 
<<< Matrix Elements

matB after swap_rows(0, 2):
Matrix Info >>>
rows            3
cols            4
elements        12
paddings        1
stride          5
memory          15
data pointer    0x3fc9a284
temp pointer    0
ext_buff        1   (External buffer or View)
sub_matrix      0
<<< Matrix Info
Matrix Elements >>>
           8          0.4          0.5          0.6       |      0 
           4          0.1          0.2          0.3       |      0 
       99.99            1            2            3       |      0 
<<< Matrix Elements

[A3.17] Swap Columns
matB before swap columns:
Matrix Info >>>
rows            3
cols            4
elements        12
paddings        1
stride          5
memory          15
data pointer    0x3fc9a284
temp pointer    0
ext_buff        1   (External buffer or View)
sub_matrix      0
<<< Matrix Info
Matrix Elements >>>
           8          0.4          0.5          0.6       |      0 
           4          0.1          0.2          0.3       |      0 
       99.99            1            2            3       |      0 
<<< Matrix Elements

matB after swap_cols(0, 2):
Matrix Info >>>
rows            3
cols            4
elements        12
paddings        1
stride          5
memory          15
data pointer    0x3fc9a284
temp pointer    0
ext_buff        1   (External buffer or View)
sub_matrix      0
<<< Matrix Info
Matrix Elements >>>
         0.5          0.4            8          0.6       |      0 
         0.2          0.1            4          0.3       |      0 
           2            1        99.99            3       |      0 
<<< Matrix Elements

[A3.18] Clear
matB before clear:
Matrix Info >>>
rows            3
cols            4
elements        12
paddings        1
stride          5
memory          15
data pointer    0x3fc9a284
temp pointer    0
ext_buff        1   (External buffer or View)
sub_matrix      0
<<< Matrix Info
Matrix Elements >>>
         0.5          0.4            8          0.6       |      0 
         0.2          0.1            4          0.3       |      0 
           2            1        99.99            3       |      0 
<<< Matrix Elements

matB after clear:
Matrix Info >>>
rows            3
cols            4
elements        12
paddings        1
stride          5
memory          15
data pointer    0x3fc9a284
temp pointer    0
ext_buff        1   (External buffer or View)
sub_matrix      0
<<< Matrix Info
Matrix Elements >>>
           0            0            0            0       |      0 
           0            0            0            0       |      0 
           0            0            0            0       |      0 
<<< Matrix Elements

Phase 2: Basic Operations (B)

[Test Organization: Application-Oriented Logic]
  Foundation  Basic Ops  Properties  Linear Systems  Decompositions  Applications  Quality


[B1: Assignment Operator Tests]

[B1.1] Assignment (Same Dimensions)
Matrix Elements >>>
           1            2            3       |
           4            5            6       |
<<< Matrix Elements


[B1.2] Assignment (Different Dimensions)
Matrix Elements >>>
           1            2            3       |
           4            5            6       |
<<< Matrix Elements


[B1.3] Assignment to Sub-Matrix (Expect Error)
[Error] Assignment to a sub-matrix is not allowed.
Matrix Elements >>>
           5            6       |      7            0            8 
           9           10       |     11            0   4.2039e-45 
<<< Matrix Elements


[B1.4] Self-Assignment
Matrix Elements >>>
           1            2            3       |
           4            5            6       |
<<< Matrix Elements


[B2: Matrix Addition Tests]

[B2.1] Matrix Addition (Same Dimensions)
Matrix Elements >>>
           2            3            4       |
           5            6            7       |
<<< Matrix Elements


[B2.2] Sub-Matrix Addition
Matrix Elements >>>
          10           12       |      7            0            8 
          18           20       |     11            0           12 
<<< Matrix Elements


[B2.3] Full Matrix + Sub-Matrix Addition
Matrix Elements >>>
          12           14       |
          20           22       |
<<< Matrix Elements


[B2.4] Addition Dimension Mismatch (Expect Error)
[Error] Matrix addition failed: Dimension mismatch (2x2 vs 3x3)

[B3: Constant Addition Tests]

[B3.1] Full Matrix + Constant
Matrix Elements >>>
           5            6            7       |
           8            9           10       |
<<< Matrix Elements


[B3.2] Sub-Matrix + Constant
Matrix Elements >>>
           8            9       |      7            0            8 
          12           13       |     11            0           12 
<<< Matrix Elements


[B3.3] Add Zero
Matrix Elements >>>
           1            2       |
           3            4       |
<<< Matrix Elements


[B3.4] Add Negative Constant
Matrix Elements >>>
          -5            5       |
          15           25       |
<<< Matrix Elements


[B4: Matrix Subtraction Tests]

[B4.1] Matrix Subtraction
Matrix Elements >>>
           4            5       |
           6            7       |
<<< Matrix Elements


[B4.2] Subtraction Dimension Mismatch (Expect Error)
[Error] Matrix subtraction failed: Dimension mismatch (2x2 vs 3x3)

[B5: Constant Subtraction Tests]

[B5.1] Full Matrix - Constant
Matrix Elements >>>
          -1            0            1       |
           2            3            4       |
<<< Matrix Elements


[B5.2] Sub-Matrix - Constant
Matrix Elements >>>
         3.5          4.5       |      7            0            8 
         7.5          8.5       |     11            0   4.2039e-45 
<<< Matrix Elements


[B6: Matrix Element-wise Division Tests]

[B6.1] Element-wise Division (Same Dimensions, No Zero)
Matrix Elements >>>
           5            5       |
           6            5       |
<<< Matrix Elements


[B6.2] Dimension Mismatch (Expect Error)
[Error] Matrix division failed: Dimension mismatch (2x2 vs 3x3)

[B6.3] Division by Matrix Containing Zero (Expect Error)
[Error] Matrix division failed: Division by zero detected at position (0, 1)
Matrix Elements >>>
           5           10       |
          15           20       |
<<< Matrix Elements


[B7: Matrix Division by Constant Tests]

[B7.1] Divide Full Matrix by Positive Constant
Matrix Elements >>>
           1          1.5            2       |
         2.5            3          3.5       |
<<< Matrix Elements


[B7.2] Divide Matrix by Negative Constant
Matrix Elements >>>
          -2           -4       |
          -6           -8       |
<<< Matrix Elements


[B7.3] Division by Zero Constant (Expect Error)
[Error] Matrix division by zero is undefined (divisor=0)
Matrix Elements >>>
           1            2       |
           3            4       |
<<< Matrix Elements


[B8: Matrix Exponentiation Tests]

[B8.1] Raise Each Element to Power of 2
Matrix Elements >>>
           4            9       |
          16           25       |
<<< Matrix Elements


[B8.2] Raise Each Element to Power of 0
Matrix Elements >>>
           1            1       |
           1            1       |
<<< Matrix Elements


[B8.3] Raise Each Element to Power of 1
Matrix Elements >>>
           9            8       |
           7            6       |
<<< Matrix Elements


[B8.4] Raise Each Element to Power of -1 (Expect Error or Warning)
[Error] Negative exponent not supported in operator^ (exponent=-1)
Matrix Elements >>>
           1            2       |
           4            5       |
<<< Matrix Elements


[B8.5] Raise Matrix Containing Zero to Power of 3
Matrix Elements >>>
           0            8       |
          -1           27       |
<<< Matrix Elements

PPhase 3: Matrix Properties (C)

[Test Organization: Application-Oriented Logic]
  Foundation  Basic Ops  Properties  Linear Systems  Decompositions  Applications  Quality


[C1: Matrix Transpose Tests]

[C1.1] Transpose of 2x3 Matrix
Original 2x3 Matrix:
Matrix Elements >>>
           1            2            3       |
           4            5            6       |
<<< Matrix Elements

Transposed 3x2 Matrix:
Matrix Elements >>>
           1            4       |
           2            5       |
           3            6       |
<<< Matrix Elements


[C1.2] Transpose of 3x3 Square Matrix
Original 3x3 Matrix:
Matrix Elements >>>
           1            2            3       |
           4            5            6       |
           7            8            9       |
<<< Matrix Elements

Transposed 3x3 Matrix:
Matrix Elements >>>
           1            4            7       |
           2            5            8       |
           3            6            9       |
<<< Matrix Elements


[C1.3] Transpose of Matrix with Padding
Original 4x2 Matrix (with padding):
Matrix Elements >>>
           1            2       |      0 
           3            4       |      0 
           5            6       |      0 
           7            8       |      0 
<<< Matrix Elements

Transposed 2x4 Matrix:
Matrix Elements >>>
           1            3            5            7       |
           2            4            6            8       |
<<< Matrix Elements


[C1.4] Transpose of Empty Matrix
Matrix Elements >>>
           0       |
<<< Matrix Elements

Matrix Elements >>>
           0       |
<<< Matrix Elements


[C2: Matrix Minor and Cofactor Tests]

[C2.1] Minor of 3x3 Matrix (Remove Row 1, Col 1)
Original 3x3 Matrix:
Matrix Elements >>>
           1            2            3       |
           4            5            6       |
           7            8            9       |
<<< Matrix Elements

Minor Matrix (remove row 1, col 1, no sign):
Matrix Elements >>>
           1            3       |
           7            9       |
<<< Matrix Elements


[C2.2] Cofactor of 3x3 Matrix (Remove Row 1, Col 1)
Note: Cofactor matrix is the same as minor matrix.
      The sign (-1)^(i+j) is applied when computing cofactor value, not to matrix elements.
Cofactor Matrix (same as minor):
Matrix Elements >>>
           1            3       |
           7            9       |
<<< Matrix Elements


[C2.3] Minor (Remove Row 0, Col 0)
Matrix Elements >>>
           5            6       |
           8            9       |
<<< Matrix Elements


[C2.4] Cofactor (Remove Row 0, Col 0)
Note: Cofactor matrix is the same as minor matrix.
Matrix Elements >>>
           5            6       |
           8            9       |
<<< Matrix Elements


[C2.5] Cofactor (Remove Row 0, Col 1)
Note: Cofactor matrix is the same as minor matrix.
      When computing cofactor value, sign (-1)^(0+1) = -1 would be applied.
Cofactor Matrix (same as minor):
Matrix Elements >>>
           4            6       |
           7            9       |
<<< Matrix Elements


[C2.6] Minor (Remove Row 2, Col 2)
Matrix Elements >>>
           1            2       |
           4            5       |
<<< Matrix Elements


[C2.7] Cofactor (Remove Row 2, Col 2)
Note: Cofactor matrix is the same as minor matrix.
Matrix Elements >>>
           1            2       |
           4            5       |
<<< Matrix Elements


[C2.8] Minor of 4x4 Matrix (Remove Row 2, Col 1)
Matrix Elements >>>
           1            2            3            4       |
           5            6            7            8       |
           9           10           11           12       |
          13           14           15           16       |
<<< Matrix Elements

Minor Matrix:
Matrix Elements >>>
           1            3            4       |
           5            7            8       |
          13           15           16       |
<<< Matrix Elements


[C2.9] Cofactor of 4x4 Matrix (Remove Row 2, Col 1)
Note: Cofactor matrix is the same as minor matrix.
      When computing cofactor value, sign (-1)^(2+1) = -1 would be applied.
Cofactor Matrix (same as minor):
Matrix Elements >>>
           1            3            4       |
           5            7            8       |
          13           15           16       |
<<< Matrix Elements


[C2.10] Non-square Matrix (Expect Error)
Testing minor():
[Error] Minor requires square matrix (got 3x4)
minor() result: Non-empty (Error) [FAIL]
Testing cofactor():
[Error] Minor requires square matrix (got 3x4)
cofactor() result: Non-empty (Error) [FAIL]

[C2.11] minor() - Boundary Case - Out of Bounds Indices
[Error] minor: target_row=-1 is out of range [0, 2]
minor(-1, 0): Non-empty (Error) [FAIL]
[Error] minor: target_col=-1 is out of range [0, 2]
minor(0, -1): Non-empty (Error) [FAIL]
[Error] minor: target_row=3 is out of range [0, 2]
minor(3, 0) (out of bounds): Non-empty (Error) [FAIL]

[C2.12] minor() - Boundary Case - 1x1 Matrix
[>>> Error ! <<<] Memory allocation failed in alloc_mem()
1x1 matrix minor(0,0): Empty matrix (Expected) [PASS]

[C3: Matrix Determinant Tests]

[C3.1] 1x1 Matrix Determinant
Matrix:
Matrix Elements >>>
           7       |
<<< Matrix Elements

Determinant: 7  (Expected: 7)

[C3.2] 2x2 Matrix Determinant
Matrix:
Matrix Elements >>>
           3            8       |
           4            6       |
<<< Matrix Elements

Determinant: -14  (Expected: -14)

[C3.3] 3x3 Matrix Determinant
Matrix:
Matrix Elements >>>
           1            2            3       |
           0            4            5       |
           1            0            6       |
<<< Matrix Elements

Determinant: 22  (Expected: 22)

[C3.4] 4x4 Matrix Determinant
Matrix:
Matrix Elements >>>
           1            2            3            4       |
           5            6            7            8       |
           9           10           11           12       |
          13           14           15           16       |
<<< Matrix Elements

Note: This matrix has linearly dependent rows (each row differs by constant 4),
      so the determinant should be 0.
Determinant: 0  (Expected: 0)

[C3.5] 5x5 Matrix Determinant (Tests Auto-select to LU Method)
Matrix (5x5, tridiagonal):
Matrix Elements >>>
           2            1            0            0            0       |
           1            2            1            0            0       |
           0            1            2            1            0       |
           0            0            1            2            1       |
           0            0            0            1            2       |
<<< Matrix Elements

Determinant (auto-select, should use LU for n > 4): 6
Note: For n = 5 > 4, auto-select should use LU decomposition (O()).

[C3.6] Non-square Matrix (Expect Error)
Matrix (3x4, non-square):
Matrix Elements >>>
           0            0            0            0       |
           0            0            0            0       |
           0            0            0            0       |
<<< Matrix Elements

[Error] Determinant requires a square matrix (got 3x4)
Determinant: 0  (Expected: 0 with error message)

[C3.7] Comparison of Different Methods (5x5 Matrix)
Matrix (5x5):
Matrix Elements >>>
           2            2            3            4            5       |
           2            5            6            8           10       |
           3            6           10           12           15       |
           4            8           12           17           20       |
           5           10           15           20           26       |
<<< Matrix Elements

Determinant (auto-select): 56  (should use LU for n > 4)
Determinant (Laplace):     56  (O(n!), slow for n=5)
Determinant (LU):          56  (O(), efficient)
Determinant (Gaussian):    56  (O(), efficient)
Note: All methods should give the same result (within numerical precision).
      Auto-select should use LU for n > 4, avoiding slow Laplace expansion.

[C3.8] Large Matrix (6x6) - Tests Efficient Methods
Matrix (6x6, showing first 4x4 block):
       1.5          2          3          4 ...
         2        4.5          6          8 ...
         3          6        9.5         12 ...
         4          8         12       16.5 ...
...
Determinant (auto-select, uses LU): 2.85938
Determinant (LU):                   2.85938
Determinant (Gaussian):             2.85938
Note: For n > 4, auto-select uses LU decomposition (O() instead of O(n!)).

[C3.9] Large Matrix (8x8) - Performance Comparison
Matrix (8x8, showing first 4x4 block):
         1          2          3          4 ...
         2          4          6          8 ...
         3          6          9         12 ...
         4          8         12         16 ...
...
[Error] LU decomposition: Matrix is singular or near-singular.
[Warning] determinant_lu: LU decomposition failed (status=458754), matrix may be singular
Determinant (LU):       0
Determinant (Gaussian): 0
Note: Both methods are O() and should be much faster than Laplace expansion.

[C3.10] determinant_laplace() - Boundary Case - Empty Matrix
[>>> Error ! <<<] Memory allocation failed in alloc_mem()
[Error] determinant_laplace: matrix data pointer is null
Empty matrix determinant (Laplace): 0 (Expected: 1.0) [FAIL]

[C3.11] determinant_lu() - Boundary Case - Empty Matrix
[Error] determinant_lu: matrix data pointer is null
Empty matrix determinant (LU): 0 (Expected: 1.0) [FAIL]

[C3.12] determinant_gaussian() - Boundary Case - Empty Matrix
[Error] determinant_gaussian: matrix data pointer is null
Empty matrix determinant (Gaussian): 0 (Expected: 1.0) [FAIL]

[C3.13] Determinant Methods - Non-Square Matrix
[Error] Determinant requires a square matrix (got 2x3)
[Error] Determinant requires a square matrix (got 2x3)
[Error] Determinant requires a square matrix (got 2x3)
Non-square matrix (2x3) determinant (Laplace): 0 (Expected: 0.0) [PASS]
Non-square matrix (2x3) determinant (LU): 0 (Expected: 0.0) [PASS]
Non-square matrix (2x3) determinant (Gaussian): 0 (Expected: 0.0) [PASS]

[C4: Matrix Adjoint Tests]

[C4.1] Adjoint of 1x1 Matrix
Original Matrix:
Matrix Elements >>>
           5       |
<<< Matrix Elements

[>>> Error ! <<<] Memory allocation failed in alloc_mem()
[Error] adjoint: failed to create cofactor matrix at (0, 0)
Adjoint Matrix:
Matrix Elements >>>
           0       |
<<< Matrix Elements


[C4.2] Adjoint of 2x2 Matrix
Original Matrix:
Matrix Elements >>>
           1            2       |
           3            4       |
<<< Matrix Elements

Adjoint Matrix:
Matrix Elements >>>
           4           -2       |
          -3            1       |
<<< Matrix Elements


[C4.3] Adjoint of 3x3 Matrix
Original Matrix:
Matrix Elements >>>
           1            2            3       |
           0            4            5       |
           1            0            6       |
<<< Matrix Elements

Adjoint Matrix:
Matrix Elements >>>
          24          -12           -2       |
           5            3           -5       |
          -4            2            4       |
<<< Matrix Elements


[C4.4] Adjoint of Non-Square Matrix (Expect Error)
Original Matrix (2x3, non-square):
Matrix Elements >>>
           0            0            0       |
           0            0            0       |
<<< Matrix Elements

[Error] Adjoint requires a square matrix (got 2x3)
Adjoint Matrix (should be empty due to error):
Matrix Elements >>>
           0       |
<<< Matrix Elements


[C5: Matrix Normalization Tests]

[C5.1] Normalize a Standard 2x2 Matrix
Before normalization:
Matrix Elements >>>
           3            4       |
           3            4       |
<<< Matrix Elements

After normalization (Expected L2 norm = 1):
Matrix Elements >>>
    0.424264     0.565685       |
    0.424264     0.565685       |
<<< Matrix Elements


[C5.2] Normalize a 2x2 Matrix with Stride=4 (Padding Test)
Before normalization:
Matrix Elements >>>
           3            4       |      0            0 
           3            4       |      0            0 
<<< Matrix Elements

After normalization:
Matrix Elements >>>
    0.424264     0.565685       |      0            0 
    0.424264     0.565685       |      0            0 
<<< Matrix Elements


[C5.3] Normalize a Zero Matrix (Expect Warning)
Matrix Elements >>>
           0            0       |
           0            0       |
<<< Matrix Elements

[Warning] normalize: matrix norm is zero (matrix is all zeros), normalization skipped

[C6: Matrix Norm Calculation Tests]

[C6.1] 2x2 Matrix Norm (Expect 5.0)
Matrix:
Matrix Elements >>>
           3            4       |
           0            0       |
<<< Matrix Elements

Calculated Norm: 5

[C6.2] Zero Matrix Norm (Expect 0.0)
Matrix:
Matrix Elements >>>
           0            0            0       |
           0            0            0       |
           0            0            0       |
<<< Matrix Elements

Calculated Norm: 0

[C6.3] Matrix with Negative Values
Matrix:
Matrix Elements >>>
          -1           -2       |
          -3           -4       |
<<< Matrix Elements

Calculated Norm: 5.47723  (Expect sqrt(30)  5.477)

[C6.4] 2x2 Matrix with Stride=4 (Padding Test)
Matrix:
Matrix Elements >>>
           1            2       |      0            0 
           3            4       |      0            0 
<<< Matrix Elements

Calculated Norm: 5.47723  (Expect sqrt(30)  5.477)

[C7: Matrix Inversion Tests]

[C7.1] Inverse of 2x2 Matrix
Original Matrix:
Matrix Elements >>>
           4            7       |
           2            6       |
<<< Matrix Elements

Inverse Matrix:
Matrix Elements >>>
         0.6         -0.7       |
        -0.2          0.4       |
<<< Matrix Elements

Expected Approx:
[ 0.6  -0.7 ]
[ -0.2  0.4 ]

[C7.2] Singular Matrix (Expect Error)
Original Matrix:
Matrix Elements >>>
           1            2       |
           2            4       |
<<< Matrix Elements

Note: This matrix is singular (determinant = 0), so inverse should fail.
[Error] inverse_adjoint: matrix is singular (det=0), cannot compute inverse
Inverse Matrix (Should be zero matrix):
Matrix Elements >>>
           0       |
<<< Matrix Elements


[C7.3] Inverse of 3x3 Matrix
Original Matrix:
Matrix Elements >>>
           3            0            2       |
           2            0           -2       |
           0            1            1       |
<<< Matrix Elements

Inverse Matrix:
Matrix Elements >>>
         0.2          0.2           -0       |
        -0.2          0.3            1       |
         0.2         -0.3            0       |
<<< Matrix Elements


[C7.4] Non-Square Matrix (Expect Error)
Original Matrix (2x3, non-square):
Matrix Elements >>>
           0            0            0       |
           0            0            0       |
<<< Matrix Elements

[Error] inverse_adjoint: requires square matrix (got 2x3)
Inverse Matrix (should be empty due to error):
Matrix Elements >>>
           0       |
<<< Matrix Elements


[C8: Matrix Utilities Tests]

[C8.1] Generate Identity Matrix (eye)
3x3 Identity Matrix:
Matrix Elements >>>
           1            0            0       |
           0            1            0       |
           0            0            1       |
<<< Matrix Elements

5x5 Identity Matrix:
Matrix Elements >>>
           1            0            0            0            0       |
           0            1            0            0            0       |
           0            0            1            0            0       |
           0            0            0            1            0       |
           0            0            0            0            1       |
<<< Matrix Elements


[C8.2] Generate Ones Matrix
3x4 Ones Matrix:
Matrix Elements >>>
           1            1            1            1       |
           1            1            1            1       |
           1            1            1            1       |
<<< Matrix Elements

4x4 Ones Matrix (Square):
Matrix Elements >>>
           1            1            1            1       |
           1            1            1            1       |
           1            1            1            1       |
           1            1            1            1       |
<<< Matrix Elements


[C8.3] Augment Two Matrices Horizontally [A | B]
Matrix A:
Matrix Elements >>>
           1            2       |
           3            4       |
<<< Matrix Elements

Matrix B:
Matrix Elements >>>
           5            6            7       |
           8            9           10       |
<<< Matrix Elements

Augmented Matrix [A | B]:
Matrix Elements >>>
           1            2            5            6            7       |
           3            4            8            9           10       |
<<< Matrix Elements


[C8.4] Augment with Row Mismatch (Expect Error)
[Error] augment: row counts must match (A: 2, B: 3)
Matrix Info >>>
rows            1
cols            1
elements        1
paddings        0
stride          1
memory          1
data pointer    0x3fce9c54
temp pointer    0
ext_buff        0
sub_matrix      0
<<< Matrix Info

[C8.5] Vertically Stack Two Matrices [A; B]
Matrix A (top):
Matrix Elements >>>
           1            2            3       |
           4            5            6       |
<<< Matrix Elements

Matrix B (bottom):
Matrix Elements >>>
           7            8            9       |
          10           11           12       |
<<< Matrix Elements

Vertically Stacked Matrix [A; B]:
Matrix Elements >>>
           1            2            3       |
           4            5            6       |
           7            8            9       |
          10           11           12       |
<<< Matrix Elements

Expected: 4x3 matrix with A on top, B on bottom

[C8.6] Vertical Stack with Different Row Counts (Same Columns)
Matrix A (1x3):
Matrix Elements >>>
           1            2            3       |
<<< Matrix Elements

Matrix B (3x3):
Matrix Elements >>>
           4            5            6       |
           7            8            9       |
          10           11           12       |
<<< Matrix Elements

Vertically Stacked Matrix [A; B] (1x3 + 3x3 = 4x3):
Matrix Elements >>>
           1            2            3       |
           4            5            6       |
           7            8            9       |
          10           11           12       |
<<< Matrix Elements


[C8.7] VStack with Column Mismatch (Expect Error)
Matrix A (2x2):
Matrix Elements >>>
           1            2       |
           3            4       |
<<< Matrix Elements

Matrix B (2x3, different columns):
Matrix Elements >>>
           5            6            7       |
           8            9           10       |
<<< Matrix Elements

[Error] vstack: column counts must match (A: 2, B: 3)
Result (should be empty due to error):
Matrix Info >>>
rows            1
cols            1
elements        1
paddings        0
stride          1
memory          1
data pointer    0x3fce9e1c
temp pointer    0
ext_buff        0
sub_matrix      0
<<< Matrix Info

Phase 4: Linear System Solving (D)

[Test Organization: Application-Oriented Logic]
  Foundation  Basic Ops  Properties  Linear Systems  Decompositions  Applications  Quality


[D1: Gaussian Elimination Tests]

[D1.1] 3x3 Matrix (Simple Upper Triangular)
Original Matrix:
Matrix Elements >>>
           2            1           -1       |
          -3           -1            2       |
          -2            1            2       |
<<< Matrix Elements

After Gaussian Elimination (Should be upper triangular):
Matrix Elements >>>
           2            1           -1       |
           0          0.5          0.5       |
           0            0           -1       |
<<< Matrix Elements


[D1.2] 3x4 Augmented Matrix (Linear System Ax = b)
Original Augmented Matrix [A | b]:
Matrix Elements >>>
           1            2           -1            8       |
          -3           -1            2          -11       |
          -2            1            2           -3       |
<<< Matrix Elements

After Gaussian Elimination (Row Echelon Form):
Matrix Elements >>>
           1            2           -1            8       |
           0            5           -1           13       |
           0            0            1            0       |
<<< Matrix Elements


[D1.3] Singular Matrix (No Unique Solution)
Original Singular Matrix:
Matrix Elements >>>
           1            2       |
           2            4       |
<<< Matrix Elements

After Gaussian Elimination (Should show rows of zeros):
Matrix Elements >>>
           1            2       |
           0            0       |
<<< Matrix Elements


[D1.4] Zero Matrix
Matrix Elements >>>
           0            0            0       |
           0            0            0       |
           0            0            0       |
<<< Matrix Elements

After Gaussian Elimination (Should be a zero matrix):
Matrix Elements >>>
           0            0            0       |
           0            0            0       |
           0            0            0       |
<<< Matrix Elements


[D1.5] gaussian_eliminate() - Boundary Case - Empty Matrix
[>>> Error ! <<<] Memory allocation failed in alloc_mem()
[Error] gaussian_eliminate: matrix data pointer is null
Empty matrix gaussian_eliminate: Empty matrix or error state (Expected) [PASS]

[D1.6] gaussian_eliminate() - Boundary Case - 1x1 Matrix
1x1 matrix after gaussian_eliminate:
Matrix Elements >>>
           5       |
<<< Matrix Elements

1x1 matrix gaussian_eliminate: [PASS]

[D2: Row Reduce from Gaussian (RREF) Tests]

[D2.1] 3x4 Augmented Matrix
Original Matrix:
Matrix Elements >>>
           1            2           -1           -4       |
           2            3           -1          -11       |
          -2            0           -3           22       |
<<< Matrix Elements

RREF Result:
Matrix Elements >>>
           1            0            0           -8       |
           0            1            0            1       |
           0            0            1           -2       |
<<< Matrix Elements


[D2.2] 2x3 Matrix
Original Matrix:
Matrix Elements >>>
           1            2            3       |
           4            5            6       |
<<< Matrix Elements

RREF Result:
Matrix Elements >>>
           1            0           -1       |
           0            1            2       |
<<< Matrix Elements


[D2.3] Already Reduced Matrix
Original Matrix:
Matrix Elements >>>
           1            0            2       |
           0            1            3       |
<<< Matrix Elements

RREF Result:
Matrix Elements >>>
           1            0            2       |
           0            1            3       |
<<< Matrix Elements


[D2.4] row_reduce_from_gaussian() - Boundary Case - Empty Matrix
[>>> Error ! <<<] Memory allocation failed in alloc_mem()
[Error] row_reduce_from_gaussian: matrix data pointer is null
Empty matrix row_reduce_from_gaussian: Empty matrix or error state (Expected) [PASS]

[D3: Gaussian Inverse Tests]

[D3.1] 2x2 Matrix Inverse
Original matrix (mat1):
Matrix Elements >>>
           4            7       |
           2            6       |
<<< Matrix Elements

Inverse matrix (mat1):
Matrix Elements >>>
         0.6         -0.7       |
        -0.2          0.4       |
<<< Matrix Elements


[D3.2] Identity Matrix Inverse
Original matrix (Identity):
Matrix Elements >>>
           1            0            0       |
           0            1            0       |
           0            0            1       |
<<< Matrix Elements

Inverse matrix (Identity):
Matrix Elements >>>
           1            0            0       |
           0            1            0       |
           0            0            1       |
<<< Matrix Elements


[D3.3] Singular Matrix (Expected: No Inverse)
Original matrix (singular):
Matrix Elements >>>
           1            2            3       |
           4            5            6       |
           7            8            9       |
<<< Matrix Elements

[Error] inverse_gje: matrix is singular (not invertible), left half is not identity matrix at (0, 2): expected=0, actual=-1
Inverse matrix (singular):
Matrix Elements >>>
           0       |
<<< Matrix Elements


[D3.4] 3x3 Matrix Inverse
Original matrix (mat4):
Matrix Elements >>>
           4            7            2       |
           3            5            1       |
           8            6            9       |
<<< Matrix Elements

Inverse matrix (mat4):
Matrix Elements >>>
    -1.85714      2.42857     0.142857       |
    0.904762    -0.952381   -0.0952381       |
     1.04762     -1.52381     0.047619       |
<<< Matrix Elements


[D3.5] Non-square Matrix Inverse (Expected Error)
Original matrix (non-square):
Matrix Elements >>>
           1            2            3       |
           4            5            6       |
<<< Matrix Elements

[Error] inverse_gje: requires square matrix (got 2x3)
Inverse matrix (non-square):
Matrix Elements >>>
           0       |
<<< Matrix Elements


[D4: Dot Product Tests]

[D4.1] Valid Dot Product (Same Length Vectors)
Vector A:
Matrix Elements >>>
           1       |
           2       |
           3       |
<<< Matrix Elements

Vector B:
Matrix Elements >>>
           4       |
           5       |
           6       |
<<< Matrix Elements

Dot product of vectorA and vectorB: 32

[D4.2] Invalid Dot Product (Dimension Mismatch)
Vector A (3x1):
Matrix Elements >>>
           1       |
           2       |
           3       |
<<< Matrix Elements

Vector C (2x1, different size):
Matrix Elements >>>
           1       |
           2       |
<<< Matrix Elements

[Error] dotprod: matrices must have the same size (A: 3x1, B: 2x1)
Dot product (dimension mismatch): 0

[D4.3] Dot Product of Zero Vectors
Zero Vector A:
Matrix Elements >>>
           0       |
           0       |
           0       |
<<< Matrix Elements

Zero Vector B:
Matrix Elements >>>
           0       |
           0       |
           0       |
<<< Matrix Elements

Dot product of zero vectors: 0

[D5: Solve Linear System Tests]

[D5.1] Solving a Simple 2x2 System Ax = b
Matrix A:
Matrix Elements >>>
           2            1       |
           1            3       |
<<< Matrix Elements

Vector b:
Matrix Elements >>>
           5       |
           6       |
<<< Matrix Elements

Solution x:
Matrix Elements >>>
         1.8       |
         1.4       |
<<< Matrix Elements


[D5.2] Solving a 3x3 System Ax = b
Matrix A:
Matrix Elements >>>
           1            2            1       |
           2            0            3       |
           3            2            1       |
<<< Matrix Elements

Vector b:
Matrix Elements >>>
           9       |
           8       |
           7       |
<<< Matrix Elements

Solution x:
Matrix Elements >>>
          -1       |
     3.33333       |
     3.33333       |
<<< Matrix Elements


[D5.3] Solving a System Where One Row is All Zeros (Expect Failure or Infinite Solutions)
Matrix A (has zero row):
Matrix Elements >>>
           1            2            3       |
           0            0            0       |
           4            5            6       |
<<< Matrix Elements

Vector b:
Matrix Elements >>>
           9       |
           0       |
          15       |
<<< Matrix Elements

[Error] solve: pivot at (1, 1) is zero or too small (0), matrix is singular or near-singular
Solution x:
Matrix Elements >>>
           0       |
<<< Matrix Elements


[D5.4] Solving a System with Zero Determinant (Singular Matrix)
Matrix A (singular, determinant = 0):
Matrix Elements >>>
           2            4            1       |
           1            2            3       |
           3            6            2       |
<<< Matrix Elements

Vector b:
Matrix Elements >>>
           5       |
           6       |
           7       |
<<< Matrix Elements

[Error] solve: pivot at (1, 1) is zero or too small (0), matrix is singular or near-singular
Solution x:
Matrix Elements >>>
           0       |
<<< Matrix Elements


[D5.5] Solving a System with Linearly Dependent Rows (Expect Failure or Infinite Solutions)
Matrix A (all rows linearly dependent):
Matrix Elements >>>
           1            1            1       |
           2            2            2       |
           3            3            3       |
<<< Matrix Elements

Vector b:
Matrix Elements >>>
           6       |
          12       |
          18       |
<<< Matrix Elements

[Error] solve: pivot at (1, 1) is zero or too small (0), matrix is singular or near-singular
Solution x:
Matrix Elements >>>
           0       |
<<< Matrix Elements


[D5.6] Solving a Larger 4x4 System Ax = b
Matrix A:
Matrix Elements >>>
           4            2            3            1       |
           2            5            1            2       |
           3            1            6            3       |
           1            2            3            4       |
<<< Matrix Elements

Vector b:
Matrix Elements >>>
          10       |
          12       |
          14       |
          16       |
<<< Matrix Elements

Solution x:
Matrix Elements >>>
     1.80645       |
    0.258065       |
   -0.516129       |
     3.80645       |
<<< Matrix Elements


[D5.7] solve() - Boundary Case - Empty Matrix
[>>> Error ! <<<] Memory allocation failed in alloc_mem()
[>>> Error ! <<<] Memory allocation failed in alloc_mem()
[Error] solve: matrix A data pointer is null
Empty system solve: Empty matrix or error state (Expected) [PASS]

[D5.8] solve() - Error Handling - Dimension Mismatch
[Error] solve: dimensions do not match (A: 2x2, b: 3x1, expected b: 2x1)
Dimension mismatch solve: Empty matrix or error state (Expected) [PASS]

[D6: Band Solve Tests]

[D6.1] Simple 3x3 Band Matrix
Matrix A:
Matrix Elements >>>
           2            1            0       |
           1            3            2       |
           0            1            4       |
<<< Matrix Elements

Vector b:
Matrix Elements >>>
           5       |
           6       |
           7       |
<<< Matrix Elements

Solution x:
Matrix Elements >>>
         2.5       |
           0       |
        1.75       |
<<< Matrix Elements


[D6.2] 4x4 Band Matrix
Matrix A:
Matrix Elements >>>
           2            1            0            0       |
           1            3            2            0       |
           0            1            4            2       |
           0            0            1            5       |
<<< Matrix Elements

Vector b:
Matrix Elements >>>
           8       |
           9       |
          10       |
          11       |
<<< Matrix Elements

Solution x:
Matrix Elements >>>
     3.51429       |
    0.971429       |
     1.28571       |
     1.94286       |
<<< Matrix Elements


[D6.3] Incompatible Dimensions (Expect Error)
Matrix A (3x3):
Matrix Elements >>>
           1            2            3       |
           4            5            6       |
           7            8            9       |
<<< Matrix Elements

Vector b (2x1, incompatible):
Matrix Elements >>>
          10       |
          11       |
<<< Matrix Elements

[Error] band_solve: dimensions do not match (A: 3x3, b: 2x1, expected b: 3x1)
Solution x:
Matrix Elements >>>
           0       |
<<< Matrix Elements


[D6.4] Singular Matrix (No Unique Solution)
Matrix A (singular, linearly dependent rows):
Matrix Elements >>>
           1            2            3       |
           2            4            6       |
           3            6            9       |
<<< Matrix Elements

Vector b:
Matrix Elements >>>
          10       |
          20       |
          30       |
<<< Matrix Elements

[Error] band_solve: zero or near-zero pivot detected at (1, 1) = 0, matrix is singular or near-singular
Solution x:
Matrix Elements >>>
           0       |
<<< Matrix Elements


[D6.5] band_solve() - Boundary Case - Empty Matrix
[>>> Error ! <<<] Memory allocation failed in alloc_mem()
[>>> Error ! <<<] Memory allocation failed in alloc_mem()
[Error] band_solve: matrix A data pointer is null
Empty system band_solve: Empty matrix or error state (Expected) [PASS]

[D6.6] band_solve() - Error Handling - Invalid Bandwidth
[Error] band_solve: bandwidth k must be >= 1 (got -1)
band_solve with k=-1: Empty matrix or error state (Expected) [PASS]

[D7: Roots Tests]

[D7.1] Solving a Simple 2x2 System Ax = b
Matrix A:
Matrix Elements >>>
           2            1       |
           1            3       |
<<< Matrix Elements

Vector b:
Matrix Elements >>>
           5       |
           6       |
<<< Matrix Elements

Solution x:
Matrix Elements >>>
         1.8       |
         1.4       |
<<< Matrix Elements


[D7.2] Solving a 3x3 System Ax = b
Matrix A:
Matrix Elements >>>
           1            2            1       |
           2            0            3       |
           3            2            1       |
<<< Matrix Elements

Vector b:
Matrix Elements >>>
           9       |
           8       |
           7       |
<<< Matrix Elements

Solution x:
Matrix Elements >>>
          -1       |
     3.33333       |
     3.33333       |
<<< Matrix Elements


[D7.3] Singular Matrix (No Unique Solution)
Matrix A (singular, linearly dependent rows):
Matrix Elements >>>
           1            2       |
           2            4       |
<<< Matrix Elements

Vector b:
Matrix Elements >>>
           5       |
           6       |
<<< Matrix Elements

[Error] roots: pivot is zero or too small at (1, 1) = 0, system may have no solution
Solution x:
Matrix Elements >>>
           0       |
<<< Matrix Elements


[D7.4] Incompatible Dimensions (Expect Error)
Matrix A (3x3):
Matrix Elements >>>
           1            2            3       |
           4            5            6       |
           7            8            9       |
<<< Matrix Elements

Vector b (2x1, incompatible):
Matrix Elements >>>
          10       |
          11       |
<<< Matrix Elements

[Error] roots: dimensions do not match (A: 3x3, y: 2x1, expected y: 3x1)
Dimension mismatch roots: Empty matrix or error state (Expected) [PASS]

[D7.5] roots() - Boundary Case - Empty Matrix
[>>> Error ! <<<] Memory allocation failed in alloc_mem()
[>>> Error ! <<<] Memory allocation failed in alloc_mem()
[Error] roots: matrix A data pointer is null
Empty system roots: Empty matrix or error state (Expected) [PASS]

Phase 5: Advanced Linear Algebra (E1+2)

[Test Organization: Application-Oriented Logic]
  Foundation  Basic Ops  Properties  Linear Systems  Decompositions  Applications  Quality


[E1: Matrix Decomposition Tests]

[E1.1] is_positive_definite() - Basic Functionality

[E1.11] Positive Definite 3x3 Matrix
Matrix:
Matrix Elements >>>
           4            1            0       |
           1            3            0       |
           0            0            2       |
<<< Matrix Elements

Is positive definite: True (Expected: True) [PASS]

[E1.12] Non-Positive Definite Matrix
Matrix:
Matrix Elements >>>
           1            2       |
           2            1       |
<<< Matrix Elements

Is positive definite: False (Expected: False) [PASS]

[E1.13] max_minors_to_check Parameter Testing
max_minors_to_check = -1 (check all): True (Expected: True) [PASS]
max_minors_to_check = 3 (check first 3): True (Expected: True) [PASS]
[Error] is_positive_definite: max_minors_to_check must be > 0 or -1 (got 0)
max_minors_to_check = 0 (invalid): False (Expected: False) [PASS]

[E1.14] Parameter Validation - Negative Tolerance
[Error] is_positive_definite: tolerance must be non-negative (got -1e-06)
tolerance = -1e-6 (invalid): False (Expected: False) [PASS]

[E1.15] Boundary Case - Empty Matrix (0x0)
[>>> Error ! <<<] Memory allocation failed in alloc_mem()
[Error] is_positive_definite: matrix data pointer is null
Empty matrix (0x0): False (Expected: False, empty matrix is invalid) [PASS]

[E1.16] Boundary Case - Invalid Dimensions
Non-square matrix (2x3): False (Expected: False) [PASS]

[E1.2] LU Decomposition

[E1.21] 3x3 Matrix - LU Decomposition with Pivoting
Matrix A:
Matrix Elements >>>
           2            1            1       |
           4            3            3       |
           2            1            2       |
<<< Matrix Elements


[Results]
Status: OK
L matrix (lower triangular):
Matrix Elements >>>
           1            0            0       |
         0.5            1            0       |
         0.5            1            1       |
<<< Matrix Elements

U matrix (upper triangular):
Matrix Elements >>>
           4            3            3       |
           0         -0.5         -0.5       |
           0            0            1       |
<<< Matrix Elements

P matrix (permutation):
Matrix Elements >>>
           0            1            0       |
           1            0            0       |
           0            0            1       |
<<< Matrix Elements


[Verification] P * A should equal L * U
Total difference: 0 [PASS]

[E1.22] Solve Linear System using LU Decomposition
System: A * x = b
A:
Matrix Elements >>>
           2            1            1       |
           4            3            3       |
           2            1            2       |
<<< Matrix Elements

b:
Matrix Elements >>>
           1       |
           2       |
           3       |
<<< Matrix Elements


[Results]
Solution x:
Matrix Elements >>>
         0.5       |
          -2       |
           2       |
<<< Matrix Elements

Verification error: 0 [PASS]

[E1.26] solve_lu() - Boundary Case - Empty Matrix
[>>> Error ! <<<] Memory allocation failed in alloc_mem()
[>>> Error ! <<<] Memory allocation failed in alloc_mem()
[Error] lu_decompose: matrix data pointer is null
[Error] solve_lu: invalid LU decomposition (status: 458759)
Empty system: x rows = 1 (Expected: 0 or error state) [PASS]

[E1.27] solve_lu() - Invalid LU Decomposition
[Error] solve_lu: invalid LU decomposition (status: 258)
Invalid LU decomposition: x rows = 1 (Expected: 0 or error state) [PASS]

[E1.23] Boundary Case - Empty Matrix (0x0)
[>>> Error ! <<<] Memory allocation failed in alloc_mem()
[Error] lu_decompose: matrix data pointer is null
Empty matrix: Status = Error, L rows = 1 (Expected: Error status, L is 0x0 or error state) [PASS]

[E1.24] LU Decomposition without Pivoting
Status: OK
Pivoted: No (Expected) [PASS]
Verification (A = L * U): difference = 0 [PASS]

[E1.25] lu_decompose() - Error Handling - Non-Square Matrix
[Error] lu_decompose: requires square matrix (got 2x3)
Non-square matrix (2x3): Status = Error (Expected) [PASS]

[E1.3] Cholesky Decomposition

[E1.31] SPD Matrix - Cholesky Decomposition
Matrix A (SPD):
Matrix Elements >>>
           4            2            0       |
           2            5            1       |
           0            1            3       |
<<< Matrix Elements


[Results]
Status: OK
L matrix (lower triangular):
Matrix Elements >>>
           2            0            0       |
           1            2            0       |
           0          0.5      1.65831       |
<<< Matrix Elements


[Verification] L * L^T should equal A
Total difference: 2.38419e-07 [PASS]

[E1.32] Solve Linear System using Cholesky Decomposition
Solution x:
Matrix Elements >>>
    0.272727       |
    0.454545       |
    0.181818       |
<<< Matrix Elements

Verification error: 0 [PASS]

[E1.35] solve_cholesky() - Boundary Case - Empty Matrix
[>>> Error ! <<<] Memory allocation failed in alloc_mem()
[>>> Error ! <<<] Memory allocation failed in alloc_mem()
[Error] cholesky_decompose: matrix data pointer is null
[Error] solve_cholesky: invalid Cholesky decomposition (status: 458759)
Empty system: x rows = 1 (Expected: 0 or error state) [PASS]

[E1.36] solve_cholesky() - Invalid Cholesky Decomposition
[Error] solve_cholesky: invalid Cholesky decomposition (status: 258)
Invalid Cholesky decomposition: x rows = 1 (Expected: 0 or error state) [PASS]

[E1.33] Boundary Case - Empty Matrix (0x0)
[>>> Error ! <<<] Memory allocation failed in alloc_mem()
[Error] cholesky_decompose: matrix data pointer is null
Empty matrix: Status = Error, L rows = 1 (Expected: Error status, L is 0x0 or error state) [PASS]

[E1.34] Non-Symmetric Matrix (Should Fail)
[Error] cholesky_decompose: requires symmetric matrix
Non-symmetric matrix: Status = Error (Expected) [PASS]

[E1.37] solve_cholesky() - Error Handling - Dimension Mismatch
[Error] solve_cholesky: dimension mismatch - b must be 3x1 vector (got 4x1)
Dimension mismatch solve_cholesky: Empty matrix or error state (Expected) [PASS]

[E1.4] QR Decomposition

[E1.41] General 3x3 Matrix - QR Decomposition
Matrix A:
Matrix Elements >>>
           1            2            3       |
           4            5            6       |
           7            8            9       |
<<< Matrix Elements


[Results]
Status: OK
Q matrix (orthogonal):
Matrix Elements >>>
    0.123091     0.904534     0.408248       |
    0.492366     0.301511    -0.816497       |
     0.86164    -0.301511     0.408248       |
<<< Matrix Elements

R matrix (upper triangular):
Matrix Elements >>>
     8.12404      9.60114      11.0782       |
           0     0.904534      1.80907       |
           0            0            0       |
<<< Matrix Elements


[Verification] Q * R should equal A
Total difference: 1.66893e-06 [PASS]
Q orthogonality error: 2.83733e-07 [PASS]

[E1.42] Least Squares Solution using QR Decomposition
Overdetermined system: A * x  b
A:
Matrix Elements >>>
           1            1       |
           1            2       |
           1            3       |
<<< Matrix Elements

b:
Matrix Elements >>>
           2       |
           3       |
           4       |
<<< Matrix Elements


[Results]
Least squares solution x:
Matrix Elements >>>
           1       |
           1       |
<<< Matrix Elements

Residual norm ||A*x - b||: 4.12953e-07

[E1.46] solve_qr() - Boundary Case - Empty Matrix
[>>> Error ! <<<] Memory allocation failed in alloc_mem()
[>>> Error ! <<<] Memory allocation failed in alloc_mem()
[Error] qr_decompose: matrix data pointer is null
[Error] solve_qr: invalid QR decomposition (status: 458759)
Empty system: x rows = 1 (Expected: 0 or error state) [PASS]

[E1.47] solve_qr() - Invalid QR Decomposition
[Error] solve_qr: invalid QR decomposition (status: 258)
Invalid QR decomposition: x rows = 1 (Expected: 0 or error state) [PASS]

[E1.43] Boundary Case - Empty Matrix (0x0)
[>>> Error ! <<<] Memory allocation failed in alloc_mem()
[Error] qr_decompose: matrix data pointer is null
Empty matrix: Status = Error, Q rows = 1 (Expected: Error status, Q is 0x0 or error state) [PASS]

[E1.44] Boundary Case - Zero Rows or Columns
[>>> Error ! <<<] Memory allocation failed in alloc_mem()
[>>> Error ! <<<] Memory allocation failed in alloc_mem()
[Error] qr_decompose: matrix data pointer is null
Matrix with 0 rows (0x3): Status = Error [PASS]
[Error] qr_decompose: matrix data pointer is null
Matrix with 0 cols (3x0): Status = Error [PASS]

[E1.45] solve_qr() - Error Handling - Dimension Mismatch
[Error] solve_qr: dimension mismatch - b must be 3x1 vector (got 4x1)
Dimension mismatch solve_qr: Empty matrix or error state (Expected) [PASS]

[E1.5] Singular Value Decomposition (SVD)

[E1.51] General 3x3 Matrix - SVD Decomposition
Matrix A:
Matrix Elements >>>
           1            2            3       |
           4            5            6       |
           7            8            9       |
<<< Matrix Elements


[Results]
Status: OK
Singular values:
Matrix Elements >>>
     1.06837       |
     16.8481       |
           0       |
<<< Matrix Elements

Numerical rank: 2
Iterations: 7
Reconstruction error: 1.68085e-05 [PASS]

[E1.52] Pseudo-inverse using SVD
Matrix A (3x2):
Matrix Elements >>>
           1            2       |
           3            4       |
           5            6       |
<<< Matrix Elements


[Results]
Pseudo-inverse A^+ (2x3):
Matrix Elements >>>
    -1.33333    -0.333333     0.666666       |
     1.08333     0.333333    -0.416666       |
<<< Matrix Elements

Verification error (A * A^+ * A  A): 5.72205e-06 [PASS]

[E1.57] pseudo_inverse() - Parameter Validation - tolerance < 0
[Error] pseudo_inverse: tolerance must be >= 0 (got -1e-06)
tolerance = -1e-6: A_plus rows = 1 (Expected: 0 or error state) [PASS]

[E1.58] pseudo_inverse() - Invalid SVD Decomposition
[Error] pseudo_inverse: invalid SVD decomposition (status: 258)
Invalid SVD decomposition: A_plus rows = 1 (Expected: 0 or error state) [PASS]

[E1.53] Parameter Validation - max_iter <= 0
[Error] svd_decompose: max_iter must be > 0 (got 0)
max_iter = 0: Status = Error (Expected) [PASS]
[Error] svd_decompose: max_iter must be > 0 (got -1)
max_iter = -1: Status = Error (Expected) [PASS]

[E1.54] Parameter Validation - tolerance < 0
[Error] svd_decompose: tolerance must be >= 0 (got -1e-06)
tolerance = -1e-6: Status = Error (Expected) [PASS]

[E1.55] Boundary Case - Empty Matrix (m=0 or n=0)
[>>> Error ! <<<] Memory allocation failed in alloc_mem()
[>>> Error ! <<<] Memory allocation failed in alloc_mem()
[Error] svd_decompose: matrix data pointer is null
Matrix with 0 rows (0x3): Status = Error [PASS]
[Error] svd_decompose: matrix data pointer is null
Matrix with 0 cols (3x0): Status = Error [PASS]

[E1.56] pseudo_inverse() - Error Handling - Invalid SVD Decomposition
[Error] pseudo_inverse: invalid SVD decomposition (status: 258)
Invalid SVD decomposition: A_plus rows = 1 (Expected: 0 or error state) [PASS]

[E1.6] Matrix Decomposition Performance Tests

[E1.61] LU Decomposition Performance
[Performance] LU Decomposition (4x4 matrix): 142.00 us

[E1.62] Cholesky Decomposition Performance
[Performance] Cholesky Decomposition (4x4 SPD matrix): 90.00 us

[E1.63] QR Decomposition Performance
[Performance] QR Decomposition (4x4 matrix): 188.00 us

[E1.64] SVD Decomposition Performance
[Performance] SVD Decomposition (4x4 matrix): 373.00 us

[Matrix Decomposition Tests Complete]

[E2: Gram-Schmidt Orthogonalization Tests]

[E2.1] Basic Orthogonalization - Linearly Independent Vectors
Input vectors (each column is a vector):
Matrix Elements >>>
        1.00         1.00         0.00       |
        0.00         1.00         1.00       |
        1.00         0.00         1.00       |
<<< Matrix Elements


[Results]
Status: OK
Orthogonalized vectors Q (each column is orthogonal):
Matrix Elements >>>
        0.71         0.41        -0.58       |
        0.00         0.82         0.58       |
        0.71        -0.41         0.58       |
<<< Matrix Elements

Coefficients R (upper triangular):
Matrix Elements >>>
        1.41         0.71         0.71       |
        0.00         1.22         0.41       |
        0.00         0.00         1.15       |
<<< Matrix Elements


[Verification] Q^T * Q should be identity
Orthogonality error: 0.00 [PASS]

[Verification] Each column of Q should be normalized
  Column 0 norm: 1.00 (error: 0.00) [PASS]
  Column 1 norm: 1.00 (error: 0.00) [PASS]
  Column 2 norm: 1.00 (error: 0.00) [PASS]

[Verification] Q * R should reconstruct original vectors
Reconstruction error: 0.00 [PASS]

[E2.2] Orthogonalization - Near-Linear-Dependent Vectors
Input vectors (third vector is nearly linear dependent):
Matrix Elements >>>
        1.00         0.00         1.00       |
        0.00         1.00         1.00       |
        0.00         0.00         0.00       |
<<< Matrix Elements


[Results]
Status: OK
Orthogonalized vectors Q:
Matrix Elements >>>
        1.00         0.00         0.00       |
        0.00         1.00         0.00       |
        0.00         0.00         1.00       |
<<< Matrix Elements

Coefficients R:
Matrix Elements >>>
        1.00         0.00         1.00       |
        0.00         1.00         1.00       |
        0.00         0.00         0.00       |
<<< Matrix Elements


[Note] Third column norm: 1.00 (should be 0 if linearly dependent, or 1 if orthogonalized)

[E2.3] Orthogonalization - 2D Vectors (2x2)
Input vectors:
Matrix Elements >>>
        3.00         1.00       |
        1.00         2.00       |
<<< Matrix Elements


[Results]
Status: OK
Orthogonalized vectors Q:
Matrix Elements >>>
        0.95        -0.32       |
        0.32         0.95       |
<<< Matrix Elements

Coefficients R:
Matrix Elements >>>
        3.16         1.58       |
        0.00         1.58       |
<<< Matrix Elements


[Verification] Dot product of Q columns: 0.00 (should be ~0 for orthogonal) [PASS]

[E2.4] Error Handling - Invalid Input
[>>> Error ! <<<] Memory allocation failed in alloc_mem()
[Error] gram_schmidt_orthogonalize: Input matrix is null.
Empty matrix test: PASS (correctly rejected)

[E2.5] gram_schmidt_orthogonalize() - Parameter Validation - Negative Tolerance
[Error] gram_schmidt_orthogonalize: tolerance must be non-negative (got -1e-06)
tolerance = -1e-6: PASS (correctly rejected)

[E2.6] gram_schmidt_orthogonalize() - Boundary Case - Zero Rows
[>>> Error ! <<<] Memory allocation failed in alloc_mem()
[Error] gram_schmidt_orthogonalize: Input matrix is null.
Zero rows (0x2): PASS (correctly rejected)

[E2.7] gram_schmidt_orthogonalize() - Boundary Case - Zero Columns
[>>> Error ! <<<] Memory allocation failed in alloc_mem()
[Error] gram_schmidt_orthogonalize: Input matrix is null.
Zero columns (2x0): PASS (correctly rejected)

Phase 6: System Identification Applications (E3)

[Test Organization: Application-Oriented Logic]
  Foundation  Basic Ops  Properties  Linear Systems  Decompositions  Applications  Quality


[E3: Eigenvalue Decomposition Tests]

[E3.1] is_symmetric() - Basic Functionality
[E3.11] Symmetric 3x3 Matrix
Matrix:
Matrix Elements >>>
           4            1            2       |
           1            3            0       |
           2            0            5       |
<<< Matrix Elements

Is symmetric: True (Expected: True)

[E3.12] Non-Symmetric 3x3 Matrix
Matrix:
Matrix Elements >>>
           1            2            3       |
           4            5            6       |
           7            8            9       |
<<< Matrix Elements

Is symmetric: False (Expected: False)

[E3.13] Non-Square Matrix (2x3)
Is symmetric: False (Expected: False)

[E3.14] Symmetric Matrix with Small Numerical Errors
Matrix with error 1e-05:
Matrix Elements >>>
           1      2.00001       |
           2            3       |
<<< Matrix Elements

Difference: |A(0,1) - A(1,0)| = 1.001358e-05 (Expected: 0.000010)
A(0,1) stored value: 2.00001001 (Expected: 2.00001001)
Is symmetric (tolerance=1e-4): True (Expected: True, tolerance > error) [PASS]
Is symmetric (tolerance=1e-6): False (Expected: False, tolerance < error) [PASS]
Difference accuracy: |actual_diff - expected_diff| = 1.36e-08 [PASS - difference stored correctly]

[E3.15] Parameter Validation - Negative Tolerance
[Error] is_symmetric: tolerance must be >= 0 (got -1e-06)
tolerance = -1e-6 (invalid): False (Expected: False) [PASS]

[E3.16] Boundary Case - Empty Matrix (0x0)
[>>> Error ! <<<] Memory allocation failed in alloc_mem()
[Error] is_symmetric: matrix data pointer is null
Empty matrix (0x0): False (Expected: False, empty matrix is invalid) [PASS]

[E3.2] power_iteration() - Dominant Eigenvalue

[E3.21] Simple 2x2 Matrix
Matrix:
Matrix Elements >>>
        2.00         1.00       |
        1.00         2.00       |
<<< Matrix Elements


[Expected Results]
  Expected eigenvalues: 3.0 (largest), 1.0 (smallest)
  Expected dominant eigenvector (for λ=3): approximately [0.707, 0.707] or [-0.707, -0.707] (normalized)
  Expected dominant eigenvector (for λ=1): approximately [0.707, -0.707] or [-0.707, 0.707] (normalized)

[Actual Results]
  Dominant eigenvalue: 3.00 (Expected: 3.0, largest eigenvalue)
  Iterations: 2
  Status: OK
  Dominant eigenvector:
Matrix Elements >>>
        0.71       |
        0.71       |
<<< Matrix Elements

  Error from expected (3.0): 0.00 [PASS]

[E3.22] 3x3 Stiffness Matrix (SHM Application)
Stiffness Matrix:
Matrix Elements >>>
        2.00        -1.00         0.00       |
       -1.00         2.00        -1.00       |
        0.00        -1.00         2.00       |
<<< Matrix Elements


[Expected Results]
  Expected eigenvalues (approximate): 3.414 (largest), 2.000, 0.586 (smallest)
  Expected primary frequency: sqrt(3.414)  1.848 rad/s

[Actual Results]
  Dominant eigenvalue (primary frequency squared): 3.41
  Primary frequency: 1.85 rad/s (Expected: ~1.848 rad/s)
  Iterations: 8
  Status: OK
  Error from expected (3.41): 0.00 [PASS]

[E3.23] Non-Square Matrix (Expect Error)
[Error] power_iteration: requires square matrix (got 2x3)
Status: Error (Expected)

[E3.25] Parameter Validation - max_iter <= 0
[Error] power_iteration: max_iter must be > 0 (got 0)
max_iter = 0: Status = Error (Expected) [PASS]
[Error] power_iteration: max_iter must be > 0 (got -1)
max_iter = -1: Status = Error (Expected) [PASS]

[E3.26] Parameter Validation - tolerance < 0
[Error] power_iteration: tolerance must be >= 0 (got -1e-06)
tolerance = -1e-6: Status = Error (Expected) [PASS]

[E3.27] Boundary Case - Empty Matrix (0x0)
[>>> Error ! <<<] Memory allocation failed in alloc_mem()
[Error] power_iteration: matrix data pointer is null
Empty matrix: Status = Error, eigenvalue = 0.00 (Expected: Error status) [PASS]

[E3.24] inverse_power_iteration() - Smallest Eigenvalue (System Identification)

[E3.28] Simple 2x2 Matrix - Smallest Eigenvalue
Matrix (same as E3.21):
Matrix Elements >>>
        2.00         1.00       |
        1.00         2.00       |
<<< Matrix Elements


[Expected Results]
  Expected eigenvalues: 3.0 (largest), 1.0 (smallest)
  Expected smallest eigenvalue: 1.0
  Expected smallest eigenvector (for λ=1): approximately [0.707, -0.707] or [-0.707, 0.707] (normalized)
  Note: This is critical for system identification - smallest eigenvalue = fundamental frequency

[Actual Results]
  Smallest eigenvalue: 1.00 (Expected: 1.0, smallest eigenvalue)
  Iterations: 6
  Status: OK
  Smallest eigenvector:
Matrix Elements >>>
        0.71       |
       -0.71       |
<<< Matrix Elements

  Error from expected (1.0): 0.00 [PASS]

[Comparison] Power vs Inverse Power Iteration:
  Power iteration (λ_max): 3.00
  Inverse power iteration (λ_min): 1.00
  Ratio (λ_max/λ_min): 3.00 (Expected: ~3.0) [PASS]

[E3.29] 3x3 Stiffness Matrix - Smallest Eigenvalue (SHM Application)
Stiffness Matrix (same as E3.22):
Matrix Elements >>>
        2.00        -1.00         0.00       |
       -1.00         2.00        -1.00       |
        0.00        -1.00         2.00       |
<<< Matrix Elements


[Expected Results]
  Expected eigenvalues (approximate): 3.414 (largest), 2.000, 0.586 (smallest)
  Expected smallest eigenvalue: ~0.586 (fundamental frequency squared)
  Expected fundamental frequency: sqrt(0.586)  0.765 rad/s
  Note: Smallest eigenvalue is critical for system identification - represents fundamental mode

[Actual Results]
  Smallest eigenvalue (fundamental frequency squared): 0.59
  Fundamental frequency: 0.77 rad/s (Expected: ~0.765 rad/s)
  Iterations: 8
  Status: OK
  Smallest eigenvector (fundamental mode shape):
Matrix Elements >>>
        0.50       |
        0.71       |
        0.50       |
<<< Matrix Elements

  Error from expected (0.59): 0.00 [PASS]

[Comparison] Power vs Inverse Power Iteration for SHM:
  Power iteration (primary frequency²): 3.41  frequency: 1.85 rad/s
  Inverse power iteration (fundamental frequency²): 0.59  frequency: 0.77 rad/s
  Frequency ratio: 2.41 (Expected: ~2.4, ratio of highest to lowest mode)

[E3.210] Non-Square Matrix (Expect Error)
[Error] inverse_power_iteration: requires square matrix (got 2x3)
Status: Error (Expected)
Error handling: [PASS]

[E3.211] Near-Singular Matrix (Edge Case)
Matrix (near-singular but invertible):
Matrix Elements >>>
        1.00         0.00         0.00       |
        0.00         1.00         0.00       |
        0.00         0.00         1.00       |
<<< Matrix Elements


[Results]
  Status: OK
  Smallest eigenvalue: 1.00
  Iterations: 2
  Note: Successfully handled near-singular matrix [PASS]

[E3.212] Parameter Validation - max_iter <= 0
[Error] inverse_power_iteration: max_iter must be > 0 (got 0)
max_iter = 0: Status = Error (Expected) [PASS]
[Error] inverse_power_iteration: max_iter must be > 0 (got -1)
max_iter = -1: Status = Error (Expected) [PASS]

[E3.213] Parameter Validation - tolerance < 0
[Error] inverse_power_iteration: tolerance must be >= 0 (got -1e-06)
tolerance = -1e-6: Status = Error (Expected) [PASS]

[E3.214] Boundary Case - Empty Matrix (0x0)
[>>> Error ! <<<] Memory allocation failed in alloc_mem()
[Error] inverse_power_iteration: matrix data pointer is null
Empty matrix: Status = Error, eigenvalue = 0.00 (Expected: Error status) [PASS]

[E3.215] Singular Matrix (Should Fail)
[Error] solve: pivot at (1, 1) is zero or too small (0), matrix is singular or near-singular
[Error] solve: pivot at (1, 1) is zero or too small (0), matrix is singular or near-singular
[Error] solve: pivot at (1, 1) is zero or too small (0), matrix is singular or near-singular
Singular matrix: Status = OK (Expected: Error or OK with eigenvalue  0) [FAIL]

[E3.3] eigendecompose_jacobi() - Symmetric Matrix Decomposition

[E3.31] 2x2 Symmetric Matrix - Complete Decomposition
[Expected Results]
  Expected eigenvalues: 3.0, 1.0 (in any order)
  Expected eigenvectors (for λ=3): [0.707, 0.707] or [-0.707, -0.707] (normalized)
  Expected eigenvectors (for λ=1): [0.707, -0.707] or [-0.707, 0.707] (normalized)

[Actual Results]
Eigenvalues:
Matrix Elements >>>
        1.00       |
        3.00       |
<<< Matrix Elements

Eigenvectors (each column is an eigenvector):
Matrix Elements >>>
        0.71         0.71       |
       -0.71         0.71       |
<<< Matrix Elements

Iterations: 2
Status: OK
Eigenvalue check (should be 3.0 and 1.0): [PASS]

[Verification] Check A * v = lambda * v for first eigenvector:
A * v:
Matrix Elements >>>
        0.71       |
       -0.71       |
<<< Matrix Elements

lambda * v:
Matrix Elements >>>
        0.71       |
       -0.71       |
<<< Matrix Elements

Verification (A*v = λ*v): [PASS]

[E3.32] 3x3 Stiffness Matrix (SHM Application)
[Expected Results]
  Expected eigenvalues (approximate): 3.414, 2.000, 0.586
  Expected natural frequencies: 1.848, 1.414, 0.765 rad/s
  Note: Eigenvalues may appear in any order

[Actual Results]
Eigenvalues (natural frequencies squared):
Matrix Elements >>>
        3.41       |
        0.59       |
        2.00       |
<<< Matrix Elements

Natural frequencies (rad/s):
  Mode 0: 1.85 rad/s (Expected: ~1.85 rad/s) [PASS]
  Mode 1: 0.77 rad/s (Expected: ~0.76 rad/s) [PASS]
  Mode 2: 1.41 rad/s (Expected: ~1.41 rad/s) [PASS]
Eigenvectors (mode shapes):
Matrix Elements >>>
        0.50         0.50        -0.71       |
       -0.71         0.71         0.00       |
        0.50         0.50         0.71       |
<<< Matrix Elements

Iterations: 9
Status: OK

[E3.33] Diagonal Matrix (Eigenvalues on diagonal)
Matrix:
Matrix Elements >>>
        5.00         0.00         0.00       |
        0.00         3.00         0.00       |
        0.00         0.00         1.00       |
<<< Matrix Elements


[Expected Results]
  Expected eigenvalues: 5.0, 3.0, 1.0 (diagonal elements, may be in any order)
  Expected eigenvectors: standard basis vectors [1,0,0], [0,1,0], [0,0,1] (or their negatives)
  Expected iterations: 1 (diagonal matrix should converge immediately)

[Actual Results]
Eigenvalues:
Matrix Elements >>>
        5.00       |
        3.00       |
        1.00       |
<<< Matrix Elements

Eigenvectors:
Matrix Elements >>>
        1.00         0.00         0.00       |
        0.00         1.00         0.00       |
        0.00         0.00         1.00       |
<<< Matrix Elements

Iterations: 1 (Expected: 1)
Eigenvalue check (should be 5.0, 3.0, 1.0): [PASS]

[E3.34] Parameter Validation - tolerance < 0
[Error] eigendecompose_jacobi: tolerance must be >= 0 (got -1e-06)
tolerance = -1e-6: Status = Error (Expected) [PASS]

[E3.35] Parameter Validation - max_iter <= 0
[Error] eigendecompose_jacobi: max_iter must be > 0 (got 0)
max_iter = 0: Status = Error (Expected) [PASS]
[Error] eigendecompose_jacobi: max_iter must be > 0 (got -1)
max_iter = -1: Status = Error (Expected) [PASS]

[E3.36] Boundary Case - Empty Matrix (0x0)
[>>> Error ! <<<] Memory allocation failed in alloc_mem()
[Error] eigendecompose_jacobi: matrix data pointer is null
Empty matrix: Status = Error, eigenvalues rows = 1 (Expected: Error status, eigenvalues is 0x0 or error state) [PASS]

[E3.4] eigendecompose_qr() - General Matrix Decomposition

[E3.41] General 2x2 Matrix
Matrix:
Matrix Elements >>>
        1.00         2.00       |
        3.00         4.00       |
<<< Matrix Elements


[Expected Results]
  Expected eigenvalues: (5+33)/2  5.372, (5-33)/2  -0.372
  Note: This is a non-symmetric matrix, eigenvalues are real but may have complex eigenvectors

[Actual Results]
Eigenvalues:
Matrix Elements >>>
        5.37       |
       -0.37       |
<<< Matrix Elements

Eigenvectors:
Matrix Elements >>>
        0.42         0.91       |
        0.91        -0.42       |
<<< Matrix Elements

Iterations: 6
Status: OK
Eigenvalue 1: 5.37 (Expected: 5.37, Error: 0.00, Rel Error: 0.01%) [PASS]
Eigenvalue 2: -0.37 (Expected: -0.37, Error: 0.00, Rel Error: 0.07%) [PASS]
Overall eigenvalue check: [PASS]

[E3.42] Non-Symmetric 3x3 Matrix
Matrix [1,2,3; 4,5,6; 7,8,9]:
Matrix Elements >>>
        1.00         2.00         3.00       |
        4.00         5.00         6.00       |
        7.00         8.00         9.00       |
<<< Matrix Elements


[Expected Results]
  Expected eigenvalues (theoretical): 16.12, -1.12, 0.00
  Note: This matrix is rank-deficient (determinant = 0), so one eigenvalue is 0
  Note: QR algorithm may have numerical errors, especially for non-symmetric matrices
  Acceptable range: largest eigenvalue ~15-18, smallest eigenvalue near 0

[Actual Results]
Eigenvalues:
Matrix Elements >>>
       16.12       |
       -1.12       |
        0.00       |
<<< Matrix Elements

Eigenvectors:
Matrix Elements >>>
        0.23         0.88         0.41       |
        0.53         0.24        -0.82       |
        0.82        -0.40         0.41       |
<<< Matrix Elements

Iterations: 6
Status: OK
Eigenvalue 0: 16.12 (Expected: 16.12, Error: 0.00, Rel Error: 0.02%) [PASS]
Eigenvalue 1: -1.12 (Expected: -1.12, Error: 0.00, Rel Error: 0.28%) [PASS]
Eigenvalue 2: 0.00 (Expected: 0.00, Error: 0.00, Rel Error: 0.00%) [PASS]
Overall eigenvalue check: [PASS]

[E3.43] Parameter Validation - max_iter <= 0
[Error] eigendecompose_qr: max_iter must be > 0 (got 0)
max_iter = 0: Status = Error (Expected) [PASS]
[Error] eigendecompose_qr: max_iter must be > 0 (got -1)
max_iter = -1: Status = Error (Expected) [PASS]

[E3.44] Parameter Validation - tolerance < 0
[Error] eigendecompose_qr: tolerance must be >= 0 (got -1e-06)
tolerance = -1e-6: Status = Error (Expected) [PASS]

[E3.45] Boundary Case - Empty Matrix (0x0)
[>>> Error ! <<<] Memory allocation failed in alloc_mem()
[Error] eigendecompose_qr: matrix data pointer is null
Empty matrix: Status = Error, eigenvalues rows = 1 (Expected: Error status, eigenvalues is 0x0 or error state) [PASS]

[E3.5] eigendecompose() - Automatic Method Selection

[E3.51] Symmetric Matrix (Auto-select: Jacobi)
Matrix:
Matrix Elements >>>
        4.00         1.00         2.00       |
        1.00         3.00         0.00       |
        2.00         0.00         5.00       |
<<< Matrix Elements


[Expected Results]
  Method: Should automatically use Jacobi (symmetric matrix detected)
  Expected eigenvalues (approximate): 6.67, 3.48, 1.85
  Note: Eigenvalues may appear in any order

[Actual Results]
Eigenvalues:
Matrix Elements >>>
        1.85       |
        3.48       |
        6.67       |
<<< Matrix Elements

Iterations: 8
Status: OK
Method used: Jacobi (auto-selected for symmetric matrix)

[E3.52] Non-Symmetric Matrix (Auto-select: QR)
[Expected Results]
  Method: Should automatically use QR (non-symmetric matrix detected)
  Expected eigenvalues (theoretical): 16.12, -1.12, 0.00
  Note: One eigenvalue should be near 0 (rank-deficient matrix)
  Note: QR algorithm may have numerical errors for non-symmetric matrices
  Acceptable: largest ~15-18, smallest near 0, one near -1 to -3

[Actual Results]
Eigenvalues:
Matrix Elements >>>
       16.12       |
       -1.12       |
        0.00       |
<<< Matrix Elements

Iterations: 6
Status: OK
Method used: QR (auto-selected for non-symmetric matrix)
Eigenvalue 0: 16.12 (Expected: 16.12, Error: 0.00, Rel Error: 0.02%) [PASS]
Eigenvalue 1: -1.12 (Expected: -1.12, Error: 0.00, Rel Error: 0.28%) [PASS]
Eigenvalue 2: 0.00 (Expected: 0.00, Error: 0.00, Rel Error: 0.00%) [PASS]
Overall eigenvalue check: [PASS]

[E3.53] Parameter Validation - tolerance < 0
[Error] eigendecompose: tolerance must be >= 0 (got -1e-06)
tolerance = -1e-6: Status = Error (Expected) [PASS]

[E3.54] eigendecompose() - Boundary Case - Empty Matrix (0x0)
[>>> Error ! <<<] Memory allocation failed in alloc_mem()
[Error] eigendecompose: matrix data pointer is null
Empty matrix: Status = Error, eigenvalues rows = 1 (Expected: Error status, eigenvalues is 0x0 or error state) [PASS]

[E3.55] eigendecompose() - Error Handling - Non-Square Matrix
[Error] eigendecompose_qr: requires square matrix (got 2x3)
Non-square matrix (2x3): Status = Error (Expected) [PASS]

[E3.6] SHM Application - Structural Dynamics Analysis

[E3.61] 4-DOF Mass-Spring System
Stiffness Matrix K:
Matrix Elements >>>
        2.00        -1.00         0.00         0.00       |
       -1.00         2.00        -1.00         0.00       |
        0.00        -1.00         2.00        -1.00       |
        0.00         0.00        -1.00         1.00       |
<<< Matrix Elements

Is symmetric: Yes

[Quick Analysis] Primary frequency using power_iteration():
[Expected Results]
  Expected primary eigenvalue: ~3.53 (largest eigenvalue)
  Expected primary frequency: sqrt(3.53)  1.88 rad/s

[Actual Results]
  Primary eigenvalue: 3.53 (Expected: ~3.53)
  Primary frequency: 1.88 rad/s (Expected: ~1.88 rad/s)
  Iterations: 13
  Error from expected: 0.00 [PASS]

[Complete Analysis] Full modal analysis using eigendecompose_jacobi():
[Expected Results]
  Expected eigenvalues (approximate): 3.53, 2.35, 1.00, 0.12
  Expected natural frequencies: 1.88, 1.53, 1.00, 0.35 rad/s
  Note: These are approximate values for the 4-DOF system

[Actual Results]
All eigenvalues (natural frequencies squared):
Matrix Elements >>>
        3.53       |
        1.00       |
        2.35       |
        0.12       |
<<< Matrix Elements

Natural frequencies (rad/s):
  Mode 0: 1.88 rad/s (Expected: ~1.88 rad/s) [PASS]
  Mode 1: 1.00 rad/s (Expected: ~1.00 rad/s) [PASS]
  Mode 2: 1.53 rad/s (Expected: ~1.53 rad/s) [PASS]
  Mode 3: 0.35 rad/s (Expected: ~0.35 rad/s) [PASS]
Mode shapes (eigenvectors):
Matrix Elements >>>
        0.43         0.58        -0.66         0.23       |
       -0.66         0.58         0.23         0.43       |
        0.58        -0.00         0.58         0.58       |
       -0.23        -0.58        -0.43         0.66       |
<<< Matrix Elements

Total iterations: 17

[E3.7] Edge Cases and Error Handling

[E3.71] 1x1 Matrix
Matrix: [5.0]
[Expected Results]
  Expected eigenvalue: 5.0 (the matrix element itself)
  Expected eigenvector: [1.0] (normalized)

[Actual Results]
Eigenvalue: 5.00 (Expected: 5.0)
Eigenvector:
Matrix Elements >>>
        1.00       |
<<< Matrix Elements

Error from expected: 0.00 [PASS]

[E3.72] Zero Matrix
[Error] power_iteration: computed vector norm too small
Status: Error (Expected)

[E3.73] Identity Matrix
Matrix (3x3 Identity):
Matrix Elements >>>
        1.00         0.00         0.00       |
        0.00         1.00         0.00       |
        0.00         0.00         1.00       |
<<< Matrix Elements


[Expected Results]
  Expected eigenvalues: 1.0, 1.0, 1.0 (all eigenvalues are 1)
  Expected eigenvectors: Any orthonormal basis (e.g., standard basis vectors)
  Expected iterations: 1 (should converge immediately)

[Actual Results]
Eigenvalues (should all be 1.0):
Matrix Elements >>>
        1.00       |
        1.00       |
        1.00       |
<<< Matrix Elements

Eigenvectors:
Matrix Elements >>>
        1.00         0.00         0.00       |
        0.00         1.00         0.00       |
        0.00         0.00         1.00       |
<<< Matrix Elements

Iterations: 1 (Expected: 1)
All eigenvalues = 1.0: [PASS]

[E3.8] Performance Test for SHM Applications

[E3.81] Power Iteration Performance (Real-time SHM - Dominant Eigenvalue)
[Performance] Power Iteration (3x3 matrix): 112.00 us

[E3.82] Inverse Power Iteration Performance (System Identification - Smallest Eigenvalue)
[Performance] Inverse Power Iteration (3x3 matrix): 543.00 us

[E3.83] Jacobi Method Performance (Complete Eigendecomposition - Symmetric Matrices)
[Performance] Jacobi Decomposition (3x3 symmetric matrix): 166.00 us

[E3.84] QR Method Performance (Complete Eigendecomposition - General Matrices)
[Performance] QR Decomposition (3x3 general matrix): 818.00 us

[Eigenvalue Decomposition Tests Complete]

Phase 7: Auxiliary Functions (F)

[Test Organization: Application-Oriented Logic]
  Foundation  Basic Ops  Properties  Linear Systems  Decompositions  Applications  Quality


[F1: Stream Operators Tests]

[F1.1] Stream Insertion Operator (<<) for Mat
Matrix mat1:
1 2 3
4 5 6
7 8 9


[F1.2] Stream Insertion Operator (<<) for Mat::ROI
ROI created: ROI(pos_x=1, pos_y=2, width=3, height=4)
Expected output:
  row start: 2 (pos_y)
  col start: 1 (pos_x)
  row count: 4 (height)
  col count: 3 (width)

Actual output:
row start 2
col start 1
row count 4
col count 3


[F1.3] Stream Extraction Operator (>>) for Mat
Simulated input: "10 20 30 40"
Matrix mat2 after input:
10 20
30 40

Expected: [10, 20; 30, 40]

[F1.4] Stream Extraction Operator (>>) for Mat (2x3 matrix)
Simulated input: "1.5 2.5 3.5 4.5 5.5 6.5"
Matrix mat3 after input:
1.5 2.5 3.5
4.5 5.5 6.5

Expected: [1.5, 2.5, 3.5; 4.5, 5.5, 6.5]

[F2: Global Arithmetic Operators Tests]

[F2.1] Matrix Addition (operator+)
Matrix A:
Matrix Elements >>>
           1            2       |
           3            4       |
<<< Matrix Elements

Matrix B:
Matrix Elements >>>
           5            6       |
           7            8       |
<<< Matrix Elements

matA + matB:
6 8
10 12


[F2.2] Matrix Addition with Constant (operator+)
Matrix A:
Matrix Elements >>>
           1            2       |
           3            4       |
<<< Matrix Elements

Constant: 5.0
matA + 5.0f:
6 7
8 9


[F2.3] Matrix Subtraction (operator-)
Matrix A:
Matrix Elements >>>
           1            2       |
           3            4       |
<<< Matrix Elements

Matrix B:
Matrix Elements >>>
           5            6       |
           7            8       |
<<< Matrix Elements

matA - matB:
-4 -4
-4 -4


[F2.4] Matrix Subtraction with Constant (operator-)
Matrix A:
Matrix Elements >>>
           1            2       |
           3            4       |
<<< Matrix Elements

Constant: 2.0
matA - 2.0f:
-1 0
1 2


[F2.5] Matrix Multiplication (operator*)
Matrix C (2x3):
Matrix Elements >>>
           1            2            3       |
           4            5            6       |
<<< Matrix Elements

Matrix D (3x2):
Matrix Elements >>>
           7            8       |
           9           10       |
          11           12       |
<<< Matrix Elements

matC * matD:
58 64
139 154


[F2.6] Matrix Multiplication with Constant (operator*)
Matrix A:
Matrix Elements >>>
           1            2       |
           3            4       |
<<< Matrix Elements

Constant: 2.0
matA * 2.0f:
2 4
6 8


[F2.7] Matrix Division (operator/)
Matrix A:
Matrix Elements >>>
           1            2       |
           3            4       |
<<< Matrix Elements

Constant: 2.0
matA / 2.0f:
0.5 1
1.5 2


[F2.8] Matrix Division Element-wise (operator/)
Matrix A:
Matrix Elements >>>
           1            2       |
           3            4       |
<<< Matrix Elements

Matrix B:
Matrix Elements >>>
           5            6       |
           7            8       |
<<< Matrix Elements

matA / matB:
0.2 0.333333
0.428571 0.5


[F2.9] Matrix Comparison (operator==)
Matrix E:
Matrix Elements >>>
           1            2       |
           3            4       |
<<< Matrix Elements

Matrix F:
Matrix Elements >>>
           1            2       |
           3            4       |
<<< Matrix Elements

matE == matF: True

After modifying matF(0,0) = 5:
Matrix E:
Matrix Elements >>>
           1            2       |
           3            4       |
<<< Matrix Elements

Matrix F:
Matrix Elements >>>
           5            2       |
           3            4       |
<<< Matrix Elements

operator == Error: 0 0, m1.data=1, m2.data=5, diff=4
matE == matF after modification: False

Phase 8: Quality Assurance (G)

[Test Organization: Application-Oriented Logic]
  Foundation  Basic Ops  Properties  Linear Systems  Decompositions  Applications  Quality


[G1: Quality Assurance - Boundary Conditions and Error Handling Tests]

[G1.1] Null Pointer Handling in print_matrix
[Error] Cannot print matrix: data pointer is null.

[G1.2] Null Pointer Handling in operator<<
[Error] Cannot print matrix: data pointer is null.


[G1.3] Invalid Block Parameters
[Error] block: invalid position: start_row=-1, start_col=0 (must be non-negative)
block(-1, 0, 2, 2): Error
[Error] block: block exceeds row boundary: start_row=2, block_rows=2, source.rows=3
block(2, 2, 2, 2) on 3x3 matrix: Error
[Error] block: invalid block size: block_rows=0, block_cols=2 (must be positive)
block(0, 0, 0, 2): Error

[G1.4] Invalid swap_rows Parameters
Before invalid swap_rows:
Matrix Elements >>>
           1            2            3       |
           4            5            6       |
           7            8            9       |
<<< Matrix Elements

[Error] swap_rows: row1 index out of range: row1=-1, matrix.rows=3
After swap_rows(-1, 1):
Matrix Elements >>>
           1            2            3       |
           4            5            6       |
           7            8            9       |
<<< Matrix Elements

[Error] swap_rows: row2 index out of range: row2=5, matrix.rows=3
After swap_rows(0, 5):
Matrix Elements >>>
           1            2            3       |
           4            5            6       |
           7            8            9       |
<<< Matrix Elements


[G1.5] Invalid swap_cols Parameters
Before invalid swap_cols:
Matrix Elements >>>
           1            2            3       |
           4            5            6       |
           7            8            9       |
<<< Matrix Elements

[Error] swap_cols: col1 index out of range: col1=-1, matrix.cols=3
After swap_cols(-1, 1):
Matrix Elements >>>
           1            2            3       |
           4            5            6       |
           7            8            9       |
<<< Matrix Elements

[Error] swap_cols: col2 index out of range: col2=5, matrix.cols=3
After swap_cols(0, 5):
Matrix Elements >>>
           1            2            3       |
           4            5            6       |
           7            8            9       |
<<< Matrix Elements


[G1.6] Division by Zero
[Error] Division by zero in operator/.
mat3 / 0.0f: Error

[G1.7] Matrix Division with Zero Elements
[Error] Matrix division failed: Division by zero detected at position (0, 1)
mat4 /= divisor (with zero):
Matrix Elements >>>
           1            2       |
           3            4       |
<<< Matrix Elements


[G1.8] Empty Matrix Operations
[>>> Error ! <<<] Memory allocation failed in alloc_mem()
[>>> Error ! <<<] Memory allocation failed in alloc_mem()
[Error] operator+=: this matrix data pointer is null
Empty matrix addition: Empty matrix or error state (Expected) [PASS]

[G2: Quality Assurance - Performance Benchmarks Tests]

[G2.1] Matrix Addition Performance
[Performance] 50x50 Matrix Addition (100 iterations): 18155.00 us total, 181.55 us avg

[G2.2] Matrix Multiplication Performance
[Performance] 30x30 Matrix Multiplication (100 iterations): 66752.00 us total, 667.52 us avg

[G2.3] Matrix Transpose Performance
[Performance] 50x30 Matrix Transpose (100 iterations): 22005.00 us total, 220.05 us avg

[G2.4] Determinant Calculation Performance Comparison

[G2.4.1] Small Matrix (4x4) - Laplace Expansion
[Performance] 4x4 Determinant (Laplace, 10 iterations): 3121.00 us total, 312.10 us avg

[G2.4.2] Large Matrix (8x8) - LU Decomposition
[Performance] 8x8 Determinant (LU, 10 iterations): 2027.00 us total, 202.70 us avg

[G2.4.3] Large Matrix (8x8) - Gaussian Elimination
[Performance] 8x8 Determinant (Gaussian, 10 iterations): 461.00 us total, 46.10 us avg

[G2.4.4] Large Matrix (8x8) - Auto-select Method
[Performance] 8x8 Determinant (auto-select, 10 iterations): 2013.00 us total, 201.30 us avg

[Note] Performance Summary:
  - Laplace expansion (O(n!)): Suitable only for small matrices (n <= 4)
  - LU decomposition (O()): Efficient for large matrices, auto-selected for n > 4
  - Gaussian elimination (O()): Alternative efficient method for large matrices
  - Auto-select: Automatically chooses the best method based on matrix size

[G2.5] Matrix Copy with Padding Performance
[Performance] 8x8 Copy ROI (with padding) (100 iterations): 2587.00 us total, 25.87 us avg

[G2.6] Element Access Performance
[Performance] Computing element access (warmup)...
[Performance] 50x50 Element Access (all elements) (100 iterations): 9685.00 us total, 96.85 us avg

[G3: Quality Assurance - Memory Layout Tests (Padding and Stride)]

[G3.1] Contiguous Memory (no padding)
Matrix 3x4 (stride=4, pad=0):
Matrix Info >>>
rows            3
cols            4
elements        12
paddings        0
stride          4
memory          12
data pointer    0x3fce9af0
temp pointer    0
ext_buff        0
sub_matrix      0
<<< Matrix Info
Matrix Elements >>>
        0.00         1.00         2.00         3.00       |
        4.00         5.00         6.00         7.00       |
        8.00         9.00        10.00        11.00       |
<<< Matrix Elements


[G3.2] Padded Memory (stride > col)
Matrix 3x4 (stride=5, pad=1):
Matrix Info >>>
rows            3
cols            4
elements        12
paddings        1
stride          5
memory          15
data pointer    0x3fc9a3f4
temp pointer    0
ext_buff        1   (External buffer or View)
sub_matrix      0
<<< Matrix Info
Matrix Elements >>>
        0.00         1.00         2.00         3.00       |   0.00 
        4.00         5.00         6.00         7.00       |   0.00 
        8.00         9.00        10.00        11.00       |   0.00 
<<< Matrix Elements


[G3.3] Addition with Padded Matrices
Result of padded matrix addition:
Matrix Info >>>
rows            3
cols            4
elements        12
paddings        1
stride          5
memory          15
data pointer    0x3fce9c64
temp pointer    0
ext_buff        0
sub_matrix      0
<<< Matrix Info
Matrix Elements >>>
       11.00        22.00        33.00        44.00       |  20.00 
       55.00        66.00        77.00        88.00       |  25.00 
       99.00       110.00       121.00       132.00       |   1.61 
<<< Matrix Elements


[G3.4] ROI Operations with Padded Matrices
ROI (1,1,2,2) from padded matrix:
Matrix Info >>>
rows            2
cols            2
elements        4
paddings        3
stride          5
memory          10
data pointer    0x3fc9a40c
temp pointer    0
ext_buff        1   (External buffer or View)
sub_matrix      1   (This is a Sub-Matrix View)
<<< Matrix Info
Matrix Elements >>>
        5.00         6.00       |   7.00         0.00         8.00 
        9.00        10.00       |  11.00         0.00         0.00 
<<< Matrix Elements


[G3.5] Copy Operations Preserve Stride
Copied matrix (should have stride=4, no padding):
Matrix Info >>>
rows            3
cols            4
elements        12
paddings        0
stride          4
memory          12
data pointer    0x3fce9d98
temp pointer    0
ext_buff        0
sub_matrix      0
<<< Matrix Info
Matrix Elements >>>
        0.00         1.00         2.00         3.00       |
        4.00         5.00         6.00         7.00       |
        8.00         9.00        10.00        11.00       |
<<< Matrix Elements