#[cfg(feature = "shadowing")]
use anyhow::anyhow;
use serde::{Deserialize, Serialize};
use crate::{
algebra::algebraic_traits::{One, Zero},
structure::{
permuted::PermuteTensor,
slot::{AbsInd, IsAbstractSlot},
PermutedStructure,
},
};
use std::{
borrow::Cow,
fmt::{Debug, Display},
};
#[cfg(feature = "shadowing")]
use symbolica::{
atom::{Atom, AtomView},
domains::{
float::{Complex as SymComplex, Real, SingleFloat},
rational::Rational,
InternalOrdering,
},
evaluate::{
CompileOptions, CompiledCode, CompiledNumber, EvalTree, ExportNumber, ExportSettings,
ExportedCode, ExpressionEvaluator, FunctionMap,
},
};
#[cfg(feature = "shadowing")]
use crate::{
algebra::complex::{symbolica_traits::CompiledComplexEvaluatorSpenso, Complex},
tensors::data::{DataIterator, DenseTensor, SetTensorData, SparseTensor},
tensors::parametric::ParamTensor,
};
#[cfg(feature = "shadowing")]
use super::store::TensorScalarStoreMapping;
use crate::{
structure::{CastStructure, HasStructure, ScalarTensor, TensorStructure},
tensors::data::DataTensor,
};
use super::{
library::LibraryTensor,
store::{NetworkStore, TensorScalarStore},
ExecutionResult,
};
use super::{Library, Network, TensorNetworkError, TensorOrScalarOrKey};
#[derive(
Debug,
Clone,
Serialize,
Deserialize,
bincode_trait_derive::Encode,
bincode_trait_derive::Decode,
// bincode_trait_derive::BorrowDecodeFromDecode,
)]
#[cfg_attr(
feature = "shadowing",
trait_decode(trait = symbolica::state::HasStateMap),
)]
pub struct TensorNetworkSet<S, K, FK, Aind> {
pub networks: Vec<Network<S, K, FK, Aind>>,
}
impl<S, K, FK, Aind> FromIterator<Network<S, K, FK, Aind>> for TensorNetworkSet<S, K, FK, Aind> {
fn from_iter<T: IntoIterator<Item = Network<S, K, FK, Aind>>>(iter: T) -> Self {
Self {
networks: Vec::from_iter(iter),
}
}
}
impl<S, K, FK, Aind> TensorNetworkSet<S, K, FK, Aind> {
pub fn new() -> Self {
TensorNetworkSet { networks: vec![] }
}
pub fn push(&mut self, network: Network<S, K, FK, Aind>) {
self.networks.push(network);
}
}
impl<S, K, FK, Aind> Default for TensorNetworkSet<S, K, FK, Aind> {
fn default() -> Self {
Self::new()
}
}
#[cfg(feature = "shadowing")]
pub type EvalTreeTensorNetworkSet<T, S, K, FK, Aind, Str> =
SharedTensorNetworkSet<EvalTree<T>, S, K, FK, Aind, Str>;
#[cfg(feature = "shadowing")]
pub type EvalTensorNetworkSet<T, S, K, FK, Aind, Str> =
SharedTensorNetworkSet<ExpressionEvaluator<T>, S, K, FK, Aind, Str>;
#[cfg(feature = "shadowing")]
pub type CompiledTensorNetworkSet<S, K, FK, Aind, Str> =
SharedTensorNetworkSet<CompiledComplexEvaluatorSpenso, S, K, FK, Aind, Str>;
#[derive(Debug, Clone)]
pub struct SharedTensorNetworkSet<
D,
S: TensorStructure,
K,
FK,
Aind,
Str: TensorScalarStore<Tensor = DataTensor<usize, S>, Scalar = usize> = NetworkStore<
DataTensor<usize, S>,
usize,
>,
> {
pub networks: Vec<Network<Str, K, FK, Aind>>,
pub shared_data: D,
pub len: usize,
}
impl<
T: TensorStructure,
S,
K: Display + Debug,
FK: Display + Debug + Clone,
Str: TensorScalarStore<Tensor = T, Scalar = S>,
Aind: AbsInd,
> TensorNetworkSet<Str, K, FK, Aind>
{
#[allow(clippy::type_complexity, clippy::result_large_err)]
pub fn result(
&self,
) -> Result<
Vec<ExecutionResult<TensorOrScalarOrKey<&T, &S, &PermutedStructure<K>, Aind>>>,
TensorNetworkError<K, FK>,
>
where
T::Slot: IsAbstractSlot<Aind = Aind>,
{
self.networks.iter().map(|n| n.result()).collect()
}
#[allow(clippy::type_complexity, clippy::result_large_err)]
pub fn result_tensor<'a, LT, L: Library<T::Structure, Key = K, Value = PermutedStructure<LT>>>(
&'a self,
lib: &L,
) -> Result<Vec<ExecutionResult<Cow<'a, T>>>, TensorNetworkError<K, FK>>
where
S: 'a,
T: Clone + ScalarTensor + HasStructure,
T::Scalar: One + Zero,
for<'b> &'b S: Into<T::Scalar>,
LT: TensorStructure<Indexed = T> + Clone + LibraryTensor<WithIndices = T>,
T: PermuteTensor<Permuted = T>,
<<LT::WithIndices as HasStructure>::Structure as TensorStructure>::Slot:
IsAbstractSlot<Aind = Aind>,
T::Slot: IsAbstractSlot<Aind = Aind>,
{
self.networks.iter().map(|n| n.result_tensor(lib)).collect()
}
#[allow(clippy::type_complexity, clippy::result_large_err)]
pub fn result_scalar<'a>(
&'a self,
) -> Result<Vec<ExecutionResult<Cow<'a, S>>>, TensorNetworkError<K, FK>>
where
T: Clone + ScalarTensor + 'a,
T::Scalar: Into<S>,
S: One + Zero + Clone,
T::Slot: IsAbstractSlot<Aind = Aind>,
{
self.networks.iter().map(|n| n.result_scalar()).collect()
}
pub fn cast<U>(self) -> TensorNetworkSet<Str::Store<U, S>, K, FK, Aind>
where
K: Clone,
T: CastStructure<U> + HasStructure,
T::Structure: TensorStructure,
U: HasStructure,
T::Slot: IsAbstractSlot<Aind = Aind>,
U::Structure: From<T::Structure> + TensorStructure<Slot = T::Slot>,
{
self.networks.into_iter().map(|n| n.cast()).collect()
}
}
#[cfg(feature = "shadowing")]
impl<
Store: TensorScalarStore<Tensor = ParamTensor<S>, Scalar = Atom>,
S: TensorStructure + Clone,
K: Clone,
FK: Clone,
Aind: AbsInd,
> TensorNetworkSet<Store, K, FK, Aind>
{
#[allow(clippy::type_complexity, clippy::result_large_err)]
pub fn eval_tree(
self,
fn_map: &FunctionMap,
params: &[Atom],
) -> anyhow::Result<
EvalTreeTensorNetworkSet<
SymComplex<Rational>,
S,
K,
FK,
Aind,
Store::Store<DataTensor<usize, S>, usize>,
>,
>
where
Store::Store<DataTensor<usize, S>, usize>:
TensorScalarStore<Tensor = DataTensor<usize, S>, Scalar = usize>,
S: TensorStructure,
{
let mut networks = vec![];
let mut atoms = vec![];
let mut scalar_id = 0;
let mut tensor_id = 0;
for net in &self.networks {
for s in net.iter_scalars() {
atoms.push(s);
tensor_id += 1;
}
let tensors = net.map_ref(
|_| {
let oldid = scalar_id;
scalar_id += 1;
oldid
},
|t| {
let structure = t.structure().clone();
match &t.tensor {
DataTensor::Dense(d) => {
let oldid = tensor_id;
tensor_id += d.size().unwrap();
for (_, a) in d.flat_iter() {
atoms.push(a);
}
DataTensor::Dense(
DenseTensor::from_data(Vec::from_iter(oldid..tensor_id), structure)
.expect("Failed to create DenseTensor"),
)
}
DataTensor::Sparse(s) => {
let mut t = SparseTensor::empty(structure, 0);
for (i, a) in s.flat_iter() {
t.set_flat(i, tensor_id)
.expect("Failed to set value in SparseTensor");
atoms.push(a);
tensor_id += 1;
}
DataTensor::Sparse(t)
}
}
},
);
networks.push(tensors);
}
Ok(EvalTreeTensorNetworkSet {
networks,
shared_data: AtomView::to_eval_tree_multiple(&atoms, fn_map, params)
.map_err(|s| anyhow!(s))?,
len: atoms.len(),
})
}
}
#[cfg(feature = "shadowing")]
impl<
S: Clone + TensorStructure,
K,
FK,
Aind: AbsInd,
Store: TensorScalarStore<Tensor = DataTensor<usize, S>, Scalar = usize>,
> EvalTreeTensorNetworkSet<SymComplex<Rational>, S, K, FK, Aind, Store>
{
pub fn horner_scheme(&mut self) {
self.shared_data.horner_scheme();
}
}
#[cfg(feature = "shadowing")]
impl<
T,
S: TensorStructure + Clone,
K: Clone,
FK: Clone,
Aind: AbsInd,
Store: TensorScalarStore<Tensor = DataTensor<usize, S>, Scalar = usize> + Clone,
> EvalTreeTensorNetworkSet<T, S, K, FK, Aind, Store>
{
pub fn map_coeff<T2, F: Fn(&T) -> T2>(
&self,
f: &F,
) -> EvalTreeTensorNetworkSet<T2, S, K, FK, Aind, Store>
where
T: Clone + PartialEq,
{
EvalTreeTensorNetworkSet {
networks: self.networks.clone(),
shared_data: self.shared_data.map_coeff(f),
len: self.len,
}
}
pub fn linearize(
self,
cpe_rounds: Option<usize>,
verbose: bool,
) -> EvalTensorNetworkSet<T, S, K, FK, Aind, Store>
where
T: Clone + Default + PartialEq,
{
EvalTensorNetworkSet {
networks: self.networks,
shared_data: self.shared_data.linearize(cpe_rounds, verbose),
len: self.len,
}
}
pub fn common_subexpression_elimination(&mut self)
where
T: std::fmt::Debug + std::hash::Hash + Eq + InternalOrdering + Clone + Default,
{
self.shared_data.common_subexpression_elimination()
}
#[allow(clippy::type_complexity)]
pub fn evaluate(
&mut self,
params: &[T],
) -> TensorNetworkSet<Store::Store<DataTensor<T, S>, T>, K, FK, Aind>
where
T: Real + SingleFloat,
S: TensorStructure + Clone,
{
let zero = params[0].zero();
let mut data = vec![zero; self.len];
let mut networks = vec![];
self.shared_data.evaluate(params, &mut data);
for net in self.networks.iter() {
let data_net = net.map_ref(
|s| data[*s].clone(),
|p| {
let structure = p.structure().clone();
match &p {
DataTensor::Dense(d) => {
let mut t_data = vec![];
for (_, &a) in d.flat_iter() {
t_data.push(data[a].clone());
}
DataTensor::Dense(DenseTensor::from_data(t_data, structure).unwrap())
}
DataTensor::Sparse(s) => {
let mut t = SparseTensor::empty(structure, T::new_zero());
for (i, &a) in s.flat_iter() {
t.set_flat(i, data[a].clone()).unwrap();
}
DataTensor::Sparse(t)
}
}
},
);
networks.push(data_net);
}
TensorNetworkSet { networks }
}
}
#[cfg(feature = "shadowing")]
impl<
T,
S: TensorStructure + Clone,
K: Clone,
FK: Clone,
Aind: AbsInd,
Store: TensorScalarStore<Tensor = DataTensor<usize, S>, Scalar = usize> + Clone,
> EvalTensorNetworkSet<T, S, K, FK, Aind, Store>
{
#[allow(clippy::type_complexity)]
pub fn evaluate(
&mut self,
params: &[T],
) -> TensorNetworkSet<Store::Store<DataTensor<T, S>, T>, K, FK, Aind>
where
T: Real + SingleFloat,
S: TensorStructure + Clone,
{
let zero = params[0].zero();
let mut data = vec![zero; self.len];
let mut networks = vec![];
self.shared_data.evaluate(params, &mut data);
for net in self.networks.iter() {
let data_net = net.map_ref(
|s| data[*s].clone(),
|p| {
let structure = p.structure().clone();
match &p {
DataTensor::Dense(d) => {
let mut t_data = vec![];
for (_, &a) in d.flat_iter() {
t_data.push(data[a].clone());
}
DataTensor::Dense(DenseTensor::from_data(t_data, structure).unwrap())
}
DataTensor::Sparse(s) => {
let mut t = SparseTensor::empty(structure, T::new_zero());
for (i, &a) in s.flat_iter() {
t.set_flat(i, data[a].clone()).unwrap();
}
DataTensor::Sparse(t)
}
}
},
);
networks.push(data_net);
}
TensorNetworkSet { networks }
}
#[allow(clippy::type_complexity)]
pub fn export_cpp<F: CompiledNumber>(
&self,
path: impl AsRef<std::path::Path>,
function_name: &str,
settings: ExportSettings,
) -> Result<SharedTensorNetworkSet<ExportedCode<F>, S, K, FK, Aind, Store>, std::io::Error>
where
T: ExportNumber + SingleFloat,
{
Ok(SharedTensorNetworkSet {
networks: self.networks.clone(),
shared_data: self.shared_data.export_cpp(path, function_name, settings)?,
len: self.len,
})
}
}
#[cfg(feature = "shadowing")]
impl<F: CompiledNumber, S: TensorStructure + Clone, K: Clone, FK: Clone, Aind: AbsInd>
SharedTensorNetworkSet<ExportedCode<F>, S, K, FK, Aind>
{
pub fn compile(
&self,
out: impl AsRef<std::path::Path>,
options: CompileOptions,
) -> Result<SharedTensorNetworkSet<CompiledCode<F>, S, K, FK, Aind>, std::io::Error> {
Ok(SharedTensorNetworkSet {
networks: self.networks.clone(),
shared_data: self.shared_data.compile(out, options)?,
len: self.len,
})
}
}
#[cfg(feature = "shadowing")]
impl<F: CompiledNumber, S: TensorStructure + Clone, K: Clone, FK: Clone, Aind: AbsInd>
SharedTensorNetworkSet<CompiledCode<F>, S, K, FK, Aind>
{
pub fn load(&self) -> Result<SharedTensorNetworkSet<F::Evaluator, S, K, FK, Aind>, String> {
Ok(SharedTensorNetworkSet {
networks: self.networks.clone(),
shared_data: self.shared_data.load()?,
len: self.len,
})
}
}
#[cfg(feature = "shadowing")]
impl<
S: TensorStructure + Clone,
K: Clone,
FK: Clone,
Store: TensorScalarStore<Tensor = DataTensor<usize, S>, Scalar = usize> + Clone,
Aind: AbsInd,
> CompiledTensorNetworkSet<S, K, FK, Aind, Store>
{
#[allow(clippy::type_complexity, clippy::result_large_err)]
pub fn evaluate(
&mut self,
params: &[crate::algebra::complex::Complex<f64>],
) -> TensorNetworkSet<
Store::Store<
DataTensor<crate::algebra::complex::Complex<f64>, S>,
crate::algebra::complex::Complex<f64>,
>,
K,
FK,
Aind,
>
where
S: TensorStructure + Clone,
{
let zero = crate::algebra::complex::Complex::default();
let mut data = vec![zero; self.len];
let mut networks = vec![];
self.shared_data.evaluate(params, &mut data);
for net in self.networks.iter() {
let data_net = net.map_ref(
|s| data[*s],
|p| {
let structure = p.structure().clone();
match &p {
DataTensor::Dense(d) => {
let mut t_data = vec![];
for (_, &a) in d.flat_iter() {
t_data.push(data[a]);
}
DataTensor::Dense(DenseTensor::from_data(t_data, structure).unwrap())
}
DataTensor::Sparse(s) => {
let mut t = SparseTensor::empty(structure, Complex::new_zero());
for (i, &a) in s.flat_iter() {
t.set_flat(i, data[a]).unwrap();
}
DataTensor::Sparse(t)
}
}
},
);
networks.push(data_net);
}
TensorNetworkSet { networks }
}
}