• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

vigna / webgraph-rs / 14999125721

13 May 2025 02:22PM UTC coverage: 49.654% (-5.7%) from 55.382%
14999125721

push

github

zommiommy
wip hyperball cli

4 of 147 new or added lines in 4 files covered. (2.72%)

477 existing lines in 46 files now uncovered.

3663 of 7377 relevant lines covered (49.65%)

25650535.86 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

63.43
/webgraph/src/graphs/vec_graph.rs
1
/*
2
 * SPDX-FileCopyrightText: 2023 Inria
3
 * SPDX-FileCopyrightText: 2023 Sebastiano Vigna
4
 *
5
 * SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
6
 */
7

8
use crate::prelude::*;
9
use epserde::Epserde;
10
use lender::prelude::*;
11

12
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
13
#[derive(Epserde, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
14
pub struct LabelledArc<L>(usize, L);
15

16
impl<L> From<(usize, L)> for LabelledArc<L> {
17
    fn from((v, l): (usize, L)) -> Self {
1,432,555✔
18
        Self(v, l)
1,432,555✔
19
    }
20
}
21

22
impl<L> From<LabelledArc<L>> for (usize, L) {
23
    fn from(value: LabelledArc<L>) -> (usize, L) {
15✔
24
        (value.0, value.1)
15✔
25
    }
26
}
27

28
/// A mutable [`LabeledRandomAccessGraph`] implementation based on a vector of
29
/// vectors.
30
///
31
/// This implementation is faster and uses less resources than a
32
/// [`LabeledBTreeGraph`](crate::graphs::btree_graph::LabeledBTreeGraph), but it
33
/// is less flexible as arcs can be added only in increasing successor order.
34
///
35
/// This struct can be serialized with
36
/// [ε-serde](https://crates.io/crates/epserde). By setting the feature `serde`,
37
/// this struct can be serialized using [serde](https://crates.io/crates/serde),
38
/// too.
39
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
40
#[derive(Epserde, Clone, Debug, PartialEq, Eq)]
41
pub struct LabeledVecGraph<L: Clone + 'static> {
42
    /// The number of arcs in the graph.
43
    number_of_arcs: u64,
44
    /// For each node, its list of successors.
45
    succ: Vec<Vec<LabelledArc<L>>>,
46
}
47

48
impl<L: Clone + 'static> core::default::Default for LabeledVecGraph<L> {
49
    fn default() -> Self {
×
50
        Self::new()
×
51
    }
52
}
53

54
impl<L: Clone + 'static> LabeledVecGraph<L> {
55
    /// Creates a new empty graph.
56
    pub fn new() -> Self {
975✔
57
        Self {
58
            number_of_arcs: 0,
59
            succ: vec![],
975✔
60
        }
61
    }
62

63
    /// Creates a new empty graph with `n` nodes.
64
    pub fn empty(n: usize) -> Self {
×
65
        Self {
66
            number_of_arcs: 0,
67
            succ: Vec::from_iter((0..n).map(|_| Vec::new())),
×
68
        }
69
    }
70

71
    /// Add an isolated node to the graph and return true if it is a new node.
72
    pub fn add_node(&mut self, node: usize) -> bool {
1,426,601✔
73
        let len = self.succ.len();
4,279,803✔
74
        self.succ.extend((len..=node).map(|_| Vec::new()));
5,750,540✔
75
        len <= node
1,426,601✔
76
    }
77

78
    /// Add an arc to the graph.
79
    ///
80
    /// New arcs must be added in increasing successor order, or this method
81
    /// will panic.
82
    ///
83
    /// # Panics
84
    ///
85
    /// This method will panic:
86
    /// - if one of the given nodes is greater or equal than the number of nodes
87
    ///   in the graph;
88
    /// - if the successor is lesser than or equal to the current last successor
89
    ///   of the source node.
