1use ndarray::{Array1, Array2, ArrayView1};
7use num_traits::Float;
8use std::fmt::{self, Debug};
9use std::ops::{Add, Div, Mul, Sub};
10
11use crate::coo_array::CooArray;
12use crate::csr_array::CsrArray;
13use crate::error::{SparseError, SparseResult};
14use crate::sparray::{SparseArray, SparseSum};
15
16#[derive(Clone)]
31pub struct LilArray<T>
32where
33 T: Float
34 + Add<Output = T>
35 + Sub<Output = T>
36 + Mul<Output = T>
37 + Div<Output = T>
38 + Debug
39 + Copy
40 + 'static,
41{
42 data: Vec<Vec<T>>,
44 indices: Vec<Vec<usize>>,
46 shape: (usize, usize),
48}
49
50impl<T> LilArray<T>
51where
52 T: Float
53 + Add<Output = T>
54 + Sub<Output = T>
55 + Mul<Output = T>
56 + Div<Output = T>
57 + Debug
58 + Copy
59 + 'static,
60{
61 pub fn new(shape: (usize, usize)) -> Self {
69 let (rows, _) = shape;
70 let data = vec![Vec::new(); rows];
71 let indices = vec![Vec::new(); rows];
72
73 Self {
74 data,
75 indices,
76 shape,
77 }
78 }
79
80 pub fn from_lists(
93 data: Vec<Vec<T>>,
94 indices: Vec<Vec<usize>>,
95 shape: (usize, usize),
96 ) -> SparseResult<Self> {
97 if data.len() != shape.0 || indices.len() != shape.0 {
99 return Err(SparseError::InconsistentData {
100 reason: "Number of rows in data and indices must match the shape".to_string(),
101 });
102 }
103
104 for (i, (row_data, row_indices)) in data.iter().zip(indices.iter()).enumerate() {
105 if row_data.len() != row_indices.len() {
106 return Err(SparseError::InconsistentData {
107 reason: format!("Row {}: data and indices have different lengths", i),
108 });
109 }
110
111 if let Some(&max_col) = row_indices.iter().max() {
112 if max_col >= shape.1 {
113 return Err(SparseError::IndexOutOfBounds {
114 index: (i, max_col),
115 shape,
116 });
117 }
118 }
119 }
120
121 let mut new_data = Vec::with_capacity(shape.0);
123 let mut new_indices = Vec::with_capacity(shape.0);
124
125 for (row_data, row_indices) in data.iter().zip(indices.iter()) {
126 let mut pairs: Vec<(usize, T)> = row_indices
128 .iter()
129 .copied()
130 .zip(row_data.iter().copied())
131 .collect();
132 pairs.sort_by_key(|&(idx, _)| idx);
133
134 let mut sorted_data = Vec::with_capacity(row_data.len());
136 let mut sorted_indices = Vec::with_capacity(row_indices.len());
137
138 for (idx, val) in pairs {
139 sorted_indices.push(idx);
140 sorted_data.push(val);
141 }
142
143 new_data.push(sorted_data);
144 new_indices.push(sorted_indices);
145 }
146
147 Ok(Self {
148 data: new_data,
149 indices: new_indices,
150 shape,
151 })
152 }
153
154 pub fn from_triplets(
168 rows: &[usize],
169 cols: &[usize],
170 data: &[T],
171 shape: (usize, usize),
172 ) -> SparseResult<Self> {
173 if rows.len() != cols.len() || rows.len() != data.len() {
174 return Err(SparseError::InconsistentData {
175 reason: "rows, cols, and data must have the same length".to_string(),
176 });
177 }
178
179 let (num_rows, num_cols) = shape;
180
181 if let Some(&max_row) = rows.iter().max() {
183 if max_row >= num_rows {
184 return Err(SparseError::IndexOutOfBounds {
185 index: (max_row, 0),
186 shape,
187 });
188 }
189 }
190
191 if let Some(&max_col) = cols.iter().max() {
192 if max_col >= num_cols {
193 return Err(SparseError::IndexOutOfBounds {
194 index: (0, max_col),
195 shape,
196 });
197 }
198 }
199
200 let mut lil = LilArray::new(shape);
202
203 for (&row, &col, &value) in rows
205 .iter()
206 .zip(cols.iter())
207 .zip(data.iter())
208 .map(|((r, c), d)| (r, c, d))
209 {
210 lil.set(row, col, value)?;
211 }
212
213 Ok(lil)
214 }
215
216 pub fn get_data(&self) -> &Vec<Vec<T>> {
218 &self.data
219 }
220
221 pub fn get_indices(&self) -> &Vec<Vec<usize>> {
223 &self.indices
224 }
225
226 pub fn sort_indices(&mut self) {
228 for row in 0..self.shape.0 {
229 if !self.data[row].is_empty() {
230 let mut pairs: Vec<(usize, T)> = self.indices[row]
232 .iter()
233 .copied()
234 .zip(self.data[row].iter().copied())
235 .collect();
236
237 pairs.sort_by_key(|&(idx, _)| idx);
239
240 self.indices[row].clear();
242 self.data[row].clear();
243
244 for (idx, val) in pairs {
245 self.indices[row].push(idx);
246 self.data[row].push(val);
247 }
248 }
249 }
250 }
251}
252
253impl<T> SparseArray<T> for LilArray<T>
254where
255 T: Float
256 + Add<Output = T>
257 + Sub<Output = T>
258 + Mul<Output = T>
259 + Div<Output = T>
260 + Debug
261 + Copy
262 + 'static,
263{
264 fn shape(&self) -> (usize, usize) {
265 self.shape
266 }
267
268 fn nnz(&self) -> usize {
269 self.indices.iter().map(|row| row.len()).sum()
270 }
271
272 fn dtype(&self) -> &str {
273 "float" }
275
276 fn to_array(&self) -> Array2<T> {
277 let (rows, cols) = self.shape;
278 let mut result = Array2::zeros((rows, cols));
279
280 for row in 0..rows {
281 for (idx, &col) in self.indices[row].iter().enumerate() {
282 result[[row, col]] = self.data[row][idx];
283 }
284 }
285
286 result
287 }
288
289 fn toarray(&self) -> Array2<T> {
290 self.to_array()
291 }
292
293 fn to_coo(&self) -> SparseResult<Box<dyn SparseArray<T>>> {
294 let nnz = self.nnz();
295 let mut row_indices = Vec::with_capacity(nnz);
296 let mut col_indices = Vec::with_capacity(nnz);
297 let mut values = Vec::with_capacity(nnz);
298
299 for row in 0..self.shape.0 {
300 for (idx, &col) in self.indices[row].iter().enumerate() {
301 row_indices.push(row);
302 col_indices.push(col);
303 values.push(self.data[row][idx]);
304 }
305 }
306
307 CooArray::from_triplets(&row_indices, &col_indices, &values, self.shape, false)
308 .map(|array| Box::new(array) as Box<dyn SparseArray<T>>)
309 }
310
311 fn to_csr(&self) -> SparseResult<Box<dyn SparseArray<T>>> {
312 let (rows, _cols) = self.shape;
313 let nnz = self.nnz();
314
315 let mut data = Vec::with_capacity(nnz);
316 let mut indices = Vec::with_capacity(nnz);
317 let mut indptr = Vec::with_capacity(rows + 1);
318
319 indptr.push(0);
320
321 for row in 0..rows {
322 for (idx, &col) in self.indices[row].iter().enumerate() {
323 indices.push(col);
324 data.push(self.data[row][idx]);
325 }
326 indptr.push(indptr.last().unwrap() + self.indices[row].len());
327 }
328
329 CsrArray::new(
330 Array1::from_vec(data),
331 Array1::from_vec(indices),
332 Array1::from_vec(indptr),
333 self.shape,
334 )
335 .map(|array| Box::new(array) as Box<dyn SparseArray<T>>)
336 }
337
338 fn to_csc(&self) -> SparseResult<Box<dyn SparseArray<T>>> {
339 self.to_coo()?.to_csc()
341 }
342
343 fn to_dok(&self) -> SparseResult<Box<dyn SparseArray<T>>> {
344 self.to_coo()?.to_dok()
346 }
347
348 fn to_lil(&self) -> SparseResult<Box<dyn SparseArray<T>>> {
349 Ok(Box::new(self.clone()))
350 }
351
352 fn to_dia(&self) -> SparseResult<Box<dyn SparseArray<T>>> {
353 self.to_coo()?.to_dia()
355 }
356
357 fn to_bsr(&self) -> SparseResult<Box<dyn SparseArray<T>>> {
358 self.to_coo()?.to_bsr()
360 }
361
362 fn add(&self, other: &dyn SparseArray<T>) -> SparseResult<Box<dyn SparseArray<T>>> {
363 let self_csr = self.to_csr()?;
365 self_csr.add(other)
366 }
367
368 fn sub(&self, other: &dyn SparseArray<T>) -> SparseResult<Box<dyn SparseArray<T>>> {
369 let self_csr = self.to_csr()?;
371 self_csr.sub(other)
372 }
373
374 fn mul(&self, other: &dyn SparseArray<T>) -> SparseResult<Box<dyn SparseArray<T>>> {
375 let self_csr = self.to_csr()?;
377 self_csr.mul(other)
378 }
379
380 fn div(&self, other: &dyn SparseArray<T>) -> SparseResult<Box<dyn SparseArray<T>>> {
381 let self_csr = self.to_csr()?;
383 self_csr.div(other)
384 }
385
386 fn dot(&self, other: &dyn SparseArray<T>) -> SparseResult<Box<dyn SparseArray<T>>> {
387 let self_csr = self.to_csr()?;
389 self_csr.dot(other)
390 }
391
392 fn dot_vector(&self, other: &ArrayView1<T>) -> SparseResult<Array1<T>> {
393 let (rows, cols) = self.shape;
394 if cols != other.len() {
395 return Err(SparseError::DimensionMismatch {
396 expected: cols,
397 found: other.len(),
398 });
399 }
400
401 let mut result = Array1::zeros(rows);
402
403 for row in 0..rows {
404 for (idx, &col) in self.indices[row].iter().enumerate() {
405 result[row] = result[row] + self.data[row][idx] * other[col];
406 }
407 }
408
409 Ok(result)
410 }
411
412 fn transpose(&self) -> SparseResult<Box<dyn SparseArray<T>>> {
413 self.to_coo()?.transpose()
416 }
417
418 fn copy(&self) -> Box<dyn SparseArray<T>> {
419 Box::new(self.clone())
420 }
421
422 fn get(&self, i: usize, j: usize) -> T {
423 if i >= self.shape.0 || j >= self.shape.1 {
424 return T::zero();
425 }
426
427 match self.indices[i].binary_search(&j) {
428 Ok(pos) => self.data[i][pos],
429 Err(_) => T::zero(),
430 }
431 }
432
433 fn set(&mut self, i: usize, j: usize, value: T) -> SparseResult<()> {
434 if i >= self.shape.0 || j >= self.shape.1 {
435 return Err(SparseError::IndexOutOfBounds {
436 index: (i, j),
437 shape: self.shape,
438 });
439 }
440
441 match self.indices[i].binary_search(&j) {
442 Ok(pos) => {
443 if value.is_zero() {
444 self.data[i].remove(pos);
446 self.indices[i].remove(pos);
447 } else {
448 self.data[i][pos] = value;
450 }
451 }
452 Err(pos) => {
453 if !value.is_zero() {
454 self.data[i].insert(pos, value);
456 self.indices[i].insert(pos, j);
457 }
458 }
459 }
460
461 Ok(())
462 }
463
464 fn eliminate_zeros(&mut self) {
465 for row in 0..self.shape.0 {
466 let mut new_data = Vec::new();
467 let mut new_indices = Vec::new();
468
469 for (idx, &value) in self.data[row].iter().enumerate() {
470 if !value.is_zero() {
471 new_data.push(value);
472 new_indices.push(self.indices[row][idx]);
473 }
474 }
475
476 self.data[row] = new_data;
477 self.indices[row] = new_indices;
478 }
479 }
480
481 fn sort_indices(&mut self) {
482 LilArray::sort_indices(self);
484 }
485
486 fn sorted_indices(&self) -> Box<dyn SparseArray<T>> {
487 let mut sorted = self.clone();
488 sorted.sort_indices();
489 Box::new(sorted)
490 }
491
492 fn has_sorted_indices(&self) -> bool {
493 for row in 0..self.shape.0 {
495 if self.indices[row].len() > 1 {
496 for i in 1..self.indices[row].len() {
497 if self.indices[row][i - 1] >= self.indices[row][i] {
498 return false;
499 }
500 }
501 }
502 }
503 true
504 }
505
506 fn sum(&self, axis: Option<usize>) -> SparseResult<SparseSum<T>> {
507 match axis {
508 None => {
509 let mut sum = T::zero();
511 for row in 0..self.shape.0 {
512 for &val in self.data[row].iter() {
513 sum = sum + val;
514 }
515 }
516 Ok(SparseSum::Scalar(sum))
517 }
518 Some(0) => {
519 let (_, cols) = self.shape;
521 let mut result = Array1::<T>::zeros(cols);
522
523 for row in 0..self.shape.0 {
524 for (idx, &col) in self.indices[row].iter().enumerate() {
525 result[col] = result[col] + self.data[row][idx];
526 }
527 }
528
529 let mut lil = LilArray::new((1, cols));
531 for (col, &val) in result.iter().enumerate() {
532 if !val.is_zero() {
533 lil.set(0, col, val)?;
534 }
535 }
536
537 Ok(SparseSum::SparseArray(Box::new(lil)))
538 }
539 Some(1) => {
540 let (rows, _) = self.shape;
542 let mut result = Array1::<T>::zeros(rows);
543
544 for row in 0..rows {
545 for &val in self.data[row].iter() {
546 result[row] = result[row] + val;
547 }
548 }
549
550 let mut lil = LilArray::new((rows, 1));
552 for (row, &val) in result.iter().enumerate() {
553 if !val.is_zero() {
554 lil.set(row, 0, val)?;
555 }
556 }
557
558 Ok(SparseSum::SparseArray(Box::new(lil)))
559 }
560 _ => Err(SparseError::InvalidAxis),
561 }
562 }
563
564 fn max(&self) -> T {
565 if self.nnz() == 0 {
566 return T::neg_infinity();
567 }
568
569 let mut max_val = T::neg_infinity();
570 for row in 0..self.shape.0 {
571 for &val in self.data[row].iter() {
572 if val > max_val {
573 max_val = val;
574 }
575 }
576 }
577
578 if max_val < T::zero() && self.nnz() < self.shape.0 * self.shape.1 {
580 T::zero()
581 } else {
582 max_val
583 }
584 }
585
586 fn min(&self) -> T {
587 if self.nnz() == 0 {
588 return T::infinity();
589 }
590
591 let mut min_val = T::infinity();
592 for row in 0..self.shape.0 {
593 for &val in self.data[row].iter() {
594 if val < min_val {
595 min_val = val;
596 }
597 }
598 }
599
600 if min_val > T::zero() && self.nnz() < self.shape.0 * self.shape.1 {
602 T::zero()
603 } else {
604 min_val
605 }
606 }
607
608 fn find(&self) -> (Array1<usize>, Array1<usize>, Array1<T>) {
609 let nnz = self.nnz();
610 let mut rows = Vec::with_capacity(nnz);
611 let mut cols = Vec::with_capacity(nnz);
612 let mut values = Vec::with_capacity(nnz);
613
614 for row in 0..self.shape.0 {
615 for (idx, &col) in self.indices[row].iter().enumerate() {
616 rows.push(row);
617 cols.push(col);
618 values.push(self.data[row][idx]);
619 }
620 }
621
622 (
623 Array1::from_vec(rows),
624 Array1::from_vec(cols),
625 Array1::from_vec(values),
626 )
627 }
628
629 fn slice(
630 &self,
631 row_range: (usize, usize),
632 col_range: (usize, usize),
633 ) -> SparseResult<Box<dyn SparseArray<T>>> {
634 let (start_row, end_row) = row_range;
635 let (start_col, end_col) = col_range;
636
637 if start_row >= self.shape.0
638 || end_row > self.shape.0
639 || start_col >= self.shape.1
640 || end_col > self.shape.1
641 || start_row >= end_row
642 || start_col >= end_col
643 {
644 return Err(SparseError::InvalidSliceRange);
645 }
646
647 let mut new_data = vec![Vec::new(); end_row - start_row];
648 let mut new_indices = vec![Vec::new(); end_row - start_row];
649
650 for row in start_row..end_row {
651 for (idx, &col) in self.indices[row].iter().enumerate() {
652 if col >= start_col && col < end_col {
653 new_data[row - start_row].push(self.data[row][idx]);
654 new_indices[row - start_row].push(col - start_col);
655 }
656 }
657 }
658
659 Ok(Box::new(LilArray {
660 data: new_data,
661 indices: new_indices,
662 shape: (end_row - start_row, end_col - start_col),
663 }))
664 }
665
666 fn as_any(&self) -> &dyn std::any::Any {
667 self
668 }
669}
670
671impl<T> fmt::Debug for LilArray<T>
672where
673 T: Float
674 + Add<Output = T>
675 + Sub<Output = T>
676 + Mul<Output = T>
677 + Div<Output = T>
678 + Debug
679 + Copy
680 + 'static,
681{
682 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
683 write!(
684 f,
685 "LilArray<{}x{}, nnz={}>",
686 self.shape.0,
687 self.shape.1,
688 self.nnz()
689 )
690 }
691}
692
693#[cfg(test)]
694mod tests {
695 use super::*;
696 use approx::assert_relative_eq;
697
698 #[test]
699 fn test_lil_array_construction() {
700 let shape = (3, 3);
702 let lil = LilArray::<f64>::new(shape);
703
704 assert_eq!(lil.shape(), (3, 3));
705 assert_eq!(lil.nnz(), 0);
706
707 let data = vec![vec![1.0, 2.0], vec![3.0], vec![4.0, 5.0]];
709 let indices = vec![vec![0, 2], vec![1], vec![0, 1]];
710
711 let lil = LilArray::from_lists(data, indices, shape).unwrap();
712
713 assert_eq!(lil.shape(), (3, 3));
714 assert_eq!(lil.nnz(), 5);
715 assert_eq!(lil.get(0, 0), 1.0);
716 assert_eq!(lil.get(0, 2), 2.0);
717 assert_eq!(lil.get(1, 1), 3.0);
718 assert_eq!(lil.get(2, 0), 4.0);
719 assert_eq!(lil.get(2, 1), 5.0);
720 assert_eq!(lil.get(0, 1), 0.0);
721 }
722
723 #[test]
724 fn test_lil_from_triplets() {
725 let rows = vec![0, 0, 1, 2, 2];
726 let cols = vec![0, 2, 1, 0, 1];
727 let data = vec![1.0, 2.0, 3.0, 4.0, 5.0];
728 let shape = (3, 3);
729
730 let lil = LilArray::from_triplets(&rows, &cols, &data, shape).unwrap();
731
732 assert_eq!(lil.shape(), (3, 3));
733 assert_eq!(lil.nnz(), 5);
734 assert_eq!(lil.get(0, 0), 1.0);
735 assert_eq!(lil.get(0, 2), 2.0);
736 assert_eq!(lil.get(1, 1), 3.0);
737 assert_eq!(lil.get(2, 0), 4.0);
738 assert_eq!(lil.get(2, 1), 5.0);
739 assert_eq!(lil.get(0, 1), 0.0);
740 }
741
742 #[test]
743 fn test_lil_array_to_array() {
744 let rows = vec![0, 0, 1, 2, 2];
745 let cols = vec![0, 2, 1, 0, 1];
746 let data = vec![1.0, 2.0, 3.0, 4.0, 5.0];
747 let shape = (3, 3);
748
749 let lil = LilArray::from_triplets(&rows, &cols, &data, shape).unwrap();
750 let dense = lil.to_array();
751
752 assert_eq!(dense.shape(), &[3, 3]);
753 assert_eq!(dense[[0, 0]], 1.0);
754 assert_eq!(dense[[0, 1]], 0.0);
755 assert_eq!(dense[[0, 2]], 2.0);
756 assert_eq!(dense[[1, 0]], 0.0);
757 assert_eq!(dense[[1, 1]], 3.0);
758 assert_eq!(dense[[1, 2]], 0.0);
759 assert_eq!(dense[[2, 0]], 4.0);
760 assert_eq!(dense[[2, 1]], 5.0);
761 assert_eq!(dense[[2, 2]], 0.0);
762 }
763
764 #[test]
765 fn test_lil_set_get() {
766 let mut lil = LilArray::<f64>::new((3, 3));
767
768 lil.set(0, 0, 1.0).unwrap();
770 lil.set(0, 2, 2.0).unwrap();
771 lil.set(1, 1, 3.0).unwrap();
772 lil.set(2, 0, 4.0).unwrap();
773 lil.set(2, 1, 5.0).unwrap();
774
775 assert_eq!(lil.get(0, 0), 1.0);
777 assert_eq!(lil.get(0, 2), 2.0);
778 assert_eq!(lil.get(1, 1), 3.0);
779 assert_eq!(lil.get(2, 0), 4.0);
780 assert_eq!(lil.get(2, 1), 5.0);
781 assert_eq!(lil.get(0, 1), 0.0);
782
783 lil.set(0, 0, 6.0).unwrap();
785 assert_eq!(lil.get(0, 0), 6.0);
786
787 lil.set(0, 0, 0.0).unwrap();
789 assert_eq!(lil.get(0, 0), 0.0);
790 assert_eq!(lil.nnz(), 4);
791 }
792
793 #[test]
794 fn test_lil_to_csr() {
795 let rows = vec![0, 0, 1, 2, 2];
796 let cols = vec![0, 2, 1, 0, 1];
797 let data = vec![1.0, 2.0, 3.0, 4.0, 5.0];
798 let shape = (3, 3);
799
800 let lil = LilArray::from_triplets(&rows, &cols, &data, shape).unwrap();
801
802 let csr = lil.to_csr().unwrap();
804
805 let dense = csr.to_array();
807 assert_eq!(dense[[0, 0]], 1.0);
808 assert_eq!(dense[[0, 1]], 0.0);
809 assert_eq!(dense[[0, 2]], 2.0);
810 assert_eq!(dense[[1, 0]], 0.0);
811 assert_eq!(dense[[1, 1]], 3.0);
812 assert_eq!(dense[[1, 2]], 0.0);
813 assert_eq!(dense[[2, 0]], 4.0);
814 assert_eq!(dense[[2, 1]], 5.0);
815 assert_eq!(dense[[2, 2]], 0.0);
816 }
817
818 #[test]
819 fn test_lil_to_coo() {
820 let rows = vec![0, 0, 1, 2, 2];
821 let cols = vec![0, 2, 1, 0, 1];
822 let data = vec![1.0, 2.0, 3.0, 4.0, 5.0];
823 let shape = (3, 3);
824
825 let lil = LilArray::from_triplets(&rows, &cols, &data, shape).unwrap();
826
827 let coo = lil.to_coo().unwrap();
829
830 let dense = coo.to_array();
832 assert_eq!(dense[[0, 0]], 1.0);
833 assert_eq!(dense[[0, 1]], 0.0);
834 assert_eq!(dense[[0, 2]], 2.0);
835 assert_eq!(dense[[1, 0]], 0.0);
836 assert_eq!(dense[[1, 1]], 3.0);
837 assert_eq!(dense[[1, 2]], 0.0);
838 assert_eq!(dense[[2, 0]], 4.0);
839 assert_eq!(dense[[2, 1]], 5.0);
840 assert_eq!(dense[[2, 2]], 0.0);
841 }
842
843 #[test]
844 fn test_lil_dot_vector() {
845 let rows = vec![0, 0, 1, 2, 2];
846 let cols = vec![0, 2, 1, 0, 1];
847 let data = vec![1.0, 2.0, 3.0, 4.0, 5.0];
848 let shape = (3, 3);
849
850 let lil = LilArray::from_triplets(&rows, &cols, &data, shape).unwrap();
851
852 let vector = Array1::from_vec(vec![1.0, 2.0, 3.0]);
854
855 let result = lil.dot_vector(&vector.view()).unwrap();
857
858 assert_eq!(result.len(), 3);
862 assert_relative_eq!(result[0], 7.0, epsilon = 1e-10);
863 assert_relative_eq!(result[1], 6.0, epsilon = 1e-10);
864 assert_relative_eq!(result[2], 14.0, epsilon = 1e-10);
865 }
866
867 #[test]
868 fn test_lil_eliminate_zeros() {
869 let mut lil = LilArray::<f64>::new((2, 2));
870
871 lil.set(0, 0, 1.0).unwrap();
872 lil.set(0, 1, 0.0).unwrap(); lil.set(1, 0, 2.0).unwrap();
874 lil.set(1, 1, 3.0).unwrap();
875
876 lil.set(0, 1, 4.0).unwrap();
878 lil.set(0, 1, 0.0).unwrap();
879
880 lil.data[1][0] = 0.0;
882
883 assert_eq!(lil.nnz(), 3); lil.eliminate_zeros();
887
888 assert_eq!(lil.nnz(), 2); assert_eq!(lil.get(0, 0), 1.0);
890 assert_eq!(lil.get(1, 1), 3.0);
891 }
892
893 #[test]
894 fn test_lil_sort_indices() {
895 let mut lil = LilArray::<f64>::new((2, 4));
897
898 lil.set(0, 3, 1.0).unwrap();
900 lil.set(0, 1, 2.0).unwrap();
901 lil.set(1, 2, 3.0).unwrap();
902 lil.set(1, 0, 4.0).unwrap();
903
904 if lil.data[0].len() >= 2 {
907 lil.data[0].swap(0, 1);
908 lil.indices[0].swap(0, 1);
909 }
910
911 assert!(!lil.has_sorted_indices());
913
914 lil.sort_indices();
916
917 assert!(lil.has_sorted_indices());
919
920 assert_eq!(lil.get(0, 1), 2.0);
922 assert_eq!(lil.get(0, 3), 1.0);
923 assert_eq!(lil.get(1, 0), 4.0);
924 assert_eq!(lil.get(1, 2), 3.0);
925
926 assert_eq!(lil.indices[0][0], 1);
928 assert_eq!(lil.indices[0][1], 3);
929 assert_eq!(lil.data[0][0], 2.0);
930 assert_eq!(lil.data[0][1], 1.0);
931
932 assert_eq!(lil.indices[1][0], 0);
933 assert_eq!(lil.indices[1][1], 2);
934 assert_eq!(lil.data[1][0], 4.0);
935 assert_eq!(lil.data[1][1], 3.0);
936 }
937
938 #[test]
939 fn test_lil_slice() {
940 let rows = vec![0, 0, 1, 2, 2];
941 let cols = vec![0, 2, 1, 0, 1];
942 let data = vec![1.0, 2.0, 3.0, 4.0, 5.0];
943 let shape = (3, 3);
944
945 let lil = LilArray::from_triplets(&rows, &cols, &data, shape).unwrap();
946
947 let slice = lil.slice((1, 3), (0, 2)).unwrap();
949
950 assert_eq!(slice.shape(), (2, 2));
952
953 assert_eq!(slice.get(0, 1), 3.0);
955 assert_eq!(slice.get(1, 0), 4.0);
956 assert_eq!(slice.get(1, 1), 5.0);
957 assert_eq!(slice.get(0, 0), 0.0);
958 }
959}