stacked_linear_algebra_graph/graph/edge_store/adjacency_matrix_attribute_caching/
transpose.rs

1use graphblas_sparse_linear_algebra::collections::sparse_matrix::operations::sparse_matrix_size;
2use graphblas_sparse_linear_algebra::collections::sparse_matrix::GetMatrixDimensions;
3use graphblas_sparse_linear_algebra::operators::binary_operator::Assignment;
4use graphblas_sparse_linear_algebra::operators::mask::MatrixMask;
5use graphblas_sparse_linear_algebra::operators::options::OptionsForOperatorWithMatrixArgument;
6use graphblas_sparse_linear_algebra::operators::transpose::TransposeMatrix;
7use graphblas_sparse_linear_algebra::{
8    collections::sparse_matrix::GetGraphblasSparseMatrix, context::GetContext,
9    operators::transpose::MatrixTranspose,
10};
11use once_cell::sync::Lazy;
12
13use crate::error::GraphComputingError;
14use crate::graph::edge_store::weighted_adjacency_matrix::{
15    CreateWeightedAdjacencyMatrix, WeightedAdjacencyMatrix,
16};
17use crate::graph::value_type::implement_macro_for_all_native_value_types_with_capitalized_value_type;
18
19static DEFAULT_GRAPHBLAS_OPERATOR_OPTIONS: Lazy<OptionsForOperatorWithMatrixArgument> =
20    Lazy::new(|| OptionsForOperatorWithMatrixArgument::new_default());
21
22static MATRIX_TRANSPOSE_OPERATOR: Lazy<MatrixTranspose> = Lazy::new(|| MatrixTranspose::new());
23
24macro_rules! create_lazy_static_assignment_operator {
25    ($VALUE_TYPE:ident, $value_type:ty) => {
26        paste::paste! {
27            static [<ASSIGNMENT_OPERATOR_ $VALUE_TYPE>]: Lazy<Assignment<$value_type>> = Lazy::new(|| Assignment::<$value_type>::new());
28        }
29    };
30}
31implement_macro_for_all_native_value_types_with_capitalized_value_type!(
32    create_lazy_static_assignment_operator
33);
34
35macro_rules! create_transpose_adjacency_matrix_function {
36    ($VALUE_TYPE:ident, $value_type:ty) => {
37        paste::paste! {
38            pub(crate) fn [<transpose_adjacency_matrix_ $value_type>](
39                adjacency_matrix: &(impl GetGraphblasSparseMatrix + GetContext),
40                mask: &(impl MatrixMask + GetContext)
41            ) -> Result<WeightedAdjacencyMatrix, GraphComputingError> {
42                let sparse_matrix_size = sparse_matrix_size(adjacency_matrix)?; // TODO: would it be more efficient to use a cached size here?
43                let mut transposed_adjacency_matrix =
44                    <WeightedAdjacencyMatrix as CreateWeightedAdjacencyMatrix<$value_type>>::new(
45                        adjacency_matrix.context(),
46                        sparse_matrix_size.column_width(),
47                    )?;
48
49                MatrixTranspose::new().apply(
50                    adjacency_matrix,
51                    &Assignment::<$value_type>::new(),
52                    &mut transposed_adjacency_matrix,
53                    // &SelectEntireMatrix::new(adjacency_matrix.context_ref()), // TODO: consider caching the selector into the edge store
54                    mask,
55                    &*DEFAULT_GRAPHBLAS_OPERATOR_OPTIONS,
56                )?;
57
58                // TODO: performance benchmarking to select fastest variant
59                // MATRIX_TRANSPOSE_OPERATOR.apply(
60                //     adjacency_matrix,
61                //     &*[<ASSIGNMENT_OPERATOR_ $VALUE_TYPE>],
62                //     // Assignment::<$value_type>::new() TODO: it might be that the overhead of dereferncing the Lazy is more expensive than inlining the function call.
63                //     &mut transposed_adjacency_matrix,
64                //     // &SelectEntireMatrix::new(adjacency_matrix.context_ref()), // TODO: consider caching the selector into the edge store
65                //     mask,
66                //     &*DEFAULT_GRAPHBLAS_OPERATOR_OPTIONS,
67                // )?;
68
69                Ok(transposed_adjacency_matrix)
70            }
71        }
72    };
73}
74implement_macro_for_all_native_value_types_with_capitalized_value_type!(
75    create_transpose_adjacency_matrix_function
76);
77
78#[cfg(test)]
79mod tests {
80    use super::*;
81
82    use graphblas_sparse_linear_algebra::{context::Context, operators::mask::SelectEntireMatrix};
83
84    use crate::graph::{
85        edge_store::weighted_adjacency_matrix::{
86            operations::{GetEdgeWeight, SetEdge},
87            CreateWeightedAdjacencyMatrix, WeightedAdjacencyMatrix,
88        },
89        indexing::VertexIndex,
90    };
91
92    #[test]
93    fn transpose_adjacency_matrix() {
94        let context = Context::init_default().unwrap();
95
96        let mut adjacency_matrix = <WeightedAdjacencyMatrix as CreateWeightedAdjacencyMatrix<
97            u32,
98        >>::new(context.clone(), 10)
99        .unwrap();
100
101        adjacency_matrix
102            .set_edge_unchecked(&VertexIndex::new(0), &VertexIndex::new(0), 1e3)
103            .unwrap();
104        adjacency_matrix
105            .set_edge_unchecked(&VertexIndex::new(1), &VertexIndex::new(0), 2e3)
106            .unwrap();
107
108        let transposed = transpose_adjacency_matrix_u32(
109            &adjacency_matrix,
110            &SelectEntireMatrix::new(context.clone()),
111        )
112        .unwrap();
113
114        assert_eq!(
115            GetEdgeWeight::<u32>::edge_weight_unchecked(
116                &transposed,
117                &VertexIndex::new(0),
118                &VertexIndex::new(0)
119            )
120            .unwrap()
121            .unwrap(),
122            1000u32
123        );
124        assert_eq!(
125            GetEdgeWeight::<u32>::edge_weight_unchecked(
126                &transposed,
127                &VertexIndex::new(0),
128                &VertexIndex::new(1)
129            )
130            .unwrap()
131            .unwrap(),
132            2000u32
133        );
134        assert_eq!(
135            GetEdgeWeight::<u32>::edge_weight_unchecked(
136                &transposed,
137                &VertexIndex::new(1),
138                &VertexIndex::new(0)
139            )
140            .unwrap(),
141            None
142        );
143    }
144}