ariadnetor_tensor/block_sparse/
tensor_data.rs1use std::sync::Arc;
4
5use aligned_vec::{AVec, ConstAlign};
6use ariadnetor_core::backend::MemoryOrder;
7use num_traits::Zero;
8use rand::RngExt;
9
10use super::{BlockCoord, BlockMeta, BlockSparseLayout, BlockSparseStorage, QNIndex};
11use crate::{Sector, TensorData};
12
13pub type BlockSparseTensorData<T, S> = TensorData<BlockSparseStorage<T>, BlockSparseLayout<S>>;
16
17impl<T, S: Sector> BlockSparseTensorData<T, S> {
18 pub fn zeros(indices: Vec<QNIndex<S>>, flux: S, order: MemoryOrder) -> Self
28 where
29 T: Clone + Zero,
30 {
31 let layout = BlockSparseLayout::new(indices, flux, order);
32 let extent = <BlockSparseLayout<S> as crate::TensorLayout>::storage_extent(&layout);
33 let mut data: AVec<T, ConstAlign<64>> = AVec::with_capacity(64, extent);
34 data.resize(extent, T::zero());
35 let storage = BlockSparseStorage::from_aligned(data);
36 Self::new(storage, layout)
37 }
38
39 pub fn from_block_fn<F>(indices: Vec<QNIndex<S>>, flux: S, order: MemoryOrder, mut f: F) -> Self
56 where
57 T: Clone + Zero,
58 F: FnMut(&BlockCoord, &[usize]) -> Vec<T>,
59 {
60 let layout = BlockSparseLayout::new(indices, flux, order);
61 let extent = <BlockSparseLayout<S> as crate::TensorLayout>::storage_extent(&layout);
62 let mut data: AVec<T, ConstAlign<64>> = AVec::with_capacity(64, extent);
63 data.resize(extent, T::zero());
64 for meta in layout.block_metas() {
65 let block_shape = layout
66 .block_shape(&meta.coord)
67 .expect("BlockSparseLayout enumerated coord must resolve to a block shape");
68 let block = f(&meta.coord, &block_shape);
69 assert_eq!(
70 block.len(),
71 meta.size,
72 "from_block_fn: closure returned {} elements for block {:?}, expected {}",
73 block.len(),
74 meta.coord,
75 meta.size,
76 );
77 for (dst, src) in data[meta.offset..meta.offset + meta.size]
78 .iter_mut()
79 .zip(block)
80 {
81 *dst = src;
82 }
83 }
84 let storage = BlockSparseStorage::from_aligned(data);
85 Self::new(storage, layout)
86 }
87
88 pub fn random<R: rand::Rng>(
95 indices: Vec<QNIndex<S>>,
96 flux: S,
97 order: MemoryOrder,
98 rng: &mut R,
99 ) -> Self
100 where
101 rand::distr::StandardUniform: rand::distr::Distribution<T>,
102 {
103 let layout = BlockSparseLayout::new(indices, flux, order);
104 let extent = <BlockSparseLayout<S> as crate::TensorLayout>::storage_extent(&layout);
105 let mut data: AVec<T, ConstAlign<64>> = AVec::with_capacity(64, extent);
106 for _ in 0..extent {
107 data.push(rng.random());
108 }
109 let storage = BlockSparseStorage::from_aligned(data);
110 Self::new(storage, layout)
111 }
112
113 pub fn block_data(&self, coord: &BlockCoord) -> Option<&[T]> {
117 let &idx = self.layout().block_index().get(coord)?;
118 let meta = &self.layout().block_metas()[idx];
119 Some(&self.storage().data()[meta.offset..meta.offset + meta.size])
120 }
121
122 pub fn shape(&self) -> &[usize] {
124 self.layout().shape()
125 }
126
127 pub fn rank(&self) -> usize {
129 self.layout().rank()
130 }
131
132 pub fn flux(&self) -> &S {
134 self.layout().flux()
135 }
136
137 pub fn indices(&self) -> &[super::QNIndex<S>] {
139 self.layout().indices()
140 }
141
142 pub fn num_blocks(&self) -> usize {
144 self.layout().num_blocks()
145 }
146
147 pub fn block_metas(&self) -> &[BlockMeta] {
149 self.layout().block_metas()
150 }
151
152 pub fn is_allowed_block(&self, coord: &BlockCoord) -> bool {
155 self.layout().is_allowed_block(coord)
156 }
157
158 pub fn order(&self) -> ariadnetor_core::backend::MemoryOrder {
160 self.layout().order()
161 }
162
163 pub fn block_data_mut(&mut self, coord: &BlockCoord) -> Option<&mut [T]>
166 where
167 T: Clone,
168 {
169 let &idx = self.layout().block_index().get(coord)?;
170 let meta = &self.layout().block_metas()[idx];
171 let offset = meta.offset;
172 let size = meta.size;
173 let arc = self.storage_mut().arc_mut();
174 let data = Arc::make_mut(arc);
175 Some(&mut data[offset..offset + size])
176 }
177}
178
179impl<T, S: Sector> BlockSparseTensorData<T, S>
180where
181 T: ariadnetor_core::Scalar,
182{
183 pub fn dagger(&self) -> Self {
191 let new_layout = self.layout().dagger_layout();
192 let new_data: AVec<T, ConstAlign<64>> =
193 AVec::from_iter(64, self.storage().data().iter().copied().map(|x| x.conj()));
194 let storage = BlockSparseStorage::from_aligned(new_data);
195 Self::new(storage, new_layout)
196 }
197
198 pub fn conj(&self) -> Self {
202 let new_data: AVec<T, ConstAlign<64>> =
203 AVec::from_iter(64, self.storage().data().iter().copied().map(|x| x.conj()));
204 let storage = BlockSparseStorage::from_aligned(new_data);
205 Self::new(storage, self.layout().clone())
206 }
207
208 pub fn stored_len(&self) -> usize {
211 self.storage().stored_len()
212 }
213
214 pub fn norm_frobenius(&self) -> T::Real {
216 self.storage().norm_frobenius()
217 }
218
219 pub fn norm(&self) -> T::Real {
221 self.storage().norm()
222 }
223
224 pub fn normalize(&mut self) -> T::Real {
227 self.storage_mut().normalize()
228 }
229
230 pub fn normalized(&self) -> (Self, T::Real) {
234 let mut result = self.clone();
235 let norm = result.normalize();
236 (result, norm)
237 }
238}
239
240impl<T, S: Sector> BlockSparseTensorData<T, S>
241where
242 T: Clone,
243{
244 pub fn scale<F>(&mut self, factor: F)
247 where
248 T: std::ops::Mul<F, Output = T>,
249 F: Clone,
250 {
251 self.storage_mut().scale(factor);
252 }
253
254 pub fn scaled<F>(&self, factor: F) -> Self
257 where
258 T: std::ops::Mul<F, Output = T>,
259 F: Clone,
260 {
261 let mut result = self.clone();
262 result.scale(factor);
263 result
264 }
265}