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<N> ArrayAdapter<N::Elem> for ndarray::ArrayBase<N, ndarray::Ix2>
where
	N: ndarray::Data,
	N::Elem: 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::Elem {
		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) = 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(),
		}
	}
}