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
//! Graph density - measures how dense or sparse a graph is.
//!
//! It is defined as the ratio of the number of edges in the graph to the total number of possible
//! edges. A dense graph has a high edge-to-node ratio, while a sparse graph has a low
//! edge-to-node ratio.
//!
//! For example in social network analysis, a dense graph may indicate a highly interconnected
//! community_detection, while a sparse graph may indicate more isolated individuals.
//!
//! # Examples
//!
//! ```rust
//! use raphtory::algorithms::metrics::directed_graph_density::directed_graph_density;
//! use raphtory::prelude::*;
//!
//! let g = Graph::new();
//! let windowed_graph = g.window(0, 7);
//! let vs = vec![
//!     (1, 1, 2),
//!     (2, 1, 3),
//!     (3, 2, 1),
//!     (4, 3, 2),
//!     (5, 1, 4),
//!     (6, 4, 5),
//! ];
//!
//! for (t, src, dst) in &vs {
//! g.add_edge(*t, *src, *dst, NO_PROPS, None);
//! }
//!
//! println!("graph density: {:?}", directed_graph_density(&windowed_graph));
//! ```
//!
use crate::db::api::view::*;

/// Measures how dense or sparse a graph is
pub fn directed_graph_density<'graph, G: GraphViewOps<'graph>>(graph: &G) -> f32 {
    graph.count_edges() as f32 / (graph.count_nodes() as f32 * (graph.count_nodes() as f32 - 1.0))
}

#[cfg(test)]
mod directed_graph_density_tests {
    use super::*;
    use crate::{
        db::{api::mutation::AdditionOps, graph::graph::Graph},
        prelude::NO_PROPS,
        test_storage,
    };

    #[test]
    fn low_graph_density() {
        let graph = Graph::new();

        let vs = vec![
            (1, 1, 2),
            (2, 1, 3),
            (3, 2, 1),
            (4, 3, 2),
            (5, 1, 4),
            (6, 4, 5),
        ];

        for (t, src, dst) in &vs {
            graph.add_edge(*t, *src, *dst, NO_PROPS, None).unwrap();
        }

        test_storage!(&graph, |graph| {
            let windowed_graph = graph.window(0, 7);
            let actual = directed_graph_density(&windowed_graph);
            let expected = 0.3;

            assert_eq!(actual, expected);
        });
    }

    #[test]
    fn complete_graph_has_graph_density_of_one() {
        let graph = Graph::new();

        let vs = vec![(1, 1, 2), (2, 2, 1)];

        for (t, src, dst) in &vs {
            graph.add_edge(*t, *src, *dst, NO_PROPS, None).unwrap();
        }

        test_storage!(&graph, |graph| {
            let windowed_graph = graph.window(0, 3);
            let actual = directed_graph_density(&windowed_graph);
            let expected = 1.0;

            assert_eq!(actual, expected);
        });
    }
}