90
    pub fn add_arc(&mut self, u: usize, v: usize, l: L) {
1,432,555✔
91
        let max = u.max(v);
5,730,220✔
92
        if max >= self.succ.len() {
2,865,110✔
93
            panic!(
×
94
                "Node {} does not exist (the graph has {} nodes)",
×
95
                max,
×
96
                self.succ.len(),
×
97
            );
98
        }
99
        let succ = &mut self.succ[u];
2,865,110✔
100

101
        match succ.last() {
1,432,555✔
102
            None => {
43,390✔
103
                succ.push((v, l).into());
43,390✔
104
                self.number_of_arcs += 1;
43,390✔
105
            }
106
            Some(LabelledArc(last, _label)) => {
2,778,330✔
107
                if v <= *last {
1,389,165✔
108
                    // arcs have to be inserted in increasing successor order
109
                    panic!(
×
110
                        "Error adding arc ({u}, {v}): successor is not increasing; the last arc inserted was ({u}, {last})"
×
111
                    );
112
                }
113
                succ.push((v, l).into());
5,556,660✔
114
                self.number_of_arcs += 1;
1,389,165✔
115
            }
116
        }
117
    }
118

119
    /// Add nodes and successors from an [`IntoLender`] yielding a
120
    /// [`NodeLabelsLender`].
121
    ///
122
    /// If the lender is sorted, consider using
123
    /// [`add_sorted_lender`](Self::add_sorted_lender), as it does not need to
124
    /// sort the output of the lender.
125
    pub fn add_lender<I: IntoLender>(&mut self, iter_nodes: I) -> &mut Self
193✔
126
    where
127
        I::Lender: for<'next> NodeLabelsLender<'next, Label = (usize, L)>,
128
    {
129
        let mut arcs = Vec::new();
386✔
130
        for_!( (node, succ) in iter_nodes {
10,726✔
UNCOV
131
            self.add_node(node);
×
132
            for (v, l) in succ {
701,181✔
133
                arcs.push((v, l));
×
134
                self.add_node(v);
×
135
            }
UNCOV
136
            arcs.sort_by_key(|x| x.0);
×
137
            for (v, l) in arcs.drain(..) {
345,324✔
138
                self.add_arc(node, v, l);
×
139
            }
140
        });
141
        self
193✔
142
    }
143

144
    /// Creates a new graph from an [`IntoLender`] yielding a
145
    /// [`NodeLabelsLender`].
146
    ///
147
    /// If the lender is sorted, consider using
148
    /// [`from_sorted_lender`](Self::from_sorted_lender), as it does not need to
149
    /// sort the output of the lender.
150
    pub fn from_lender<I: IntoLender>(iter_nodes: I) -> Self
4✔
151
    where
152
        I::Lender: for<'next> NodeLabelsLender<'next, Label = (usize, L)>,
153
    {
154
        let mut g = Self::new();
8✔
155
        g.add_lender(iter_nodes);
12✔
156
        g
4✔
157
    }
158

159
    /// Add nodes and successors from an [`IntoLender`] yielding a sorted
160
    /// [`NodeLabelsLender`].
161
    ///
162
    /// This method is faster than [`add_lender`](Self::add_lender) as
163
    /// it does not need to sort the output of the lender.
164
    pub fn add_sorted_lender<I: IntoLender>(&mut self, iter_nodes: I) -> &mut Self
×
165
    where
166
        I::Lender: for<'next> NodeLabelsLender<'next, Label = (usize, L)>,
167
        I::Lender: SortedLender,
168
        for<'succ> LenderIntoIter<'succ, I::Lender>: SortedIterator,
169
    {
170
        for_!( (node, succ) in iter_nodes {
×
171
            self.add_node(node);
×
172
            for (v, l) in succ {
×
173
                self.add_node(v);
×
174
                self.add_arc(node, v, l);
×
175
            }
176
        });
177
        self
×
178
    }
179

180
    /// Creates a new graph from a sorted [`IntoLender`] yielding a
181
    /// [`NodeLabelsLender`].
182
    ///
183
    /// This method is faster than [`from_lender`](Self::from_lender) as
184
    /// it does not need to sort the output of the lender.
185
    pub fn from_sorted_lender<I: IntoLender>(iter_nodes: I) -> Self
×
186
    where
187
        I::Lender: for<'next> NodeLabelsLender<'next, Label = (usize, L)>,
188
        I::Lender: SortedLender,
189
        for<'succ> LenderIntoIter<'succ, I::Lender>: SortedIterator,
190
    {
191
        let mut g = Self::new();
×
192
        g.add_sorted_lender(iter_nodes);
×
193
        g
×
194
    }
195

196
    /// Add labeled arcs from an [`IntoIterator`], adding new nodes as needed.
197
    ///
198
    /// The items must be triples of the form `(usize, usize, l)` specifying an
199
    /// arc and its label.
