pub use crate::{DMatrix, DVector};
#[derive(Debug)]
pub struct MarkovFlow {
pub adjacency_matrix: DMatrix<f64>,
pub dim: usize,
pub sink_matrix: DMatrix<f64>,
pub sensitivity_matrix: DMatrix<f64>,
pub influence_matrix: DMatrix<f64>,
pub origin_matrix: DMatrix<f64>,
pub dependency_matrix: DMatrix<f64>,
pub in_vector: DVector<f64>,
pub flow_vector: DVector<f64>,
pub flow_matrix: DMatrix<f64>,
}
impl MarkovFlow {
pub fn new(adj: &DMatrix<f64>, mu: f64, scale: bool) -> MarkovFlow {
let (rows, cols) = adj.shape();
if rows != cols {
panic!("Adjacency matrix has to be square.");
}
let mut adjacency_matrix = adj.map(|x: f64| if x < 0.0 { 0.0 } else { x });
adjacency_matrix.fill_diagonal(0.0);
let sink_matrix = get_sink_matrix(&adjacency_matrix, mu);
let sensitivity_matrix = get_sensitivity_matrix(&sink_matrix);
let influence_matrix = sensitivity_matrix.view((0, 0), (rows, cols)).clone_owned();
let origin_matrix = get_sensitivity_matrix(&sink_matrix.transpose());
let dependency_matrix = origin_matrix.view((0, 0), (rows, cols)).clone_owned();
let in_vector = get_in_vector(&adjacency_matrix, scale);
let flow_vector = get_flow_vector(&sensitivity_matrix, &in_vector);
let flow_matrix = get_flow_matrix(&sink_matrix, &in_vector);
MarkovFlow {
adjacency_matrix,
dim: rows,
sink_matrix,
sensitivity_matrix,
influence_matrix,
origin_matrix,
dependency_matrix,
in_vector,
flow_vector,
flow_matrix,
}
}
}
pub fn get_sink_matrix(adj: &DMatrix<f64>, mu: f64) -> DMatrix<f64> {
let cont = 1.0 / mu;
let evap = 1.0 - cont;
let (rows, cols) = adj.shape();
if mu <= 1.0 {
panic!("Mu should be >1!");
}
let mut sink_matrix = DMatrix::zeros(rows + 1, cols + 1);
for j in 0..cols {
let sum = adj.column(j).sum();
if sum.abs() < f64::EPSILON {
sink_matrix[(j, j)] = cont;
} else {
let scale = cont / sum;
for i in 0..rows {
sink_matrix[(i, j)] = adj[(i, j)] * scale;
}
}
sink_matrix[(rows, j)] = evap;
}
sink_matrix
}
pub fn get_sensitivity_matrix(sink_matrix: &DMatrix<f64>) -> DMatrix<f64> {
let (rows, cols) = sink_matrix.shape();
let mut sensitivity_matrix = DMatrix::identity(rows, cols) - sink_matrix;
let inverted = sensitivity_matrix.try_inverse_mut();
if !inverted {
panic!("Could not invert the given matrix.");
}
sensitivity_matrix
}
pub fn get_in_vector(adjacency_matrix: &DMatrix<f64>, scale: bool) -> DVector<f64> {
let rows = adjacency_matrix.shape().0;
let mut in_vector = DVector::from_element(rows + 1, 1.0);
if scale {
let sums = adjacency_matrix.row_sum();
for idx in 0..(rows) {
in_vector[idx] = sums[idx];
}
} else {
in_vector[rows] = 0.0;
}
in_vector
}
pub fn get_flow_vector(
sensitivity_matrix: &DMatrix<f64>,
in_vector: &DVector<f64>,
) -> DVector<f64> {
sensitivity_matrix * in_vector
}
pub fn get_flow_matrix(sink_matrix: &DMatrix<f64>, in_vector: &DVector<f64>) -> DMatrix<f64> {
let (rows, cols) = sink_matrix.shape();
DMatrix::from_fn(rows, cols, |i, j| sink_matrix[(i, j)] * in_vector[j])
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn example() {
let adj = DMatrix::from_row_slice(3, 3, &[2.0, 0.5, 0.7, 1.0, 2.0, 3.0, 1.0, 2.6, 0.1]);
let flow = MarkovFlow::new(&adj, 4.0, false);
assert_eq!(flow.sink_matrix[(0, 0)], 0.0);
assert_eq!(flow.sink_matrix[(3, 0)], 0.75);
let reference = DMatrix::from_row_slice(
4,
1,
&[1.12594131394443, 1.43287457803168, 1.4411841080238899, 3.0],
);
dbg!(&flow.flow_vector);
assert!(
flow.flow_vector
.relative_eq(&reference, 0.000000000000001, 0.000000000000001)
);
}
#[test]
fn climate_control() {
let adj = DMatrix::from_row_slice(
16,
16,
&[
0., 0., 0., 0., 0., 0., 6., 0., 0., 0., 6., 0., -1., 0., 2., 0., 0., 0., 4., 0.,
0., 2., 0., 0., 0., 4., 0., 0., 0., 0., 0., 0., 0., 4., 0., 4., 0., 2., 4., 0., 0.,
0., 0., 0., 0., 0., 4., 4., 0., 0., 4., 0., 8., 2., 0., 0., 0., 4., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 8., 0., 2., 0., 0., 0., 8., 4., 4., 0., 0., 0., 0., 0., 2., 2.,
2., 2., 0., 2., 0., 2., 0., 0., 0., 0., 0., 2., 2., 6., 0., 4., 0., 0., 2., 0., 8.,
0., 0., 8., 0., 0., 0., 4., 0., 0., 0., 0., 0., 0., 0., 8., 0., 8., 0., 4., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 2., 0., 8., 0., 0., 0., 0., 0., 8., 0., 0., 0., 4.,
0., 4., 8., 0., 0., 0., 0., 0., 4., 4., 0., 0., 0., 0., 6., 0., 0., 0., 4., 0., 8.,
4., 0., 4., 0., -1., 0., 0., 0., 0., 0., 0., 0., 0., 4., 0., 0., 0., 0., 4., -1.,
0., 2., 0., 0., 0., -1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 2., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 8., 0., 0., 0., 0., 0., 0., 0., 2., 0., 4., 0.,
0., 2., 4., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 4., 0., 0., 2., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0.,
],
);
let flow = MarkovFlow::new(&adj, 2.0, false);
let flow_vec_ref = DMatrix::from_row_slice(
17,
1,
&[
1.66245393, 1.57043341, 2.5625501, 1.96454112, 2.56170014, 2.05911155, 2.75477062,
2.03070853, 2.2891907, 2.50535804, 2.309491, 2.00614073, 1.20061407, 1.50870904,
1.65257344, 1.36165357, 16.,
],
);
dbg!(&flow.flow_vector);
assert!(
flow.flow_vector
.relative_eq(&flow_vec_ref, 0.00000001, 0.00000001)
);
}
}