use crate::error::{LatticeError, Result};
use crate::lattice::PaddedTileLattice;
pub trait Semiring {
fn zero() -> f32;
fn one() -> f32;
fn add(a: f32, b: f32) -> f32;
fn mul(a: f32, b: f32) -> f32;
}
pub struct Boolean;
impl Semiring for Boolean {
#[inline]
fn zero() -> f32 {
0.0
}
#[inline]
fn one() -> f32 {
1.0
}
#[inline]
fn add(a: f32, b: f32) -> f32 {
if a != 0.0 || b != 0.0 {
1.0
} else {
0.0
}
}
#[inline]
fn mul(a: f32, b: f32) -> f32 {
if a != 0.0 && b != 0.0 {
1.0
} else {
0.0
}
}
}
pub struct Tropical;
impl Semiring for Tropical {
#[inline]
fn zero() -> f32 {
f32::INFINITY
}
#[inline]
fn one() -> f32 {
0.0
}
#[inline]
fn add(a: f32, b: f32) -> f32 {
if a < b {
a
} else {
b
}
}
#[inline]
fn mul(a: f32, b: f32) -> f32 {
a + b
}
}
pub struct MaxPlus;
impl Semiring for MaxPlus {
#[inline]
fn zero() -> f32 {
f32::NEG_INFINITY
}
#[inline]
fn one() -> f32 {
0.0
}
#[inline]
fn add(a: f32, b: f32) -> f32 {
if a > b {
a
} else {
b
}
}
#[inline]
fn mul(a: f32, b: f32) -> f32 {
a + b
}
}
pub struct Counting;
impl Semiring for Counting {
#[inline]
fn zero() -> f32 {
0.0
}
#[inline]
fn one() -> f32 {
1.0
}
#[inline]
fn add(a: f32, b: f32) -> f32 {
a + b
}
#[inline]
fn mul(a: f32, b: f32) -> f32 {
a * b
}
}
pub fn semiring_matmul<S: Semiring>(
a: &PaddedTileLattice<f32>,
b: &PaddedTileLattice<f32>,
) -> Result<PaddedTileLattice<f32>> {
if a.cols() != b.rows() {
return Err(LatticeError::ContractionMismatch {
lhs_cols: a.cols(),
rhs_rows: b.rows(),
});
}
if a.geometry() != b.geometry() {
return Err(LatticeError::GeometryMismatch);
}
let m = a.rows();
let k = a.cols();
let n = b.cols();
let mut out = vec![S::zero(); m * n];
for i in 0..m {
for j in 0..n {
let mut acc = S::zero();
for kk in 0..k {
acc = S::add(acc, S::mul(*a.get(i, kk).unwrap(), *b.get(kk, j).unwrap()));
}
out[i * n + j] = acc;
}
}
PaddedTileLattice::from_dense(m, n, &out, *a.geometry())
}