summaryrefslogtreecommitdiff
path: root/graph/src/lib.rs
blob: 7b74ee1b717e73652ee17381150af85d974ad08b (plain)
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
#![warn(missing_docs)]
//! This crate implements a trait API for graphs that the crate "rep"
//! needs.
//!
//! Also a default implementation for the trait is provided, so that
//! by default no external crates are needed, whereas it is easy to
//! use external crates, if so derired.

use std::hash::Hash;

pub mod error;

pub mod adset;

pub use adset::ASGraph;

pub mod adlist;

pub use adlist::ALGraph;

pub mod labelled;

pub use labelled::DLGraph;

use error::Error;

/// The expected behaviour of an immutable graph.
pub trait Graph: Default {
    /// A type that iterates through the node indices.
    type Iter<'a>: Iterator<Item = usize> + 'a
    where
        Self: 'a;

    /// Return true if and only if the graph has no nodes.
    fn is_empty(&self) -> bool;

    /// Return the length of nodes in the graph.
    fn nodes_len(&self) -> usize;

    #[inline]
    /// Return the length of edges in the graph.
    ///
    /// This is optional.  Implementations need not support this.
    fn edges_len(&self) -> Option<usize> {
        None
    }

    #[inline]
    /// Return an iterator of nodes represented as unsigned integers.
    ///
    /// If a custom application needs to have labels on nodes, just
    /// associate the label to the node internally, and define an
    /// extension trait that allows querying those additional labels.
    ///
    /// This design choice is based on the idea that this library
    /// should be minimal and only provide the core of a graph.  As a
    /// label is not really core, it is not included here.
    fn nodes(&self) -> Box<dyn Iterator<Item = usize> + '_> {
        Box::new(0..self.nodes_len())
    }

    /// Return an iterator of edges going out of a node.
    ///
    /// Return an error if the node is not known to the graph.
    fn children_of(&self, node_id: usize) -> Result<Self::Iter<'_>, Error>;

    #[inline]
    /// Return an iterator of edges represented as pairs (FROM, TO).
    ///
    /// The default implementation iterates through the nodes and then
    /// iterates through their children.  If the implementation has a
    /// more efficient method, overwrite this method.
    fn edges(&self) -> Box<dyn Iterator<Item = (usize, usize)> + '_> {
        Box::new(self.nodes().flat_map(|node| {
            self.children_of(node)
                // If this node is invalid, this means the
                // implementation of `nodes` is wrong, so it is
                // appropriate to panic here.
                .unwrap()
                .map(move |child| (node, child))
        }))
    }

    #[inline]
    /// Return true if and only if the node is in the graph.
    fn has_node(&self, node_id: usize) -> bool {
        (0..self.nodes_len()).contains(&node_id)
    }

    /// Return the number of "children" of a node, or an error if the
    /// node is not a member of the graph.
    fn degree(&self, node_id: usize) -> Result<usize, Error>;

    /// Return a boolean indicating if the node has no children, or an
    /// error if the node is not a member of the graph.
    fn is_empty_node(&self, node_id: usize) -> Result<bool, Error>;

    /// Return true if and only if there is an edge from the source to
    /// the target.
    ///
    /// Return an error if either the source or the target is an
    /// invalid node.
    fn has_edge(&self, source: usize, target: usize) -> Result<bool, Error>;
}

/// A graph that can be extended, but not mutated, in the sense that
/// existing nodes and edges will not be modified nor removed, but new
/// nodes can be added.  The index of the new node will be returned.
///
/// Implementations can choose to keep a set of sets of edges, so that
/// new nodes will not have duplicate edge sets.  In this case, the
/// returned new node index is not necessarily equal to
/// self.nodes_len() - 1, and hence the return type is designed in
/// this way.
pub trait ExtGraph: Graph {
    /// Add a new node with `edges`.
    ///
    /// If an edge from `edges` points to a non-existent node, return
    /// an error.
    fn extend(&mut self, edges: impl IntoIterator<Item = usize>) -> Result<usize, Error>;
}

/// The type of labels should be comparable and hashable.
pub trait GraphLabel: Hash + Eq + PartialEq + Clone + Copy + Ord + PartialOrd {}

impl<T: Hash + Eq + PartialEq + Clone + Copy + Ord + PartialOrd> GraphLabel for T {}

/// A labelled graph is just a graph with labels associated to
/// vertices and / or edges.
///
/// This trait defines what the package needs out of a labelled graph.
///
/// Any implementation should be able to handle a set of types for
/// labels, so this trait is generic over the label type.
pub trait LabelGraph<T: GraphLabel>: Graph {
    /// A type that iterates through the node indices.
    type Iter<'a>: Iterator<Item = usize> + 'a
    where
        Self: 'a;

    /// A type that iterates through labels.
    type LabelIter<'a>: Iterator<Item = (&'a T, <Self as LabelGraph<T>>::Iter<'a>)> + 'a
    where
        Self: 'a,
        T: 'a;

    #[inline]
    /// Return the label of a vertex or an error if the node is
    /// invalid.
    ///
    /// The default implementation always returns None for a valid
    /// node.
    fn vertex_label(&self, node_id: usize) -> Result<Option<T>, Error> {
        if self.has_node(node_id) {
            Ok(None)
        } else {
            Err(Error::IndexOutOfBounds(node_id, self.nodes_len()))
        }
    }

    #[inline]
    /// Return the label of an edge or an error if some node is
    /// invalid.
    ///
    /// The default implementation always returns an empty vector for
    /// valid nodes.
    fn edge_label(&self, source: usize, target: usize) -> Result<Vec<T>, Error> {
        self.has_edge(source, target).map(|_| Vec::new())
    }

    /// Return an iterator of edges out of a node, whose associated
    /// label is as given.
    ///
    /// The efficiency of this method matters in implementations.
    fn find_children_with_label(
        &self,
        node_id: usize,
        label: &T,
    ) -> Result<<Self as LabelGraph<T>>::Iter<'_>, Error>;

    /// Return an iterator of labels of edges out of a node.
    ///
    /// The efficiency of this method matters in implementations.
    fn labels_of(&self, node_id: usize) -> Result<Self::LabelIter<'_>, Error>;
}

/// A labelled graph that can be extended, but not mutated, in the
/// sense that existing nodes and edges will not be modified nor
/// removed, but new nodes can be added.  The index of the new node
/// will be returned.
///
/// Implementations can choose to keep a set of sets of edges, so that
/// new nodes will not have duplicate edge sets.  In this case, the
/// returned new node index is not necessarily equal to
/// self.nodes_len() - 1, and hence the return type is designed in
/// this way.
pub trait LabelExtGraph<T: GraphLabel>: LabelGraph<T> {
    /// Add a new node with `edges`.
    ///
    /// If an edge from `edges` points to a non-existent node, return
    /// an error.
    fn extend(&mut self, edges: impl IntoIterator<Item = (T, usize)>) -> Result<usize, Error>;
}