// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

//! Matrix multiplication via `matrixmultiply` crate.
//! Pure Rust with SIMD + cache blocking, no system BLAS dependency.

/// C = alpha * A * B^T + beta * C
/// A: [m × k] row-major
/// B: [n × k] row-major (transposed in the multiply)
/// C: [m × n] row-major
pub fn sgemm_a_bt(
    m: usize,
    n: usize,
    k: usize,
    alpha: f32,
    a: &[f32],
    b: &[f32],
    beta: f32,
    c: &mut [f32],
) {
    unsafe {
        matrixmultiply::sgemm(
            m,
            k,
            n,
            alpha,
            a.as_ptr(),
            k as isize, // row stride of A
            1,          // col stride of A
            b.as_ptr(),
            1,          // B^T: col stride = 1 means we read B row-wise as columns
            k as isize, // B^T: row stride = k means next "column of B^T" = next row of B
            beta,
            c.as_mut_ptr(),
            n as isize, // row stride of C
            1,          // col stride of C
        );
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_sgemm_a_bt() {
        // A = [[1, 2], [3, 4]]  (2x2)
        // B = [[5, 6], [7, 8]]  (2x2)
        // A * B^T = [[1*5+2*6, 1*7+2*8], [3*5+4*6, 3*7+4*8]]
        //         = [[17, 23], [39, 53]]
        let a = [1.0f32, 2.0, 3.0, 4.0];
        let b = [5.0f32, 6.0, 7.0, 8.0];
        let mut c = [0.0f32; 4];

        sgemm_a_bt(2, 2, 2, 1.0, &a, &b, 0.0, &mut c);

        assert!((c[0] - 17.0).abs() < 1e-5);
        assert!((c[1] - 23.0).abs() < 1e-5);
        assert!((c[2] - 39.0).abs() < 1e-5);
        assert!((c[3] - 53.0).abs() < 1e-5);
    }

    #[test]
    fn test_sgemm_rectangular() {
        // A = [[1, 2, 3]]   (1x3)
        // B = [[4, 5, 6], [7, 8, 9]]  (2x3)
        // A * B^T = [[1*4+2*5+3*6, 1*7+2*8+3*9]] = [[32, 50]]
        let a = [1.0f32, 2.0, 3.0];
        let b = [4.0f32, 5.0, 6.0, 7.0, 8.0, 9.0];
        let mut c = [0.0f32; 2];

        sgemm_a_bt(1, 2, 3, 1.0, &a, &b, 0.0, &mut c);

        assert!((c[0] - 32.0).abs() < 1e-5);
        assert!((c[1] - 50.0).abs() < 1e-5);
    }
}
