use std::any::Any;
use std::sync::Arc;
use half::{bf16, f16};
use sim_kernel::{DefaultFactory, Error, Factory, Result, Symbol, Value};
use sim_lib_numbers_core::domains;
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum TensorLocation {
Host,
Resident {
site: Symbol,
allocation: Symbol,
},
}
pub trait TensorStorage: Send + Sync + 'static {
fn dtype(&self) -> &Symbol;
fn len(&self) -> usize;
fn is_empty(&self) -> bool {
self.len() == 0
}
fn location(&self) -> TensorLocation;
fn cell(&self, index: usize) -> Result<Value>;
fn materialize(&self) -> Result<Arc<dyn TensorStorage>>;
fn as_any(&self) -> &dyn Any;
}
pub struct BoxedTensorStorage {
dtype: Symbol,
cells: Arc<[Value]>,
}
impl BoxedTensorStorage {
pub(crate) fn new(dtype: Symbol, cells: Vec<Value>) -> Self {
Self {
dtype,
cells: cells.into(),
}
}
pub(crate) fn cells(&self) -> Arc<[Value]> {
self.cells.clone()
}
}
impl TensorStorage for BoxedTensorStorage {
fn dtype(&self) -> &Symbol {
&self.dtype
}
fn len(&self) -> usize {
self.cells.len()
}
fn location(&self) -> TensorLocation {
TensorLocation::Host
}
fn cell(&self, index: usize) -> Result<Value> {
self.cells
.get(index)
.cloned()
.ok_or_else(|| Error::Eval("tensor cell index was out of bounds".to_owned()))
}
fn materialize(&self) -> Result<Arc<dyn TensorStorage>> {
Ok(Arc::new(Self {
dtype: self.dtype.clone(),
cells: self.cells.clone(),
}))
}
fn as_any(&self) -> &dyn Any {
self
}
}
pub trait TensorCell: Clone + Send + Sync + 'static {
fn dtype() -> Symbol;
fn to_value(&self) -> Result<Value>;
}
pub struct TypedTensorStorage<T: TensorCell> {
dtype: Symbol,
cells: Arc<[T]>,
}
impl<T: TensorCell> TypedTensorStorage<T> {
pub fn new(cells: Vec<T>) -> Self {
Self::from_shared(cells.into())
}
pub fn from_shared(cells: Arc<[T]>) -> Self {
Self {
dtype: T::dtype(),
cells,
}
}
pub fn cell_slice(&self) -> &[T] {
&self.cells
}
pub fn cells(&self) -> Arc<[T]> {
self.cells.clone()
}
}
impl<T: TensorCell> TensorStorage for TypedTensorStorage<T> {
fn dtype(&self) -> &Symbol {
&self.dtype
}
fn len(&self) -> usize {
self.cells.len()
}
fn location(&self) -> TensorLocation {
TensorLocation::Host
}
fn cell(&self, index: usize) -> Result<Value> {
self.cells
.get(index)
.ok_or_else(|| Error::Eval("tensor cell index was out of bounds".to_owned()))?
.to_value()
}
fn materialize(&self) -> Result<Arc<dyn TensorStorage>> {
Ok(Arc::new(Self {
dtype: self.dtype.clone(),
cells: self.cells.clone(),
}))
}
fn as_any(&self) -> &dyn Any {
self
}
}
impl TensorCell for f64 {
fn dtype() -> Symbol {
domains::f64()
}
fn to_value(&self) -> Result<Value> {
DefaultFactory.number_literal(domains::f64(), self.to_string())
}
}
impl TensorCell for f32 {
fn dtype() -> Symbol {
domains::f32()
}
fn to_value(&self) -> Result<Value> {
DefaultFactory.number_literal(domains::f32(), self.to_string())
}
}
impl TensorCell for f16 {
fn dtype() -> Symbol {
domains::f16()
}
fn to_value(&self) -> Result<Value> {
DefaultFactory.number_literal(domains::f16(), self.to_f32().to_string())
}
}
impl TensorCell for bf16 {
fn dtype() -> Symbol {
domains::bf16()
}
fn to_value(&self) -> Result<Value> {
DefaultFactory.number_literal(domains::bf16(), self.to_f32().to_string())
}
}
impl TensorCell for i64 {
fn dtype() -> Symbol {
domains::i64()
}
fn to_value(&self) -> Result<Value> {
DefaultFactory.number_literal(domains::i64(), self.to_string())
}
}
impl TensorCell for bool {
fn dtype() -> Symbol {
domains::bool()
}
fn to_value(&self) -> Result<Value> {
DefaultFactory.number_literal(domains::bool(), self.to_string())
}
}
impl TensorCell for (f64, f64) {
fn dtype() -> Symbol {
domains::complex()
}
fn to_value(&self) -> Result<Value> {
DefaultFactory.number_literal(domains::complex(), format!("{}{:+}i", self.0, self.1))
}
}
impl TensorCell for (i64, i64) {
fn dtype() -> Symbol {
domains::rational()
}
fn to_value(&self) -> Result<Value> {
DefaultFactory.number_literal(domains::rational(), format!("{}/{}", self.0, self.1))
}
}