use mirtal_sys::ffi;
use crate::{Array, DType, Result, Shape, Stream};
#[derive(Clone, Copy)]
pub struct Graph<'stream> {
stream: GraphStream<'stream>,
}
#[derive(Clone, Copy)]
enum GraphStream<'stream> {
Public(&'stream Stream),
Native(&'stream ffi::Stream),
}
impl<'stream> Graph<'stream> {
pub(crate) const fn new(stream: &'stream Stream) -> Self {
Self { stream: GraphStream::Public(stream) }
}
pub(crate) const fn from_native(stream: &'stream ffi::Stream) -> Self {
Self { stream: GraphStream::Native(stream) }
}
pub fn add(self, left: &Array, right: &Array) -> Result<Array> {
Array::from_raw(ffi::add(left.native()?, right.native()?, self.native()?)?, "add")
}
pub fn add_scalar(self, input: &Array, value: f32) -> Result<Array> {
Array::from_raw(ffi::add_scalar(input.native()?, value, self.native()?)?, "add_scalar")
}
pub fn multiply(self, left: &Array, right: &Array) -> Result<Array> {
Array::from_raw(ffi::multiply(left.native()?, right.native()?, self.native()?)?, "multiply")
}
pub fn multiply_scalar(self, input: &Array, value: f32) -> Result<Array> {
Array::from_raw(
ffi::multiply_scalar(input.native()?, value, self.native()?)?,
"multiply_scalar",
)
}
pub fn divide(self, left: &Array, right: &Array) -> Result<Array> {
Array::from_raw(ffi::divide(left.native()?, right.native()?, self.native()?)?, "divide")
}
pub fn power_scalar(self, input: &Array, exponent: f32) -> Result<Array> {
Array::from_raw(
ffi::power_scalar(input.native()?, exponent, self.native()?)?,
"power_scalar",
)
}
pub fn rms_norm(self, input: &Array, weight: &Array, eps: f32) -> Result<Array> {
Array::from_raw(
ffi::rms_norm(input.native()?, weight.native()?, eps, self.native()?)?,
"rms_norm",
)
}
pub fn rms_norm_unit(self, input: &Array, eps: f32) -> Result<Array> {
Array::from_raw(ffi::rms_norm_unit(input.native()?, eps, self.native()?)?, "rms_norm_unit")
}
pub fn astype(self, input: &Array, dtype: DType) -> Result<Array> {
Array::from_raw(ffi::astype(input.native()?, dtype as u8, self.native()?)?, "astype")
}
pub fn reshape(self, input: &Array, shape: &Shape) -> Result<Array> {
Array::from_raw(ffi::reshape(input.native()?, &shape.native()?, self.native()?)?, "reshape")
}
pub fn transpose(self, input: &Array, axes: &[usize]) -> Result<Array> {
let axes = axes
.iter()
.copied()
.map(i32::try_from)
.collect::<std::result::Result<Vec<_>, _>>()?;
Array::from_raw(ffi::transpose(input.native()?, &axes, self.native()?)?, "transpose")
}
pub fn expand_dims(self, input: &Array, axes: &[i32]) -> Result<Array> {
Array::from_raw(ffi::expand_dims(input.native()?, axes, self.native()?)?, "expand_dims")
}
pub fn squeeze_axis(self, input: &Array, axis: i32) -> Result<Array> {
Array::from_raw(ffi::squeeze_axis(input.native()?, axis, self.native()?)?, "squeeze_axis")
}
pub fn sigmoid(self, input: &Array) -> Result<Array> {
Array::from_raw(ffi::sigmoid(input.native()?, self.native()?)?, "sigmoid")
}
pub fn sigmoid_multiply(self, gate: &Array, input: &Array) -> Result<Array> {
Array::from_raw(
ffi::sigmoid_multiply(gate.native()?, input.native()?, self.native()?)?,
"sigmoid_multiply",
)
}
pub fn silu(self, input: &Array) -> Result<Array> {
Array::from_raw(ffi::silu(input.native()?, self.native()?)?, "silu")
}
pub fn tanh(self, input: &Array) -> Result<Array> {
Array::from_raw(ffi::tanh(input.native()?, self.native()?)?, "tanh")
}
pub(crate) fn native(self) -> Result<&'stream ffi::Stream> {
match self.stream {
GraphStream::Public(stream) => stream.native(),
GraphStream::Native(stream) => Ok(stream),
}
}
}
impl std::fmt::Debug for Graph<'_> {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter.debug_struct("Graph").finish_non_exhaustive()
}
}