pub use crate::KernelIrError;
use laddu_expr::{BinaryOp, UnaryOp, parameters::ParamId};
use num::complex::Complex64;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct KernelValueId(usize);
impl KernelValueId {
pub fn from_index(index: usize) -> Self {
Self(index)
}
pub fn index(self) -> usize {
self.0
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum KernelValueKind {
Real,
Complex,
Vector {
len: usize,
},
Matrix {
rows: usize,
cols: usize,
},
}
impl KernelValueKind {
pub fn width(self) -> usize {
match self {
Self::Real | Self::Complex => 1,
Self::Vector { len } => len,
Self::Matrix { rows, cols } => checked_matrix_width(rows, cols)
.expect("kernel matrix dimensions exceed addressable width"),
}
}
fn scalar_combine(self, rhs: Self) -> Option<Self> {
match (self, rhs) {
(Self::Real, Self::Real) => Some(Self::Real),
(Self::Real | Self::Complex, Self::Real | Self::Complex) => Some(Self::Complex),
_ => None,
}
}
fn is_scalar(self) -> bool {
matches!(self, Self::Real | Self::Complex)
}
}
fn checked_matrix_width(rows: usize, cols: usize) -> Option<usize> {
rows.checked_mul(cols)
}
fn checked_row_major_index(rows: usize, cols: usize, row: usize, col: usize) -> Option<usize> {
checked_matrix_width(rows, cols)?;
if row >= rows || col >= cols {
return None;
}
row.checked_mul(cols)?.checked_add(col)
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum KernelValueClass {
Invariant,
Event,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum KernelEventDependence {
Invariant,
Event,
Operands,
}
#[derive(Clone, Debug)]
pub enum KernelInstruction {
Cached(usize),
RealConstant(f64),
ComplexConstant(Complex64),
Parameter(ParamId),
Unary {
op: UnaryOp,
input: KernelValueId,
},
Binary {
op: BinaryOp,
lhs: KernelValueId,
rhs: KernelValueId,
},
Add(Vec<KernelValueId>),
Mul(Vec<KernelValueId>),
Complex {
re: KernelValueId,
im: KernelValueId,
},
Vector(Vec<KernelValueId>),
Matrix {
rows: usize,
cols: usize,
elements: Vec<KernelValueId>,
},
Component {
input: KernelValueId,
index: usize,
},
MatrixElement {
input: KernelValueId,
row: usize,
col: usize,
},
MatMul {
lhs: KernelValueId,
rhs: KernelValueId,
},
MatVec {
matrix: KernelValueId,
vector: KernelValueId,
},
Dot {
lhs: KernelValueId,
rhs: KernelValueId,
},
Solve {
matrix: KernelValueId,
rhs: KernelValueId,
},
SolveRow {
row_slot: usize,
rhs: Vec<KernelValueId>,
},
SolveRowAdjointElement {
row_slot: usize,
index: usize,
len: usize,
adjoint: KernelValueId,
},
}
#[derive(Clone, Debug)]
pub struct KernelValue {
pub kind: KernelValueKind,
pub class: KernelValueClass,
pub instruction: KernelInstruction,
}
#[derive(Clone, Debug)]
pub struct ScalarKernelIr {
values: Vec<KernelValue>,
root: KernelValueId,
}
#[derive(Clone, Debug)]
pub struct CacheKernelIr {
values: Vec<KernelValue>,
outputs: Vec<KernelValueId>,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum OutputComponent {
Real,
Imag,
}
#[derive(Clone, Debug)]
pub struct GradientKernelIr {
values: Vec<KernelValue>,
primal_root: KernelValueId,
outputs: Vec<KernelValueId>,
component: OutputComponent,
}
#[derive(Clone, Debug)]
pub struct KernelIrBuilder {
values: Vec<KernelValue>,
}
mod builder;
mod instruction;
mod validate;
mod wrappers;
use validate::validate_graph;
#[cfg(test)]
mod tests;