1use std::sync::Arc;
24
25use crate::array::{Array, Data};
26use crate::complex::Cx;
27use crate::dtype::DType;
28use crate::error::{Error, ErrorKind, Result, Span};
29use crate::exact::{Ext, Rat};
30
31#[derive(Clone, Debug, PartialEq)]
33pub struct Sparse {
34 pub axes: Vec<usize>,
37 pub indices: Vec<usize>,
40 pub fill: Data,
43 pub entries: usize,
46}
47
48impl Sparse {
49 pub fn cell_shape(&self, shape: &[usize]) -> Vec<usize> {
52 shape
53 .iter()
54 .enumerate()
55 .filter(|(k, _)| !self.axes.contains(k))
56 .map(|(_, &n)| n)
57 .collect()
58 }
59
60 pub fn cell_size(&self, shape: &[usize]) -> usize {
62 self.cell_shape(shape).iter().product()
63 }
64}
65
66struct Plan {
70 bases: Vec<usize>,
72 cell: Vec<usize>,
74}
75
76fn plan(shape: &[usize], s: &Sparse) -> Plan {
77 let rank = shape.len();
78 let mut strides = vec![1usize; rank];
79 for k in (0..rank.saturating_sub(1)).rev() {
80 strides[k] = strides[k + 1] * shape[k + 1];
81 }
82 let k = s.axes.len();
83 let bases = (0..s.entries)
84 .map(|e| {
85 (0..k).map(|j| s.indices[e * k + j] * strides[s.axes[j]]).sum::<usize>()
86 })
87 .collect();
88 let dense: Vec<usize> = (0..rank).filter(|k| !s.axes.contains(k)).collect();
91 let mut cell = Vec::with_capacity(s.cell_size(shape));
92 let mut coord = vec![0usize; dense.len()];
93 let cells = s.cell_size(shape);
94 for _ in 0..cells {
95 cell.push(coord.iter().zip(&dense).map(|(&c, &ax)| c * strides[ax]).sum());
96 let mut j = dense.len();
97 while j > 0 {
98 j -= 1;
99 coord[j] += 1;
100 if coord[j] < shape[dense[j]] {
101 break;
102 }
103 coord[j] = 0;
104 }
105 }
106 Plan { bases, cell }
107}
108
109fn expand<T: Clone>(values: &[T], fill: &T, count: usize, p: &Plan) -> Vec<T> {
111 let mut out = vec![fill.clone(); count];
112 let width = p.cell.len();
113 for (e, &base) in p.bases.iter().enumerate() {
114 for (c, &off) in p.cell.iter().enumerate() {
115 out[base + off] = values[e * width + c].clone();
116 }
117 }
118 out
119}
120
121pub(crate) fn densify(a: &Array, s: &Sparse) -> Array {
123 let count: usize = a.shape.iter().product();
124 let p = plan(&a.shape, s);
125 macro_rules! by {
126 ($($variant:ident),*) => {
127 match (&a.data, &s.fill) {
128 $((Data::$variant(v), Data::$variant(f)) => {
129 Data::$variant(expand(v, &f[0], count, &p).into())
130 })*
131 _ => Data::empty(a.dtype()),
134 }
135 };
136 }
137 let data = by!(Bool, I64, Ext, Rat, F64, Complex, Char, Symbol, Box);
138 Array::new(a.shape.clone(), data)
139}
140
141fn nonzero(a: &Array) -> Vec<usize> {
143 fn of<T: PartialEq>(v: &[T], zero: T) -> Vec<usize> {
144 v.iter().enumerate().filter(|(_, x)| **x != zero).map(|(i, _)| i).collect()
145 }
146 match &a.data {
147 Data::Bool(v) => of(v, 0),
148 Data::I64(v) => of(v, 0),
149 Data::F64(v) => of(v, 0.0),
150 Data::Complex(v) => of(v, crate::complex::ZERO),
151 _ => Vec::new(),
152 }
153}
154
155fn zero_of(dtype: DType) -> Data {
157 match dtype {
158 DType::Bool => Data::Bool(vec![0u8].into()),
159 DType::I64 => Data::I64(vec![0i64].into()),
160 DType::F64 => Data::F64(vec![0.0f64].into()),
161 DType::Complex => Data::Complex(vec![crate::complex::ZERO].into()),
162 DType::Ext => Data::Ext(vec![Ext::default()].into()),
163 DType::Rat => Data::Rat(vec![Rat::zero()].into()),
164 DType::Char => Data::Char(vec![' '].into()),
165 DType::Symbol => Data::Symbol(vec![crate::symbol::EMPTY].into()),
166 DType::Box => Data::Box(vec![Array::box_fill()].into()),
167 }
168}
169
170fn check_storable(a: &Array, span: Span) -> Result<()> {
174 match a.dtype() {
175 DType::Bool | DType::I64 | DType::F64 | DType::Complex => Ok(()),
176 DType::Char | DType::Box | DType::Symbol => Err(Error::not_yet(
177 format!("a sparse array of {}", a.dtype().name()),
178 span,
179 )),
180 DType::Ext | DType::Rat => Err(Error::domain(
181 format!("{} has no sparse form", a.dtype().name()),
182 span,
183 )),
184 }
185}
186
187pub fn sparsify(y: &Array, span: Span) -> Result<Array> {
191 if y.is_sparse() {
192 return Ok(y.clone());
193 }
194 let y = y.to_row_major();
195 if y.rank() == 0 {
196 return Ok(y);
197 }
198 check_storable(&y, span)?;
199 let rank = y.rank();
200 let mut strides = vec![1usize; rank];
201 for k in (0..rank - 1).rev() {
202 strides[k] = strides[k + 1] * y.shape[k + 1];
203 }
204 let at = nonzero(&y);
205 let mut indices = Vec::with_capacity(at.len() * rank);
206 let mut values = Data::empty(y.dtype());
207 for &i in &at {
208 let mut rest = i;
209 for &stride in &strides {
210 indices.push(rest / stride);
211 rest %= stride;
212 }
213 values.push_from(&y.data, i);
214 }
215 let s = Sparse {
216 axes: (0..rank).collect(),
217 indices,
218 fill: zero_of(y.dtype()),
219 entries: at.len(),
220 };
221 Ok(Array::sparse(y.shape.clone(), values, s))
222}
223
224pub fn create(y: &Array, span: Span) -> Result<Array> {
229 let parts: Vec<Array> = match y.as_boxes() {
230 Some(b) if y.rank() <= 1 => b.iter().map(|a| a.densified()).collect(),
231 _ => vec![y.densified()],
232 };
233 if parts.is_empty() || parts.len() > 3 {
234 return Err(Error::new(
235 ErrorKind::Length,
236 "a sparse array is made from a shape, or a shape and its sparse axes, or those and the element that fills it",
237 Some(span),
238 ));
239 }
240 let shape = axis_lengths(&parts[0], span)?;
241 let rank = shape.len();
242 let axes = match parts.get(1) {
243 None => (0..rank).collect(),
244 Some(a) => sparse_axes(a, rank, span)?,
245 };
246 let fill = match parts.get(2) {
247 None => Data::F64(vec![0.0].into()),
250 Some(a) => {
251 if a.rank() != 0 {
252 return Err(Error::new(
253 ErrorKind::Rank,
254 "the element that fills a sparse array is one atom",
255 Some(span),
256 ));
257 }
258 a.data.slice(0, 1)
259 }
260 };
261 let empty = Array::new(vec![0], fill.slice(0, 0));
262 check_storable(&empty, span)?;
263 crate::limits::elements(&shape, span)?;
266 let s = Sparse { axes, indices: Vec::new(), fill, entries: 0 };
267 Ok(Array::sparse(shape, Data::empty(empty.dtype()), s))
268}
269
270fn axis_lengths(a: &Array, span: Span) -> Result<Vec<usize>> {
272 if a.rank() > 1 {
273 return Err(Error::new(ErrorKind::Rank, "a shape is a list, not a table", Some(span)));
274 }
275 let Some(v) = a.to_i64_vec() else {
276 return Err(Error::domain("a shape is made of integers", span));
277 };
278 if v.is_empty() {
279 return Err(Error::new(
280 ErrorKind::Length,
281 "a sparse array needs at least one axis",
282 Some(span),
283 ));
284 }
285 let mut shape = Vec::with_capacity(v.len());
286 for n in v {
287 if n < 0 {
288 return Err(Error::domain("an axis length cannot be negative", span));
289 }
290 shape.push(n as usize);
291 }
292 Ok(shape)
293}
294
295fn sparse_axes(a: &Array, rank: usize, span: Span) -> Result<Vec<usize>> {
297 if a.rank() > 1 {
298 return Err(Error::new(
299 ErrorKind::Rank,
300 "the sparse axes are a list, not a table",
301 Some(span),
302 ));
303 }
304 let Some(v) = a.to_i64_vec() else {
305 return Err(Error::domain("the sparse axes are integers", span));
306 };
307 let mut axes: Vec<usize> = Vec::with_capacity(v.len());
308 for k in v {
309 if k < 0 || k as usize >= rank || axes.contains(&(k as usize)) {
310 return Err(Error::new(
311 ErrorKind::Domain,
312 format!("{k} is not an axis of a rank-{rank} array, or names one twice"),
313 Some(span),
314 ));
315 }
316 axes.push(k as usize);
317 }
318 axes.sort_unstable();
319 Ok(axes)
320}
321
322pub fn compress(a: &Array, s: &Sparse) -> Array {
326 let width = s.cell_size(&a.shape);
327 let k = s.axes.len();
328 let keep: Vec<usize> = (0..s.entries)
329 .filter(|&e| (0..width).any(|c| !same_as_fill(&a.data, e * width + c, &s.fill)))
330 .collect();
331 let mut indices = Vec::with_capacity(keep.len() * k);
332 let mut values = Data::empty(a.dtype());
333 for &e in &keep {
334 indices.extend_from_slice(&s.indices[e * k..(e + 1) * k]);
335 for c in 0..width {
336 values.push_from(&a.data, e * width + c);
337 }
338 }
339 let out = Sparse { axes: s.axes.clone(), indices, fill: s.fill.clone(), entries: keep.len() };
340 Array::sparse(a.shape.clone(), values, out)
341}
342
343fn same_as_fill(data: &Data, i: usize, fill: &Data) -> bool {
345 fn at<T: Clone + PartialEq>(v: &[T], i: usize, f: &[T]) -> bool {
346 v[i] == f[0]
347 }
348 match (data, fill) {
349 (Data::Bool(v), Data::Bool(f)) => at(v, i, f),
350 (Data::I64(v), Data::I64(f)) => at(v, i, f),
351 (Data::F64(v), Data::F64(f)) => at(v, i, f),
352 (Data::Complex(v), Data::Complex(f)) => at::<Cx>(v, i, f),
353 _ => false,
354 }
355}
356
357pub fn values_of(a: &Array, s: &Sparse) -> Array {
360 let mut shape = vec![s.entries];
361 shape.extend(s.cell_shape(&a.shape));
362 Array::new(shape, a.data.clone())
363}
364
365pub fn indices_of(s: &Sparse) -> Array {
368 let values: Vec<i64> = s.indices.iter().map(|&i| i as i64).collect();
369 Array::new(vec![s.entries, s.axes.len()], Data::I64(values.into()))
370}
371
372pub fn attributes(a: &Array, s: &Sparse) -> Array {
375 let shape = Array::from_i64(a.shape.iter().map(|&n| n as i64).collect());
376 let axes = Array::from_i64(s.axes.iter().map(|&k| k as i64).collect());
377 let fill = Array::new(vec![], s.fill.clone());
378 Array::new(vec![3], Data::Box(vec![shape, axes, fill].into()))
379}
380
381pub fn fill_of(s: &Sparse) -> Array {
383 Array::new(vec![], s.fill.clone())
384}
385
386pub(crate) type Handle = Arc<Sparse>;