1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
//! Adapter trait for accessing different types of arrays.
//!
//! Includes adapters for `ndarray::Array2` and a serialized lower triangular matrix in a `Vec`.

/// Adapter trait for accessing different types of arrays
#[allow(clippy::len_without_is_empty)]
pub trait ArrayAdapter<N> {
	/// Get the length of an array structure
	fn len(&self) -> usize;
	/// Verify that it is a square matrix
	fn is_square(&self) -> bool;
	/// Get the contents at cell x,y
	fn get(&self, x: usize, y: usize) -> N;
}

/// Adapter trait for using `ndarray::Array2` and similar
#[cfg(feature = "ndarray")]
impl<A, N> ArrayAdapter<N> for ndarray::ArrayBase<A, ndarray::Ix2>
where
	A: ndarray::Data<Elem = N>,
	N: Copy,
{
	#[inline]
	fn len(&self) -> usize {
		self.shape()[0]
	}
	#[inline]
	fn is_square(&self) -> bool {
		self.shape()[0] == self.shape()[1]
	}
	#[inline]
	fn get(&self, x: usize, y: usize) -> N {
		self[[x, y]]
	}
}

/// Lower triangular matrix in serial form (without diagonal)
///
/// ## Example
/// ```
/// let data = kmedoids::arrayadapter::LowerTriangle { n: 4, data: vec![1, 2, 3, 4, 5, 6] };
/// let mut meds = vec![0, 1];
/// let (loss, numswap, numiter, assignment): (f64, _, _, _) = kmedoids::fasterpam(&data, &mut meds, 10);
/// println!("Loss is {}", loss);
/// ```
#[derive(Debug, Clone)]
pub struct LowerTriangle<N> {
	/// Matrix size
	pub n: usize,
	// Matrix data, lower triangular form without diagonal
	pub data: Vec<N>,
}
/// Adapter implementation for LowerTriangle
impl<N: Copy + num_traits::Zero> ArrayAdapter<N> for LowerTriangle<N> {
	#[inline]
	fn len(&self) -> usize {
		self.n
	}
	#[inline]
	fn is_square(&self) -> bool {
		self.data.len() == (self.n * (self.n - 1)) >> 1
	}
	#[inline]
	fn get(&self, x: usize, y: usize) -> N {
		match x.cmp(&y) {
			std::cmp::Ordering::Less => self.data[((y * (y - 1)) >> 1) + x],
			std::cmp::Ordering::Greater => self.data[((x * (x - 1)) >> 1) + y],
			std::cmp::Ordering::Equal => N::zero(),
		}
	}
}