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
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
use crate::{DiffusionMap, ReductionError};
use linfa::{param_guard::TransformGuard, ParamGuard};

/// Diffusion map hyperparameters
///
/// The diffusion map algorithms has only two explicit hyperparameter. The first is the stepsize.
/// As the algorithm calculates the closeness of points after a number of steps taken in the
/// diffusion graph, a larger step size introduces a more global behaviour of the projection while
/// a smaller one (especially one) just projects close obserations closely together.
/// The second parameter is the embedding size and defines the target dimensionality.
pub struct DiffusionMapValidParams {
    steps: usize,
    embedding_size: usize,
}

impl DiffusionMapValidParams {
    pub fn steps(&self) -> usize {
        self.steps
    }

    pub fn embedding_size(&self) -> usize {
        self.embedding_size
    }
}

/// Diffusion map hyperparameters
///
/// The diffusion map algorithms has only two explicit hyperparameter. The first is the stepsize.
/// As the algorithm calculates the closeness of points after a number of steps taken in the
/// diffusion graph, a larger step size introduces a more global behaviour of the projection while
/// a smaller one (especially one) just projects close obserations closely together.
/// The second parameter is the embedding size and defines the target dimensionality.
pub struct DiffusionMapParams(DiffusionMapValidParams);

impl DiffusionMapParams {
    /// Set the number of steps in the diffusion operator
    ///
    /// The diffusion map algorithm expresses the transition probability with a kernel matrix and
    /// then takes multiple steps along the diffusion operator. In practice scales the
    /// eigenvalues of the decomposition exponentially with the number of steps.
    pub fn steps(mut self, steps: usize) -> Self {
        self.0.steps = steps;

        self
    }

    pub fn embedding_size(mut self, embedding_size: usize) -> Self {
        self.0.embedding_size = embedding_size;

        self
    }

    /// Creates the set of default parameters
    ///
    /// # Parameters
    ///
    /// * `embedding_size`: the number of dimensions in the projection
    ///
    /// # Returns
    ///
    /// Parameter set with number of steps = 1
    pub fn new(embedding_size: usize) -> DiffusionMapParams {
        Self(DiffusionMapValidParams {
            steps: 1,
            embedding_size,
        })
    }
}

impl Default for DiffusionMapParams {
    fn default() -> Self {
        Self::new(2)
    }
}

impl<F> DiffusionMap<F> {
    pub fn params(embedding_size: usize) -> DiffusionMapParams {
        DiffusionMapParams::new(embedding_size)
    }
}

impl ParamGuard for DiffusionMapParams {
    type Checked = DiffusionMapValidParams;
    type Error = ReductionError;

    fn check_ref(&self) -> Result<&Self::Checked, Self::Error> {
        if self.0.steps == 0 {
            Err(ReductionError::StepsZero)
        } else if self.0.embedding_size == 0 {
            Err(ReductionError::EmbeddingTooSmall(self.0.embedding_size))
        } else {
            Ok(&self.0)
        }
    }

    fn check(self) -> Result<Self::Checked, Self::Error> {
        self.check_ref()?;
        Ok(self.0)
    }
}
impl TransformGuard for DiffusionMapParams {}