200
    pub fn add_arcs(&mut self, arcs: impl IntoIterator<Item = (usize, usize, L)>) {
46✔
201
        let mut arcs = arcs.into_iter().collect::<Vec<_>>();
184✔
202
        arcs.sort_by_key(|x| (x.0, x.1));
1,492✔
203
        for (u, v, l) in arcs {
646✔
204
            self.add_node(u);
×
205
            self.add_node(v);
×
206
            self.add_arc(u, v, l);
×
207
        }
208
    }
209

210
    /// Creates a new graph from an [`IntoIterator`].
211
    ///
212
    /// The items must be triples of the form `(usize, usize, l)` specifying an
213
    /// arc and its label.
214
    pub fn from_arcs(arcs: impl IntoIterator<Item = (usize, usize, L)>) -> Self {
6✔
215
        let mut g = Self::new();
12✔
216
        g.add_arcs(arcs);
18✔
217
        g
6✔
218
    }
219

220
    /// Shrink the capacity of the graph to fit its current size.
221
    pub fn shrink_to_fit(&mut self) {
×
222
        self.succ.shrink_to_fit();
×
223
        for s in self.succ.iter_mut() {
×
224
            s.shrink_to_fit();
×
225
        }
226
    }
227
}
228

229
impl<L: Clone + 'static> SequentialLabeling for LabeledVecGraph<L> {
230
    type Label = (usize, L);
231
    type Lender<'a>
232
        = IteratorImpl<'a, Self>
233
    where
234
        Self: 'a;
235

236
    #[inline(always)]
237
    fn num_nodes(&self) -> usize {
1,829✔
238
        self.succ.len()
3,658✔
239
    }
240

241
    #[inline(always)]
242
    fn num_arcs_hint(&self) -> Option<u64> {
1✔
243
        Some(self.num_arcs())
1✔
244
    }
245

246
    #[inline(always)]
247
    fn iter_from(&self, from: usize) -> Self::Lender<'_> {
3✔
248
        IteratorImpl {
249
            labeling: self,
250
            nodes: (from..self.num_nodes()),
6✔
251
        }
252
    }
253
}
254

255
impl<'a, L: Clone + 'static> IntoLender for &'a LabeledVecGraph<L> {
256
    type Lender = <LabeledVecGraph<L> as SequentialLabeling>::Lender<'a>;
257

258
    #[inline(always)]
259
    fn into_lender(self) -> Self::Lender {
×
260
        self.iter()
×
261
    }
262
}
263

264
impl<L: Clone + 'static> LabeledSequentialGraph<L> for LabeledVecGraph<L> {}
265

266
impl<L: Clone + 'static> RandomAccessLabeling for LabeledVecGraph<L> {
267
    type Labels<'succ> = core::iter::Map<
268
        core::iter::Cloned<core::slice::Iter<'succ, LabelledArc<L>>>,
269
        fn(LabelledArc<L>) -> (usize, L),
270
    >;
271
    #[inline(always)]
272
    fn num_arcs(&self) -> u64 {
1,708✔
273
        self.number_of_arcs
1,708✔
274
    }
275

276
    #[inline(always)]
277
    fn outdegree(&self, node: usize) -> usize {
791✔
278
        self.succ[node].len()
1,582✔
279
    }
280

281
    #[inline(always)]
282
    fn labels(&self, node: usize) -> <Self as RandomAccessLabeling>::Labels<'_> {
15✔
283
        self.succ[node].iter().cloned().map(Into::into)
60✔
284
    }
285
}
286

287
impl<L: Clone + 'static> LabeledRandomAccessGraph<L> for LabeledVecGraph<L> {}
288

289
/// A mutable [`RandomAccessGraph`] implementation based on a vector of
290
/// vectors.
291
///
292
/// This implementation is faster and uses less resources than a [`BTreeGraph`],
293
/// but it is less flexible as arcs can be added only in increasing successor
294
/// order.
295
///
296
/// This struct can be serialized with
297
/// [ε-serde](https://crates.io/crates/epserde). By setting the feature `serde`,
298
/// this struct can be serialized using [serde](https://crates.io/crates/serde),
299
/// too.
300
///
301
/// # Implementation Notes
302
///
303
/// This is just a newtype for a [`LabeledVecGraph`] with
304
/// [`()`](https://doc.rust-lang.org/std/primitive.unit.html) labels. All
305
/// mutation methods are delegated.
306
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
307
#[derive(Epserde, Clone, Debug, Default, PartialEq, Eq)]
308
pub struct VecGraph(LabeledVecGraph<()>);
309

