1use scirs2_core::ndarray::{Array1, Array2, ArrayView1};
7use scirs2_core::numeric::{Float, SparseElement};
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: SparseElement + Div<Output = T> + Float + 'static,
34{
35 data: Vec<Vec<T>>,
37 indices: Vec<Vec<usize>>,
39 shape: (usize, usize),
41}
42
43impl<T> LilArray<T>
44where
45 T: SparseElement + Div<Output = T> + Float + 'static,
46{
47 pub fn new(shape: (usize, usize)) -> Self {
55 let (rows, cols) = shape;
56 let data = vec![Vec::new(); rows];
57 let indices = vec![Vec::new(); rows];
58
59 Self {
60 data,
61 indices,
62 shape,
63 }
64 }
65
66 pub fn from_lists(
79 data: Vec<Vec<T>>,
80 indices: Vec<Vec<usize>>,
81 shape: (usize, usize),
82 ) -> SparseResult<Self> {
83 if data.len() != shape.0 || indices.len() != shape.0 {
85 return Err(SparseError::InconsistentData {
86 reason: "Number of rows in data and indices must match the shape".to_string(),
87 });
88 }
89
90 for (i, (row_data, row_indices)) in data.iter().zip(indices.iter()).enumerate() {
91 if row_data.len() != row_indices.len() {
92 return Err(SparseError::InconsistentData {
93 reason: format!("Row {i}: data and indices have different lengths"),
94 });
95 }
96
97 if let Some(&max_col) = row_indices.iter().max() {
98 if max_col >= shape.1 {
99 return Err(SparseError::IndexOutOfBounds {
100 index: (i, max_col),
101 shape,
102 });
103 }
104 }
105 }
106
107 let mut new_data = Vec::with_capacity(shape.0);
109 let mut new_indices = Vec::with_capacity(shape.0);
110
111 for (row_data, row_indices) in data.iter().zip(indices.iter()) {
112 let mut pairs: Vec<(usize, T)> = row_indices
114 .iter()
115 .copied()
116 .zip(row_data.iter().copied())
117 .collect();
118 pairs.sort_by_key(|&(idx_, _)| idx_);
119
120 let mut sorted_data = Vec::with_capacity(row_data.len());
122 let mut sorted_indices = Vec::with_capacity(row_indices.len());
123
124 for (idx, val) in pairs {
125 sorted_indices.push(idx);
126 sorted_data.push(val);
127 }
128
129 new_data.push(sorted_data);
130 new_indices.push(sorted_indices);
131 }
132
133 Ok(Self {
134 data: new_data,
135 indices: new_indices,
136 shape,
137 })
138 }
139
140 pub fn from_triplets(
154 rows: &[usize],
155 cols: &[usize],
156 data: &[T],
157 shape: (usize, usize),
158 ) -> SparseResult<Self> {
159 if rows.len() != cols.len() || rows.len() != data.len() {
160 return Err(SparseError::InconsistentData {
161 reason: "rows, cols, and data must have the same length".to_string(),
162 });
163 }
164
165 let (num_rows, num_cols) = shape;
166
167 if let Some(&max_row) = rows.iter().max() {
169 if max_row >= num_rows {
170 return Err(SparseError::IndexOutOfBounds {
171 index: (max_row, 0),
172 shape,
173 });
174 }
175 }
176
177 if let Some(&max_col) = cols.iter().max() {
178 if max_col >= num_cols {
179 return Err(SparseError::IndexOutOfBounds {
180 index: (0, max_col),
181 shape,
182 });
183 }
184 }
185
186 let mut lil = LilArray::new(shape);
188
189 for (&row, &col, &value) in rows
191 .iter()
192 .zip(cols.iter())
193 .zip(data.iter())
194 .map(|((r, c), d)| (r, c, d))
195 {
196 lil.set(row, col, value)?;
197 }
198
199 Ok(lil)
200 }
201
202 pub fn get_data(&self) -> &Vec<Vec<T>> {
204 &self.data
205 }
206
207 pub fn get_indices(&self) -> &Vec<Vec<usize>> {
209 &self.indices
210 }
211
212 pub fn sort_indices(&mut self) {
214 for row in 0..self.shape.0 {
215 if !self.data[row].is_empty() {
216 let mut pairs: Vec<(usize, T)> = self.indices[row]
218 .iter()
219 .copied()
220 .zip(self.data[row].iter().copied())
221 .collect();
222
223 pairs.sort_by_key(|&(idx_, _)| idx_);
225
226 self.indices[row].clear();
228 self.data[row].clear();
229
230 for (idx, val) in pairs {
231 self.indices[row].push(idx);
232 self.data[row].push(val);
233 }
234 }
235 }
236 }
237}
238
239impl<T> SparseArray<T> for LilArray<T>
240where
241 T: SparseElement + Div<Output = T> + Float + 'static,
242{
243 fn shape(&self) -> (usize, usize) {
244 self.shape
245 }
246
247 fn nnz(&self) -> usize {
248 self.indices.iter().map(|row| row.len()).sum()
249 }
250
251 fn dtype(&self) -> &str {
252 "float" }
254
255 fn to_array(&self) -> Array2<T> {
256 let (rows, cols) = self.shape;
257 let mut result = Array2::zeros((rows, cols));
258
259 for row in 0..rows {
260 for (idx, &col) in self.indices[row].iter().enumerate() {
261 result[[row, col]] = self.data[row][idx];
262 }
263 }
264
265 result
266 }
267
268 fn toarray(&self) -> Array2<T> {
269 self.to_array()
270 }
271
272 fn to_coo(&self) -> SparseResult<Box<dyn SparseArray<T>>> {
273 let nnz = self.nnz();
274 let mut row_indices = Vec::with_capacity(nnz);
275 let mut col_indices = Vec::with_capacity(nnz);
276 let mut values = Vec::with_capacity(nnz);
277
278 for row in 0..self.shape.0 {
279 for (idx, &col) in self.indices[row].iter().enumerate() {
280 row_indices.push(row);
281 col_indices.push(col);
282 values.push(self.data[row][idx]);
283 }
284 }
285
286 CooArray::from_triplets(&row_indices, &col_indices, &values, self.shape, false)
287 .map(|array| Box::new(array) as Box<dyn SparseArray<T>>)
288 }
289
290 fn to_csr(&self) -> SparseResult<Box<dyn SparseArray<T>>> {
291 let (rows, cols) = self.shape;
292 let nnz = self.nnz();
293
294 let mut data = Vec::with_capacity(nnz);
295 let mut indices = Vec::with_capacity(nnz);
296 let mut indptr = Vec::with_capacity(rows + 1);
297
298 indptr.push(0);
299
300 for row in 0..rows {
301 for (idx, &col) in self.indices[row].iter().enumerate() {
302 indices.push(col);
303 data.push(self.data[row][idx]);
304 }
305 indptr.push(indptr.last().unwrap() + self.indices[row].len());
306 }
307
308 CsrArray::new(
309 Array1::from_vec(data),
310 Array1::from_vec(indices),
311 Array1::from_vec(indptr),
312 self.shape,
313 )
314 .map(|array| Box::new(array) as Box<dyn SparseArray<T>>)
315 }
316
317 fn to_csc(&self) -> SparseResult<Box<dyn SparseArray<T>>> {
318 self.to_coo()?.to_csc()
320 }
321
322 fn to_dok(&self) -> SparseResult<Box<dyn SparseArray<T>>> {
323 self.to_coo()?.to_dok()
325 }
326
327 fn to_lil(&self) -> SparseResult<Box<dyn SparseArray<T>>> {
328 Ok(Box::new(self.clone()))
329 }
330
331 fn to_dia(&self) -> SparseResult<Box<dyn SparseArray<T>>> {
332 self.to_coo()?.to_dia()
334 }
335
336 fn to_bsr(&self) -> SparseResult<Box<dyn SparseArray<T>>> {
337 self.to_coo()?.to_bsr()
339 }
340
341 fn add(&self, other: &dyn SparseArray<T>) -> SparseResult<Box<dyn SparseArray<T>>> {
342 let self_csr = self.to_csr()?;
344 self_csr.add(other)
345 }
346
347 fn sub(&self, other: &dyn SparseArray<T>) -> SparseResult<Box<dyn SparseArray<T>>> {
348 let self_csr = self.to_csr()?;
350 self_csr.sub(other)
351 }
352
353 fn mul(&self, other: &dyn SparseArray<T>) -> SparseResult<Box<dyn SparseArray<T>>> {
354 let self_csr = self.to_csr()?;
356 self_csr.mul(other)
357 }
358
359 fn div(&self, other: &dyn SparseArray<T>) -> SparseResult<Box<dyn SparseArray<T>>> {
360 let self_csr = self.to_csr()?;
362 self_csr.div(other)
363 }
364
365 fn dot(&self, other: &dyn SparseArray<T>) -> SparseResult<Box<dyn SparseArray<T>>> {
366 let self_csr = self.to_csr()?;
368 self_csr.dot(other)
369 }
370
371 fn dot_vector(&self, other: &ArrayView1<T>) -> SparseResult<Array1<T>> {
372 let (rows, cols) = self.shape;
373 if cols != other.len() {
374 return Err(SparseError::DimensionMismatch {
375 expected: cols,
376 found: other.len(),
377 });
378 }
379
380 let mut result = Array1::zeros(rows);
381
382 for row in 0..rows {
383 for (idx, &col) in self.indices[row].iter().enumerate() {
384 result[row] = result[row] + self.data[row][idx] * other[col];
385 }
386 }
387
388 Ok(result)
389 }
390
391 fn transpose(&self) -> SparseResult<Box<dyn SparseArray<T>>> {
392 self.to_coo()?.transpose()
395 }
396
397 fn copy(&self) -> Box<dyn SparseArray<T>> {
398 Box::new(self.clone())
399 }
400
401 fn get(&self, i: usize, j: usize) -> T {
402 if i >= self.shape.0 || j >= self.shape.1 {
403 return T::sparse_zero();
404 }
405
406 match self.indices[i].binary_search(&j) {
407 Ok(pos) => self.data[i][pos],
408 Err(_) => T::sparse_zero(),
409 }
410 }
411
412 fn set(&mut self, i: usize, j: usize, value: T) -> SparseResult<()> {
413 if i >= self.shape.0 || j >= self.shape.1 {
414 return Err(SparseError::IndexOutOfBounds {
415 index: (i, j),
416 shape: self.shape,
417 });
418 }
419
420 match self.indices[i].binary_search(&j) {
421 Ok(pos) => {
422 if SparseElement::is_zero(&value) {
423 self.data[i].remove(pos);
425 self.indices[i].remove(pos);
426 } else {
427 self.data[i][pos] = value;
429 }
430 }
431 Err(pos) => {
432 if !SparseElement::is_zero(&value) {
433 self.data[i].insert(pos, value);
435 self.indices[i].insert(pos, j);
436 }
437 }
438 }
439
440 Ok(())
441 }
442
443 fn eliminate_zeros(&mut self) {
444 for row in 0..self.shape.0 {
445 let mut new_data = Vec::new();
446 let mut new_indices = Vec::new();
447
448 for (idx, &value) in self.data[row].iter().enumerate() {
449 if !SparseElement::is_zero(&value) {
450 new_data.push(value);
451 new_indices.push(self.indices[row][idx]);
452 }
453 }
454
455 self.data[row] = new_data;
456 self.indices[row] = new_indices;
457 }
458 }
459
460 fn sort_indices(&mut self) {
461 LilArray::sort_indices(self);
463 }
464
465 fn sorted_indices(&self) -> Box<dyn SparseArray<T>> {
466 let mut sorted = self.clone();
467 sorted.sort_indices();
468 Box::new(sorted)
469 }
470
471 fn has_sorted_indices(&self) -> bool {
472 for row in 0..self.shape.0 {
474 if self.indices[row].len() > 1 {
475 for i in 1..self.indices[row].len() {
476 if self.indices[row][i - 1] >= self.indices[row][i] {
477 return false;
478 }
479 }
480 }
481 }
482 true
483 }
484
485 fn sum(&self, axis: Option<usize>) -> SparseResult<SparseSum<T>> {
486 match axis {
487 None => {
488 let mut sum = T::sparse_zero();
490 for row in 0..self.shape.0 {
491 for &val in self.data[row].iter() {
492 sum = sum + val;
493 }
494 }
495 Ok(SparseSum::Scalar(sum))
496 }
497 Some(0) => {
498 let (_, cols) = self.shape;
500 let mut result = Array1::<T>::zeros(cols);
501
502 for row in 0..self.shape.0 {
503 for (idx, &col) in self.indices[row].iter().enumerate() {
504 result[col] = result[col] + self.data[row][idx];
505 }
506 }
507
508 let mut lil = LilArray::new((1, cols));
510 for (col, &val) in result.iter().enumerate() {
511 if !SparseElement::is_zero(&val) {
512 lil.set(0, col, val)?;
513 }
514 }
515
516 Ok(SparseSum::SparseArray(Box::new(lil)))
517 }
518 Some(1) => {
519 let (rows, _) = self.shape;
521 let mut result = Array1::<T>::zeros(rows);
522
523 for row in 0..rows {
524 for &val in self.data[row].iter() {
525 result[row] = result[row] + val;
526 }
527 }
528
529 let mut lil = LilArray::new((rows, 1));
531 for (row, &val) in result.iter().enumerate() {
532 if !SparseElement::is_zero(&val) {
533 lil.set(row, 0, val)?;
534 }
535 }
536
537 Ok(SparseSum::SparseArray(Box::new(lil)))
538 }
539 _ => Err(SparseError::InvalidAxis),
540 }
541 }
542
543 fn max(&self) -> T {
544 if self.nnz() == 0 {
545 return T::sparse_zero();
547 }
548
549 let mut max_val = T::sparse_zero();
551 let mut found_value = false;
552 for row in 0..self.shape.0 {
553 for &val in self.data[row].iter() {
554 if !found_value {
555 max_val = val;
556 found_value = true;
557 } else if val > max_val {
558 max_val = val;
559 }
560 }
561 }
562
563 let zero = T::sparse_zero();
565 if max_val < zero && self.nnz() < self.shape.0 * self.shape.1 {
566 zero
567 } else {
568 max_val
569 }
570 }
571
572 fn min(&self) -> T {
573 if self.nnz() == 0 {
574 return T::sparse_zero();
575 }
576
577 let mut min_val = T::sparse_zero();
578 for row in 0..self.shape.0 {
579 for &val in self.data[row].iter() {
580 if val < min_val {
581 min_val = val;
582 }
583 }
584 }
585
586 if min_val > T::sparse_zero() && self.nnz() < self.shape.0 * self.shape.1 {
588 T::sparse_zero()
589 } else {
590 min_val
591 }
592 }
593
594 fn find(&self) -> (Array1<usize>, Array1<usize>, Array1<T>) {
595 let nnz = self.nnz();
596 let mut rows = Vec::with_capacity(nnz);
597 let mut cols = Vec::with_capacity(nnz);
598 let mut values = Vec::with_capacity(nnz);
599
600 for row in 0..self.shape.0 {
601 for (idx, &col) in self.indices[row].iter().enumerate() {
602 rows.push(row);
603 cols.push(col);
604 values.push(self.data[row][idx]);
605 }
606 }
607
608 (
609 Array1::from_vec(rows),
610 Array1::from_vec(cols),
611 Array1::from_vec(values),
612 )
613 }
614
615 fn slice(
616 &self,
617 row_range: (usize, usize),
618 col_range: (usize, usize),
619 ) -> SparseResult<Box<dyn SparseArray<T>>> {
620 let (start_row, end_row) = row_range;
621 let (start_col, end_col) = col_range;
622
623 if start_row >= self.shape.0
624 || end_row > self.shape.0
625 || start_col >= self.shape.1
626 || end_col > self.shape.1
627 || start_row >= end_row
628 || start_col >= end_col
629 {
630 return Err(SparseError::InvalidSliceRange);
631 }
632
633 let mut new_data = vec![Vec::new(); end_row - start_row];
634 let mut new_indices = vec![Vec::new(); end_row - start_row];
635
636 for row in start_row..end_row {
637 for (idx, &col) in self.indices[row].iter().enumerate() {
638 if col >= start_col && col < end_col {
639 new_data[row - start_row].push(self.data[row][idx]);
640 new_indices[row - start_row].push(col - start_col);
641 }
642 }
643 }
644
645 Ok(Box::new(LilArray {
646 data: new_data,
647 indices: new_indices,
648 shape: (end_row - start_row, end_col - start_col),
649 }))
650 }
651
652 fn as_any(&self) -> &dyn std::any::Any {
653 self
654 }
655}
656
657impl<T> fmt::Debug for LilArray<T>
658where
659 T: SparseElement + Div<Output = T> + Float + 'static,
660{
661 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
662 write!(
663 f,
664 "LilArray<{}x{}, nnz={}>",
665 self.shape.0,
666 self.shape.1,
667 self.nnz()
668 )
669 }
670}
671
672#[cfg(test)]
673mod tests {
674 use super::*;
675 use approx::assert_relative_eq;
676
677 #[test]
678 fn test_lil_array_construction() {
679 let shape = (3, 3);
681 let lil = LilArray::<f64>::new(shape);
682
683 assert_eq!(lil.shape(), (3, 3));
684 assert_eq!(lil.nnz(), 0);
685
686 let data = vec![vec![1.0, 2.0], vec![3.0], vec![4.0, 5.0]];
688 let indices = vec![vec![0, 2], vec![1], vec![0, 1]];
689
690 let lil = LilArray::from_lists(data, indices, shape).unwrap();
691
692 assert_eq!(lil.shape(), (3, 3));
693 assert_eq!(lil.nnz(), 5);
694 assert_eq!(lil.get(0, 0), 1.0);
695 assert_eq!(lil.get(0, 2), 2.0);
696 assert_eq!(lil.get(1, 1), 3.0);
697 assert_eq!(lil.get(2, 0), 4.0);
698 assert_eq!(lil.get(2, 1), 5.0);
699 assert_eq!(lil.get(0, 1), 0.0);
700 }
701
702 #[test]
703 fn test_lil_from_triplets() {
704 let rows = vec![0, 0, 1, 2, 2];
705 let cols = vec![0, 2, 1, 0, 1];
706 let data = vec![1.0, 2.0, 3.0, 4.0, 5.0];
707 let shape = (3, 3);
708
709 let lil = LilArray::from_triplets(&rows, &cols, &data, shape).unwrap();
710
711 assert_eq!(lil.shape(), (3, 3));
712 assert_eq!(lil.nnz(), 5);
713 assert_eq!(lil.get(0, 0), 1.0);
714 assert_eq!(lil.get(0, 2), 2.0);
715 assert_eq!(lil.get(1, 1), 3.0);
716 assert_eq!(lil.get(2, 0), 4.0);
717 assert_eq!(lil.get(2, 1), 5.0);
718 assert_eq!(lil.get(0, 1), 0.0);
719 }
720
721 #[test]
722 fn test_lil_array_to_array() {
723 let rows = vec![0, 0, 1, 2, 2];
724 let cols = vec![0, 2, 1, 0, 1];
725 let data = vec![1.0, 2.0, 3.0, 4.0, 5.0];
726 let shape = (3, 3);
727
728 let lil = LilArray::from_triplets(&rows, &cols, &data, shape).unwrap();
729 let dense = lil.to_array();
730
731 assert_eq!(dense.shape(), &[3, 3]);
732 assert_eq!(dense[[0, 0]], 1.0);
733 assert_eq!(dense[[0, 1]], 0.0);
734 assert_eq!(dense[[0, 2]], 2.0);
735 assert_eq!(dense[[1, 0]], 0.0);
736 assert_eq!(dense[[1, 1]], 3.0);
737 assert_eq!(dense[[1, 2]], 0.0);
738 assert_eq!(dense[[2, 0]], 4.0);
739 assert_eq!(dense[[2, 1]], 5.0);
740 assert_eq!(dense[[2, 2]], 0.0);
741 }
742
743 #[test]
744 fn test_lil_set_get() {
745 let mut lil = LilArray::<f64>::new((3, 3));
746
747 lil.set(0, 0, 1.0).unwrap();
749 lil.set(0, 2, 2.0).unwrap();
750 lil.set(1, 1, 3.0).unwrap();
751 lil.set(2, 0, 4.0).unwrap();
752 lil.set(2, 1, 5.0).unwrap();
753
754 assert_eq!(lil.get(0, 0), 1.0);
756 assert_eq!(lil.get(0, 2), 2.0);
757 assert_eq!(lil.get(1, 1), 3.0);
758 assert_eq!(lil.get(2, 0), 4.0);
759 assert_eq!(lil.get(2, 1), 5.0);
760 assert_eq!(lil.get(0, 1), 0.0);
761
762 lil.set(0, 0, 6.0).unwrap();
764 assert_eq!(lil.get(0, 0), 6.0);
765
766 lil.set(0, 0, 0.0).unwrap();
768 assert_eq!(lil.get(0, 0), 0.0);
769 assert_eq!(lil.nnz(), 4);
770 }
771
772 #[test]
773 fn test_lil_to_csr() {
774 let rows = vec![0, 0, 1, 2, 2];
775 let cols = vec![0, 2, 1, 0, 1];
776 let data = vec![1.0, 2.0, 3.0, 4.0, 5.0];
777 let shape = (3, 3);
778
779 let lil = LilArray::from_triplets(&rows, &cols, &data, shape).unwrap();
780
781 let csr = lil.to_csr().unwrap();
783
784 let dense = csr.to_array();
786 assert_eq!(dense[[0, 0]], 1.0);
787 assert_eq!(dense[[0, 1]], 0.0);
788 assert_eq!(dense[[0, 2]], 2.0);
789 assert_eq!(dense[[1, 0]], 0.0);
790 assert_eq!(dense[[1, 1]], 3.0);
791 assert_eq!(dense[[1, 2]], 0.0);
792 assert_eq!(dense[[2, 0]], 4.0);
793 assert_eq!(dense[[2, 1]], 5.0);
794 assert_eq!(dense[[2, 2]], 0.0);
795 }
796
797 #[test]
798 fn test_lil_to_coo() {
799 let rows = vec![0, 0, 1, 2, 2];
800 let cols = vec![0, 2, 1, 0, 1];
801 let data = vec![1.0, 2.0, 3.0, 4.0, 5.0];
802 let shape = (3, 3);
803
804 let lil = LilArray::from_triplets(&rows, &cols, &data, shape).unwrap();
805
806 let coo = lil.to_coo().unwrap();
808
809 let dense = coo.to_array();
811 assert_eq!(dense[[0, 0]], 1.0);
812 assert_eq!(dense[[0, 1]], 0.0);
813 assert_eq!(dense[[0, 2]], 2.0);
814 assert_eq!(dense[[1, 0]], 0.0);
815 assert_eq!(dense[[1, 1]], 3.0);
816 assert_eq!(dense[[1, 2]], 0.0);
817 assert_eq!(dense[[2, 0]], 4.0);
818 assert_eq!(dense[[2, 1]], 5.0);
819 assert_eq!(dense[[2, 2]], 0.0);
820 }
821
822 #[test]
823 fn test_lil_dot_vector() {
824 let rows = vec![0, 0, 1, 2, 2];
825 let cols = vec![0, 2, 1, 0, 1];
826 let data = vec![1.0, 2.0, 3.0, 4.0, 5.0];
827 let shape = (3, 3);
828
829 let lil = LilArray::from_triplets(&rows, &cols, &data, shape).unwrap();
830
831 let vector = Array1::from_vec(vec![1.0, 2.0, 3.0]);
833
834 let result = lil.dot_vector(&vector.view()).unwrap();
836
837 assert_eq!(result.len(), 3);
841 assert_relative_eq!(result[0], 7.0, epsilon = 1e-10);
842 assert_relative_eq!(result[1], 6.0, epsilon = 1e-10);
843 assert_relative_eq!(result[2], 14.0, epsilon = 1e-10);
844 }
845
846 #[test]
847 fn test_lil_eliminate_zeros() {
848 let mut lil = LilArray::<f64>::new((2, 2));
849
850 lil.set(0, 0, 1.0).unwrap();
851 lil.set(0, 1, 0.0).unwrap(); lil.set(1, 0, 2.0).unwrap();
853 lil.set(1, 1, 3.0).unwrap();
854
855 lil.set(0, 1, 4.0).unwrap();
857 lil.set(0, 1, 0.0).unwrap();
858
859 lil.data[1][0] = 0.0;
861
862 assert_eq!(lil.nnz(), 3); lil.eliminate_zeros();
866
867 assert_eq!(lil.nnz(), 2); assert_eq!(lil.get(0, 0), 1.0);
869 assert_eq!(lil.get(1, 1), 3.0);
870 }
871
872 #[test]
873 fn test_lil_sort_indices() {
874 let mut lil = LilArray::<f64>::new((2, 4));
876
877 lil.set(0, 3, 1.0).unwrap();
879 lil.set(0, 1, 2.0).unwrap();
880 lil.set(1, 2, 3.0).unwrap();
881 lil.set(1, 0, 4.0).unwrap();
882
883 if lil.data[0].len() >= 2 {
886 lil.data[0].swap(0, 1);
887 lil.indices[0].swap(0, 1);
888 }
889
890 assert!(!lil.has_sorted_indices());
892
893 lil.sort_indices();
895
896 assert!(lil.has_sorted_indices());
898
899 assert_eq!(lil.get(0, 1), 2.0);
901 assert_eq!(lil.get(0, 3), 1.0);
902 assert_eq!(lil.get(1, 0), 4.0);
903 assert_eq!(lil.get(1, 2), 3.0);
904
905 assert_eq!(lil.indices[0][0], 1);
907 assert_eq!(lil.indices[0][1], 3);
908 assert_eq!(lil.data[0][0], 2.0);
909 assert_eq!(lil.data[0][1], 1.0);
910
911 assert_eq!(lil.indices[1][0], 0);
912 assert_eq!(lil.indices[1][1], 2);
913 assert_eq!(lil.data[1][0], 4.0);
914 assert_eq!(lil.data[1][1], 3.0);
915 }
916
917 #[test]
918 fn test_lil_slice() {
919 let rows = vec![0, 0, 1, 2, 2];
920 let cols = vec![0, 2, 1, 0, 1];
921 let data = vec![1.0, 2.0, 3.0, 4.0, 5.0];
922 let shape = (3, 3);
923
924 let lil = LilArray::from_triplets(&rows, &cols, &data, shape).unwrap();
925
926 let slice = lil.slice((1, 3), (0, 2)).unwrap();
928
929 assert_eq!(slice.shape(), (2, 2));
931
932 assert_eq!(slice.get(0, 1), 3.0);
934 assert_eq!(slice.get(1, 0), 4.0);
935 assert_eq!(slice.get(1, 1), 5.0);
936 assert_eq!(slice.get(0, 0), 0.0);
937 }
938}