Skip to main content

causal_hub/models/graphs/
directed.rs

1use std::collections::VecDeque;
2
3use ndarray::prelude::*;
4use serde::{
5    Deserialize, Deserializer, Serialize, Serializer,
6    de::{MapAccess, Visitor},
7    ser::SerializeMap,
8};
9
10use crate::{
11    impl_json_io,
12    models::{Graph, HasLabels},
13    set,
14    types::{Error, Labels, Result, Set},
15};
16
17/// A struct representing a directed graph using an adjacency matrix.
18#[derive(Clone, Debug, Eq, PartialEq)]
19pub struct DiGraph {
20    labels: Labels,
21    adjacency_matrix: Array2<bool>,
22}
23
24impl DiGraph {
25    /// Check if a vertex is within bounds.
26    #[inline]
27    fn check_vertex(&self, x: usize) -> Result<()> {
28        if x >= self.labels.len() {
29            return Err(Error::IndexOutOfBounds(x));
30        }
31        Ok(())
32    }
33
34    /// Returns the parents of a set of vertices.
35    ///
36    /// # Arguments
37    ///
38    /// * `x` - The set of vertices for which to find the parents.
39    ///
40    /// # Errors
41    ///
42    /// * If any vertex is out of bounds.
43    ///
44    /// # Returns
45    ///
46    /// The parents of the vertices.
47    ///
48    pub fn parents(&self, x: &Set<usize>) -> Result<Set<usize>> {
49        // Check the vertices are within bounds.
50        x.iter().try_for_each(|&v| self.check_vertex(v))?;
51
52        // Iterate over all vertices and filter the ones that are parents.
53        let mut parents: Set<_> = x
54            .iter()
55            .flat_map(|&v| {
56                self.adjacency_matrix
57                    .column(v)
58                    .into_iter()
59                    .enumerate()
60                    .filter_map(|(y, &has_edge)| has_edge.then_some(y))
61            })
62            .collect();
63
64        // Sort the parents.
65        parents.sort();
66
67        // Return the parents.
68        Ok(parents)
69    }
70
71    /// Returns the ancestors of a set of vertices.
72    ///
73    /// # Arguments
74    ///
75    /// * `x` - The set of vertices for which to find the ancestors.
76    ///
77    /// # Errors
78    ///
79    /// * If any vertex is out of bounds.
80    ///
81    /// # Returns
82    ///
83    /// The ancestors of the vertices.
84    ///
85    pub fn ancestors(&self, x: &Set<usize>) -> Result<Set<usize>> {
86        // Check the vertices are within bounds.
87        x.iter().try_for_each(|&v| self.check_vertex(v))?;
88
89        // Initialize a stack and a visited set.
90        let mut stack = VecDeque::new();
91        let mut visited = set![];
92
93        // Start with the given vertices.
94        stack.extend(x);
95
96        // While there are vertices to visit ...
97        while let Some(y) = stack.pop_back() {
98            // For each incoming edge ...
99            for z in self.parents(&set![y])? {
100                // If there is an edge from z to y and z has not been visited ...
101                if !visited.contains(&z) {
102                    // Mark z as visited.
103                    visited.insert(z);
104                    // Add z to the stack to visit its ancestors.
105                    stack.push_back(z);
106                }
107            }
108        }
109
110        // Sort the visited set.
111        visited.sort();
112
113        // Return the visited set.
114        Ok(visited)
115    }
116
117    /// Returns the children of a set of vertices.
118    ///
119    /// # Arguments
120    ///
121    /// * `x` - The set of vertices for which to find the children.
122    ///
123    /// # Errors
124    ///
125    /// * If any vertex is out of bounds.
126    ///
127    /// # Returns
128    ///
129    /// The children of the vertices.
130    ///
131    pub fn children(&self, x: &Set<usize>) -> Result<Set<usize>> {
132        // Check if the vertices are within bounds.
133        x.iter().try_for_each(|&v| self.check_vertex(v))?;
134
135        // Iterate over all vertices and filter the ones that are children.
136        let mut children: Set<_> = x
137            .iter()
138            .flat_map(|&v| {
139                self.adjacency_matrix
140                    .row(v)
141                    .into_iter()
142                    .enumerate()
143                    .filter_map(|(y, &has_edge)| has_edge.then_some(y))
144            })
145            .collect();
146
147        // Sort the children.
148        children.sort();
149
150        // Return the children.
151        Ok(children)
152    }
153
154    /// Returns the descendants of a set of vertices.
155    ///
156    /// # Arguments
157    ///
158    /// * `x` - The set of vertices for which to find the descendants.
159    ///
160    /// # Errors
161    ///
162    /// * If any vertex is out of bounds.
163    ///
164    /// # Returns
165    ///
166    /// The descendants of the vertices.
167    ///
168    pub fn descendants(&self, x: &Set<usize>) -> Result<Set<usize>> {
169        // Check the vertices are within bounds.
170        x.iter().try_for_each(|&v| self.check_vertex(v))?;
171
172        // Initialize a stack and a visited set.
173        let mut stack = VecDeque::new();
174        let mut visited = set![];
175
176        // Start with the given vertices.
177        stack.extend(x);
178
179        // While there are vertices to visit ...
180        while let Some(y) = stack.pop_back() {
181            // For each outgoing edge ...
182            for z in self.children(&set![y])? {
183                // If z has not been visited ...
184                if !visited.contains(&z) {
185                    // Mark z as visited.
186                    visited.insert(z);
187                    // Add z to the stack to visit its descendants.
188                    stack.push_back(z);
189                }
190            }
191        }
192
193        // Sort the visited set.
194        visited.sort();
195
196        // Return the visited set.
197        Ok(visited)
198    }
199}
200
201impl HasLabels for DiGraph {
202    fn labels(&self) -> &Labels {
203        &self.labels
204    }
205}
206
207impl Graph for DiGraph {
208    fn empty<I, V>(labels: I) -> Result<Self>
209    where
210        I: IntoIterator<Item = V>,
211        V: AsRef<str>,
212    {
213        // Initialize labels counter.
214        let mut n = 0;
215        // Collect the labels.
216        let mut labels: Labels = labels
217            .into_iter()
218            .inspect(|_| n += 1)
219            .map(|x| x.as_ref().to_owned())
220            .collect();
221
222        // Check for duplicate labels.
223        if labels.len() != n {
224            return Err(Error::NonUniqueLabels());
225        }
226
227        // Sort the labels.
228        labels.sort();
229
230        // Initialize the adjacency matrix with `false` values.
231        let adjacency_matrix: Array2<_> = Array::from_elem((n, n), false);
232
233        Ok(Self {
234            labels,
235            adjacency_matrix,
236        })
237    }
238
239    fn complete<I, V>(labels: I) -> Result<Self>
240    where
241        I: IntoIterator<Item = V>,
242        V: AsRef<str>,
243    {
244        // Construct the empty graph.
245        let mut graph = Self::empty(labels)?;
246        // Fill the adjacency matrix with `true` values.
247        graph.adjacency_matrix.fill(true);
248        // Remove the self-loops.
249        graph.adjacency_matrix.diag_mut().fill(false);
250
251        Ok(graph)
252    }
253
254    fn vertices(&self) -> Set<usize> {
255        (0..self.labels.len()).collect()
256    }
257
258    fn has_vertex(&self, x: usize) -> bool {
259        // Check if the vertex is within bounds.
260        x < self.labels.len()
261    }
262
263    fn add_vertex<V>(&mut self, x: V) -> usize
264    where
265        V: AsRef<str>,
266    {
267        // Cast the vertex label.
268        let x = x.as_ref().to_owned();
269        // Try to insert the vertex label.
270        let (i, f) = self.labels.insert_full(x.clone());
271
272        // If the vertex was already present ...
273        if !f {
274            // ... return early.
275            return i;
276        }
277
278        // Sort the labels.
279        self.labels.sort();
280
281        // Assert the vertex has been added.
282        debug_assert!(self.labels.contains(&x));
283        // Assert the labels are still sorted.
284        debug_assert!(self.labels.iter().is_sorted());
285
286        // Compute the index of the new vertex:
287        // since labels are unique and sorted, it is
288        // the number of labels preceding the new one.
289        let i = self
290            .labels
291            .iter()
292            .filter(|&y| y.as_str() < x.as_str())
293            .count();
294
295        // Compute the size of the adjacency matrix.
296        let n = self.adjacency_matrix.nrows();
297        // Allocate the new adjacency matrix.
298        let mut adjacency_matrix = Array2::from_elem((n + 1, n + 1), false);
299        // Copy the top-left block.
300        adjacency_matrix
301            .slice_mut(s![0..i, 0..i])
302            .assign(&self.adjacency_matrix.slice(s![0..i, 0..i]));
303        // Copy the top-right block.
304        adjacency_matrix
305            .slice_mut(s![0..i, (i + 1)..(n + 1)])
306            .assign(&self.adjacency_matrix.slice(s![0..i, i..n]));
307        // Copy the bottom-left block.
308        adjacency_matrix
309            .slice_mut(s![(i + 1)..(n + 1), 0..i])
310            .assign(&self.adjacency_matrix.slice(s![i..n, 0..i]));
311        // Copy the bottom-right block.
312        adjacency_matrix
313            .slice_mut(s![(i + 1)..(n + 1), (i + 1)..(n + 1)])
314            .assign(&self.adjacency_matrix.slice(s![i..n, i..n]));
315        // Replace the old adjacency matrix.
316        self.adjacency_matrix = adjacency_matrix;
317
318        // Assert the label set is still consistent with the adjacency matrix shape.
319        debug_assert_eq!(self.labels.len(), self.adjacency_matrix.nrows());
320        // Assert the adjacency matrix is still square.
321        debug_assert!(self.adjacency_matrix.is_square());
322
323        // Return the new vertex index.
324        i
325    }
326
327    fn del_vertex(&mut self, x: usize) -> bool {
328        // Remove the vertex label, shifting the subsequent indices.
329        let Some(label) = self.labels.shift_remove_index(x) else {
330            // If the vertex was not present, return early.
331            return false;
332        };
333
334        // Assert the vertex has been removed.
335        debug_assert!(!self.labels.contains(&label));
336        // Assert the labels are still sorted.
337        debug_assert!(self.labels.iter().is_sorted());
338
339        // Compute the size of the adjacency matrix.
340        let n = self.adjacency_matrix.nrows();
341        // Allocate the new adjacency matrix.
342        let mut adjacency_matrix = Array2::from_elem((n - 1, n - 1), false);
343        // Copy the top-left block.
344        adjacency_matrix
345            .slice_mut(s![0..x, 0..x])
346            .assign(&self.adjacency_matrix.slice(s![0..x, 0..x]));
347        // Copy the top-right block.
348        adjacency_matrix
349            .slice_mut(s![0..x, x..(n - 1)])
350            .assign(&self.adjacency_matrix.slice(s![0..x, (x + 1)..n]));
351        // Copy the bottom-left block.
352        adjacency_matrix
353            .slice_mut(s![x..(n - 1), 0..x])
354            .assign(&self.adjacency_matrix.slice(s![(x + 1)..n, 0..x]));
355        // Copy the bottom-right block.
356        adjacency_matrix
357            .slice_mut(s![x..(n - 1), x..(n - 1)])
358            .assign(&self.adjacency_matrix.slice(s![(x + 1)..n, (x + 1)..n]));
359        // Replace the old adjacency matrix.
360        self.adjacency_matrix = adjacency_matrix;
361
362        // Assert the label set is still consistent with the adjacency matrix shape.
363        debug_assert_eq!(self.labels.len(), self.adjacency_matrix.nrows());
364        // Assert the adjacency matrix is still square.
365        debug_assert!(self.adjacency_matrix.is_square());
366
367        true
368    }
369
370    fn edges(&self) -> Set<(usize, usize)> {
371        // Iterate over the adjacency matrix and collect the edges.
372        self.adjacency_matrix
373            .indexed_iter()
374            .filter_map(|(idx, &has_edge)| has_edge.then_some(idx))
375            .collect()
376    }
377
378    fn has_edge(&self, x: usize, y: usize) -> Result<bool> {
379        // Check if the vertices are within bounds.
380        self.check_vertex(x)?;
381        self.check_vertex(y)?;
382
383        Ok(self.adjacency_matrix[[x, y]])
384    }
385
386    fn add_edge(&mut self, x: usize, y: usize) -> Result<bool> {
387        // Check if the vertices are within bounds.
388        self.check_vertex(x)?;
389        self.check_vertex(y)?;
390
391        // Check if the edge already exists.
392        if self.adjacency_matrix[[x, y]] {
393            return Ok(false);
394        }
395
396        // Add the edge.
397        self.adjacency_matrix[[x, y]] = true;
398
399        Ok(true)
400    }
401
402    fn del_edge(&mut self, x: usize, y: usize) -> Result<bool> {
403        // Check if the vertices are within bounds.
404        self.check_vertex(x)?;
405        self.check_vertex(y)?;
406
407        // Check if the edge exists.
408        if !self.adjacency_matrix[[x, y]] {
409            return Ok(false);
410        }
411
412        // Delete the edge.
413        self.adjacency_matrix[[x, y]] = false;
414
415        Ok(true)
416    }
417
418    fn select(&self, x: &Set<usize>) -> Result<Self>
419    where
420        Self: Sized,
421    {
422        // Check if the vertices are within bounds.
423        x.iter().try_for_each(|&v| self.check_vertex(v))?;
424
425        // Clone and sort the vertices.
426        let mut x = x.clone();
427        x.sort();
428
429        // Allocate the new labels.
430        let labels: Labels = x.iter().map(|&v| self.labels[v].clone()).collect();
431        // Allocate the new adjacency matrix.
432        let mut adjacency_matrix: Array2<bool> = Array::from_elem((x.len(), x.len()), false);
433        // Fill the new adjacency matrix.
434        for (i, &v_i) in x.iter().enumerate() {
435            for (j, &v_j) in x.iter().enumerate() {
436                adjacency_matrix[[i, j]] = self.adjacency_matrix[[v_i, v_j]];
437            }
438        }
439
440        Self::from_adjacency_matrix(labels, adjacency_matrix)
441    }
442
443    fn from_adjacency_matrix(
444        mut labels: Labels,
445        mut adjacency_matrix: Array2<bool>,
446    ) -> Result<Self> {
447        // Check labels and adjacency matrix dimensions match.
448        if labels.len() != adjacency_matrix.nrows() {
449            return Err(Error::IncompatibleShape(
450                &labels.len().to_string(),
451                &adjacency_matrix.nrows().to_string(),
452            ));
453        }
454        // Check adjacency matrix must be square.
455        if adjacency_matrix.nrows() != adjacency_matrix.ncols() {
456            return Err(Error::IncompatibleShape(
457                &adjacency_matrix.nrows().to_string(),
458                &adjacency_matrix.ncols().to_string(),
459            ));
460        }
461
462        // Check if the labels are sorted.
463        if !labels.is_sorted() {
464            // Allocate the sorted indices.
465            let mut indices: Vec<usize> = (0..labels.len()).collect();
466            // Sort the indices based on the labels.
467            indices.sort_by_key(|&i| &labels[i]);
468            // Sort the labels.
469            labels.sort();
470            // Allocate a new adjacency matrix.
471            let mut new_adjacency_matrix = adjacency_matrix.clone();
472            // Fill the rows.
473            indices.iter().enumerate().for_each(|(i, &j)| {
474                new_adjacency_matrix
475                    .row_mut(i)
476                    .assign(&adjacency_matrix.row(j));
477            });
478            // Update the adjacency matrix.
479            adjacency_matrix = new_adjacency_matrix;
480            // Allocate a new adjacency matrix.
481            let mut new_adjacency_matrix = adjacency_matrix.clone();
482            // Fill the columns.
483            indices.iter().enumerate().for_each(|(i, &j)| {
484                new_adjacency_matrix
485                    .column_mut(i)
486                    .assign(&adjacency_matrix.column(j));
487            });
488            // Update the adjacency matrix.
489            adjacency_matrix = new_adjacency_matrix;
490        }
491
492        // Create a new graph instance.
493        Ok(Self {
494            labels,
495            adjacency_matrix,
496        })
497    }
498
499    #[inline]
500    fn to_adjacency_matrix(&self) -> Array2<bool> {
501        self.adjacency_matrix.clone()
502    }
503}
504
505impl Serialize for DiGraph {
506    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
507    where
508        S: Serializer,
509    {
510        // Convert adjacency matrix to a flat format.
511        let edges = self
512            .edges()
513            .into_iter()
514            .map(|(x, y)| {
515                let x = self.index_to_label(x).map_err(serde::ser::Error::custom)?;
516                let y = self.index_to_label(y).map_err(serde::ser::Error::custom)?;
517                Ok((x.to_owned(), y.to_owned()))
518            })
519            .collect::<std::result::Result<Vec<_>, S::Error>>()?;
520
521        // Allocate the map.
522        let mut map = serializer.serialize_map(Some(3))?;
523
524        // Serialize labels.
525        map.serialize_entry("labels", &self.labels)?;
526        // Serialize edges.
527        map.serialize_entry("edges", &edges)?;
528        // Serialize type.
529        map.serialize_entry("type", "digraph")?;
530
531        // Finalize the map serialization.
532        map.end()
533    }
534}
535
536impl<'de> Deserialize<'de> for DiGraph {
537    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
538    where
539        D: Deserializer<'de>,
540    {
541        #[derive(Deserialize)]
542        #[serde(field_identifier, rename_all = "snake_case")]
543        enum Field {
544            Labels,
545            Edges,
546            Type,
547        }
548
549        struct DiGraphVisitor;
550
551        impl<'de> Visitor<'de> for DiGraphVisitor {
552            type Value = DiGraph;
553
554            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
555                formatter.write_str("struct DiGraph")
556            }
557
558            fn visit_map<V>(self, mut map: V) -> std::result::Result<DiGraph, V::Error>
559            where
560                V: MapAccess<'de>,
561            {
562                use serde::de::Error as E;
563
564                // Allocate fields
565                let mut labels = None;
566                let mut edges = None;
567                let mut type_ = None;
568
569                // Parse the map.
570                while let Some(key) = map.next_key()? {
571                    match key {
572                        Field::Labels => {
573                            if labels.is_some() {
574                                return Err(E::duplicate_field("labels"));
575                            }
576                            labels = Some(map.next_value()?);
577                        }
578                        Field::Edges => {
579                            if edges.is_some() {
580                                return Err(E::duplicate_field("edges"));
581                            }
582                            edges = Some(map.next_value()?);
583                        }
584                        Field::Type => {
585                            if type_.is_some() {
586                                return Err(E::duplicate_field("type"));
587                            }
588                            type_ = Some(map.next_value()?);
589                        }
590                    }
591                }
592
593                // Check required fields.
594                let labels = labels.ok_or_else(|| E::missing_field("labels"))?;
595                let edges = edges.ok_or_else(|| E::missing_field("edges"))?;
596
597                // Check type is correct.
598                let type_: String = type_.ok_or_else(|| E::missing_field("type"))?;
599                if type_ != "digraph" {
600                    return Err(E::custom(format!(
601                        "Invalid type for DiGraph: expected 'digraph', found '{type_}'"
602                    )));
603                }
604
605                // Convert edges to an adjacency matrix.
606                let labels: Labels = labels;
607                let edges: Vec<(String, String)> = edges;
608                let shape = (labels.len(), labels.len());
609                let mut adjacency_matrix = Array2::from_elem(shape, false);
610                edges.into_iter().try_for_each(|(x, y)| {
611                    let x = labels
612                        .get_index_of(&x)
613                        .ok_or_else(|| E::custom(format!("Vertex `{x}` label does not exist")))?;
614                    let y = labels
615                        .get_index_of(&y)
616                        .ok_or_else(|| E::custom(format!("Vertex `{y}` label does not exist")))?;
617                    adjacency_matrix[(x, y)] = true;
618                    Ok(())
619                })?;
620
621                DiGraph::from_adjacency_matrix(labels, adjacency_matrix)
622                    .map_err(|evidence| E::custom(evidence.to_string()))
623            }
624        }
625
626        const FIELDS: &[&str] = &["labels", "edges", "type"];
627
628        deserializer.deserialize_struct("DiGraph", FIELDS, DiGraphVisitor)
629    }
630}
631
632// Implement `JsonIO` for `DiGraph`.
633impl_json_io!(DiGraph);