310
impl VecGraph {
311
    /// Creates a new empty graph.
312
    pub fn new() -> Self {
965✔
313
        LabeledVecGraph::new().into()
1,930✔
314
    }
315

316
    /// Creates a new empty graph with `n` nodes.
317
    pub fn empty(n: usize) -> Self {
×
318
        LabeledVecGraph::empty(n).into()
×
319
    }
320

321
    /// Add an isolated node to the graph and return true if it is a new node.
322
    pub fn add_node(&mut self, node: usize) -> bool {
1,244✔
323
        self.0.add_node(node)
3,732✔
324
    }
325

326
    /// Add an arc to the graph.
327
    ///
328
    /// New arcs must be added in increasing successor order, or this method
329
    /// will panic.
330
    ///
331
    /// # Panics
332
    ///
333
    /// This method will panic:
334
    /// - if one of the given nodes is greater or equal than the number of nodes
335
    ///   in the graph;
336
    /// - if the successor is lesser than or equal to the current last successor
337
    ///   of the source node.
338
    pub fn add_arc(&mut self, u: usize, v: usize) {
50,296✔
339
        self.0.add_arc(u, v, ())
251,480✔
340
    }
341

342
    /// Add nodes and successors from an [`IntoLender`] yielding a
343
    /// [`NodeLabelsLender`].
344
    ///
345
    /// If the lender is sorted, consider using
346
    /// [`add_sorted_lender`](Self::add_sorted_lender), as it does not need to
347
    /// sort the output of the lender.
348
    pub fn add_lender<I: IntoLender>(&mut self, iter_nodes: I) -> &mut Self
189✔
349
    where
350
        I::Lender: for<'next> NodeLabelsLender<'next, Label = usize>,
351
    {
352
        self.0.add_lender(UnitLender(iter_nodes.into_lender()));
567✔
353
        self
189✔
354
    }
355

356
    /// Creates a new graph from an [`IntoLender`] yielding a
357
    /// [`NodeLabelsLender`].
358
    ///
359
    /// If the lender is sorted, consider using
360
    /// [`from_sorted_lender`](Self::from_sorted_lender), as it does not need to
361
    /// sort the output of the lender.
362
    pub fn from_lender<I: IntoLender>(iter_nodes: I) -> Self
189✔
363
    where
364
        I::Lender: for<'next> NodeLabelsLender<'next, Label = usize>,
365
    {
366
        let mut g = Self::new();
378✔
367
        g.add_lender(iter_nodes);
567✔
368
        g
189✔
369
    }
370

371
    /// Add nodes and successors from an [`IntoLender`] yielding a sorted
372
    /// [`NodeLabelsLender`].
373
    ///
374
    /// This method is faster than [`add_lender`](Self::add_lender) as
375
    /// it does not need to sort the output of the lender.
376
    pub fn add_sorted_lender<I: IntoLender>(&mut self, iter_nodes: I) -> &mut Self
×
377
    where
378
        I::Lender: for<'next> NodeLabelsLender<'next, Label = usize>,
379
        I::Lender: SortedLender,
380
        for<'succ> LenderIntoIter<'succ, I::Lender>: SortedIterator,
381
    {
382
        self.0
×
383
            .add_sorted_lender(UnitLender(iter_nodes.into_lender()));
×
384
        self
×
385
    }
386

387
    /// Creates a new graph from a sorted [`IntoLender`] yielding a
388
    /// [`NodeLabelsLender`].
389
    ///
390
    /// This method is faster than [`from_lender`](Self::from_lender) as
391
    /// it does not need to sort the output of the lender.
392
    pub fn from_sorted_lender<I: IntoLender>(iter_nodes: I) -> Self
×
393
    where
394
        I::Lender: for<'next> NodeLabelsLender<'next, Label = usize>,
395
        I::Lender: SortedLender,
396
        for<'succ> LenderIntoIter<'succ, I::Lender>: SortedIterator,
397
    {
398
        let mut g = Self::new();
×
399
        g.add_sorted_lender(iter_nodes);
×
400
        g
×
401
    }
402

403
    /// Add arcs from an [`IntoIterator`], adding new nodes as needed.
404
    ///
405
    /// The items must be pairs of the form `(usize, usize)` specifying an arc.
406
    pub fn add_arcs(&mut self, arcs: impl IntoIterator<Item = (usize, usize)>) {
40✔
407
        self.0.add_arcs(arcs.into_iter().map(|(u, v)| (u, v, ())));
1,019✔
408
    }
409

410
    /// Creates a new graph from an [`IntoIterator`].
411
    ///
412
    /// The items must be pairs of the form `(usize, usize)` specifying an arc.
413
    pub fn from_arcs(arcs: impl IntoIterator<Item = (usize, usize)>) -> Self {
40✔
414
        let mut g = Self::new();
80✔
415
        g.add_arcs(arcs);
120✔
416
        g
40✔
417
    }
418

419
    /// Shrink the capacity of the graph to fit its current size.
420
    pub fn shrink_to_fit(&mut self) {
×
421
        self.0.shrink_to_fit();
×
422
    }
423
}
424

