blob: ddbe9a2cedee07aab907e69724ee15aca5a60895 [file]
// 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);
}
}