425
impl<'a> IntoLender for &'a VecGraph {
426
    type Lender = <VecGraph as SequentialLabeling>::Lender<'a>;
427

428
    #[inline(always)]
429
    fn into_lender(self) -> Self::Lender {
×
430
        self.iter()
×
431
    }
432
}
433

434
impl SequentialLabeling for VecGraph {
435
    type Label = usize;
436
    type Lender<'a>
437
        = IteratorImpl<'a, Self>
438
    where
439
        Self: 'a;
440

441
    #[inline(always)]
442
    fn num_nodes(&self) -> usize {
1,825✔
443
        self.0.num_nodes()
3,650✔
444
    }
445

446
    #[inline(always)]
447
    fn num_arcs_hint(&self) -> Option<u64> {
1✔
448
        self.0.num_arcs_hint()
2✔
449
    }
450

451
    #[inline(always)]
452
    fn iter_from(&self, from: usize) -> Self::Lender<'_> {
102✔
453
        IteratorImpl {
454
            labeling: self,
455
            nodes: (from..self.num_nodes()),
204✔
456
        }
457
    }
458
}
459

460
impl SequentialGraph for VecGraph {}
461

462
impl RandomAccessLabeling for VecGraph {
463
    type Labels<'succ> = SortedIter<
464
        core::iter::Map<
465
            core::iter::Copied<core::slice::Iter<'succ, LabelledArc<()>>>,
466
            fn(LabelledArc<()>) -> usize,
467
        >,
468
    >;
469
    #[inline(always)]
470
    fn num_arcs(&self) -> u64 {
1,707✔
471
        self.0.num_arcs()
3,414✔
472
    }
473

474
    #[inline(always)]
475
    fn outdegree(&self, node: usize) -> usize {
791✔
476
        self.0.outdegree(node)
2,373✔
477
    }
478

479
    #[inline(always)]
480
    fn labels(&self, node: usize) -> <Self as RandomAccessLabeling>::Labels<'_> {
5,389✔
481
        // this is safe as we maintain each vector of successors sorted
482
        unsafe { SortedIter::new(self.0.succ[node].iter().copied().map(|LabelledArc(x, _)| x)) }
21,556✔
483
    }
484
}
485

486
impl RandomAccessGraph for VecGraph {}
487

488
impl From<LabeledVecGraph<()>> for VecGraph {
489
    fn from(g: LabeledVecGraph<()>) -> Self {
965✔
490
        VecGraph(g)
965✔
491
    }
492
}
493

494
#[cfg(test)]
495
mod test {
496
    use super::*;
497
    #[test]
498
    fn test_vec_graph() {
499
        let mut arcs = vec![
500
            (0, 1, Some(1.0)),
501
            (0, 2, None),
502
            (1, 2, Some(2.0)),
503
            (2, 4, Some(f64::INFINITY)),
504
            (3, 4, Some(f64::NEG_INFINITY)),
505
            (1, 3, Some(f64::NAN)),
506
        ];
507
        let g = LabeledVecGraph::<_>::from_arcs(arcs.iter().copied());
508
        assert_ne!(
509
            g, g,
510
            "The label contains a NaN which is not equal to itself so the graph must be not equal to itself"
511
        );
512

513
        arcs.pop();
514
        let g = LabeledVecGraph::<_>::from_arcs(arcs);
515
        assert_eq!(g, g, "Without NaN the graph should be equal to itself");
516
    }
517
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc