petgraph/algo/
mod.rs

1/*!
2This module contains most of `petgraph`'s algorithms to operate on graphs. Some, very simple search
3algorithms like depth-first search or breadth-first search are implemented in the
4[`visit`](crate::visit) module.
5
6The `algo` module contains multiple submodules, each implementing a specific algorithm or set of
7algorithms. Some functions, like [`connected_components`], are implemented directly in this module.
8
9It is a goal to gradually migrate the algorithms to be based on graph traits
10so that they are generally applicable. For now, some of these still require
11the `Graph` type.
12*/
13
14pub mod articulation_points;
15pub mod astar;
16pub mod bellman_ford;
17pub mod bridges;
18pub mod coloring;
19pub mod dijkstra;
20pub mod dominators;
21pub mod feedback_arc_set;
22pub mod floyd_warshall;
23pub mod ford_fulkerson;
24pub mod isomorphism;
25pub mod johnson;
26pub mod k_shortest_path;
27pub mod matching;
28pub mod maximal_cliques;
29pub mod maximum_flow;
30pub mod min_spanning_tree;
31pub mod page_rank;
32pub mod scc;
33pub mod simple_paths;
34pub mod spfa;
35#[cfg(feature = "stable_graph")]
36pub mod steiner_tree;
37pub mod tred;
38
39use alloc::{vec, vec::Vec};
40
41use crate::prelude::*;
42
43use super::graph::IndexType;
44use super::unionfind::UnionFind;
45use super::visit::{
46    GraphBase, GraphRef, IntoEdgeReferences, IntoNeighbors, IntoNeighborsDirected,
47    IntoNodeIdentifiers, NodeCompactIndexable, NodeIndexable, Reversed, VisitMap, Visitable,
48};
49use super::EdgeType;
50use crate::visit::Walker;
51
52pub use astar::astar;
53pub use bellman_ford::{bellman_ford, find_negative_cycle};
54pub use bridges::bridges;
55pub use coloring::dsatur_coloring;
56pub use dijkstra::{bidirectional_dijkstra, dijkstra};
57pub use feedback_arc_set::greedy_feedback_arc_set;
58pub use floyd_warshall::floyd_warshall;
59pub use isomorphism::{
60    is_isomorphic, is_isomorphic_matching, is_isomorphic_subgraph, is_isomorphic_subgraph_matching,
61    subgraph_isomorphisms_iter,
62};
63pub use johnson::johnson;
64pub use k_shortest_path::k_shortest_path;
65pub use matching::{greedy_matching, maximum_matching, Matching};
66pub use maximal_cliques::maximal_cliques;
67pub use maximum_flow::{dinics, ford_fulkerson};
68pub use min_spanning_tree::{min_spanning_tree, min_spanning_tree_prim};
69pub use page_rank::page_rank;
70#[allow(deprecated)]
71pub use scc::scc;
72pub use scc::{
73    kosaraju_scc::kosaraju_scc,
74    tarjan_scc::{tarjan_scc, TarjanScc},
75};
76pub use simple_paths::{all_simple_paths, all_simple_paths_multi};
77pub use spfa::spfa;
78#[cfg(feature = "stable_graph")]
79pub use steiner_tree::steiner_tree;
80
81#[cfg(feature = "rayon")]
82pub use johnson::parallel_johnson;
83
84/// Return the number of connected components of the graph.
85///
86/// For a directed graph, this is the *weakly* connected components.
87///
88/// # Arguments
89/// * `g`: an input graph.
90///
91/// # Returns
92/// * `usize`: the number of connected components if `g` is undirected
93///   or number of *weakly* connected components if `g` is directed.
94///
95/// # Complexity
96/// * Time complexity: amortized **O(|E| + |V|log|V|)**.
97/// * Auxiliary space: **O(|V|)**.
98///
99/// where **|V|** is the number of nodes and **|E|** is the number of edges.
100///
101/// # Example
102/// ```rust
103/// use petgraph::Graph;
104/// use petgraph::algo::connected_components;
105/// use petgraph::prelude::*;
106///
107/// let mut graph : Graph<(),(),Directed>= Graph::new();
108/// let a = graph.add_node(()); // node with no weight
109/// let b = graph.add_node(());
110/// let c = graph.add_node(());
111/// let d = graph.add_node(());
112/// let e = graph.add_node(());
113/// let f = graph.add_node(());
114/// let g = graph.add_node(());
115/// let h = graph.add_node(());
116///
117/// graph.extend_with_edges(&[
118///     (a, b),
119///     (b, c),
120///     (c, d),
121///     (d, a),
122///     (e, f),
123///     (f, g),
124///     (g, h),
125///     (h, e)
126/// ]);
127/// // a ----> b       e ----> f
128/// // ^       |       ^       |
129/// // |       v       |       v
130/// // d <---- c       h <---- g
131///
132/// assert_eq!(connected_components(&graph),2);
133/// graph.add_edge(b,e,());
134/// assert_eq!(connected_components(&graph),1);
135/// ```
136pub fn connected_components<G>(g: G) -> usize
137where
138    G: NodeCompactIndexable + IntoEdgeReferences,
139{
140    let mut node_sets = UnionFind::new(g.node_bound());
141    for edge in g.edge_references() {
142        let (a, b) = (edge.source(), edge.target());
143
144        // union the two nodes of the edge
145        node_sets.union(g.to_index(a), g.to_index(b));
146    }
147
148    let mut labels = node_sets.into_labeling();
149    labels.sort_unstable();
150    labels.dedup();
151    labels.len()
152}
153
154/// Return `true` if the input graph contains a cycle.
155///
156/// Always treats the input graph as if undirected.
157///
158/// # Arguments:
159/// `g`: an input graph that always treated as undirected.
160///
161/// # Returns
162/// `true`: if the input graph contains a cycle.
163/// `false`: otherwise.
164///
165/// # Complexity
166/// * Time complexity: amortized **O(|E|)**.
167/// * Auxiliary space: **O(|V|)**.
168///
169/// where **|V|** is the number of nodes and **|E|** is the number of edges.
170pub fn is_cyclic_undirected<G>(g: G) -> bool
171where
172    G: NodeIndexable + IntoEdgeReferences,
173{
174    let mut edge_sets = UnionFind::new(g.node_bound());
175    for edge in g.edge_references() {
176        let (a, b) = (edge.source(), edge.target());
177
178        // union the two nodes of the edge
179        //  -- if they were already the same, then we have a cycle
180        if !edge_sets.union(g.to_index(a), g.to_index(b)) {
181            return true;
182        }
183    }
184    false
185}
186
187/// Perform a topological sort of a directed graph.
188///
189/// `toposort` returns `Err` on graphs with cycles.
190/// To handle graphs with cycles, use the one of scc algorithms or
191/// [`DfsPostOrder`](struct@crate::visit::DfsPostOrder)
192///   instead of this function.
193///
194/// The implementation is iterative.
195///
196/// # Arguments
197/// * `g`: an acyclic directed graph.
198/// * `space`: optional [`DfsSpace`]. If `space` is not `None`,
199///   it is used instead of creating a new workspace for graph traversal.
200///
201/// # Returns
202/// * `Ok`: a vector of nodes in topological order: each node is ordered before its successors
203///   (if the graph was acyclic).
204/// * `Err`: [`Cycle`] if the graph was not acyclic. Self loops are also cycles this case.
205///
206/// # Complexity
207/// * Time complexity: **O(|V| + |E|)**.
208/// * Auxiliary space: **O(|V|)**.
209///
210/// where **|V|** is the number of nodes and **|E|** is the number of edges.
211pub fn toposort<G>(
212    g: G,
213    space: Option<&mut DfsSpace<G::NodeId, G::Map>>,
214) -> Result<Vec<G::NodeId>, Cycle<G::NodeId>>
215where
216    G: IntoNeighborsDirected + IntoNodeIdentifiers + Visitable,
217{
218    // based on kosaraju scc
219    with_dfs(g, space, |dfs| {
220        dfs.reset(g);
221        let mut finished = g.visit_map();
222
223        let mut finish_stack = Vec::new();
224        for i in g.node_identifiers() {
225            if dfs.discovered.is_visited(&i) {
226                continue;
227            }
228            dfs.stack.push(i);
229            while let Some(&nx) = dfs.stack.last() {
230                if dfs.discovered.visit(nx) {
231                    // First time visiting `nx`: Push neighbors, don't pop `nx`
232                    for succ in g.neighbors(nx) {
233                        if succ == nx {
234                            // self cycle
235                            return Err(Cycle(nx));
236                        }
237                        if !dfs.discovered.is_visited(&succ) {
238                            dfs.stack.push(succ);
239                        }
240                    }
241                } else {
242                    dfs.stack.pop();
243                    if finished.visit(nx) {
244                        // Second time: All reachable nodes must have been finished
245                        finish_stack.push(nx);
246                    }
247                }
248            }
249        }
250        finish_stack.reverse();
251
252        dfs.reset(g);
253        for &i in &finish_stack {
254            dfs.move_to(i);
255            let mut cycle = false;
256            while let Some(j) = dfs.next(Reversed(g)) {
257                if cycle {
258                    return Err(Cycle(j));
259                }
260                cycle = true;
261            }
262        }
263
264        Ok(finish_stack)
265    })
266}
267
268/// Return `true` if the input directed graph contains a cycle.
269///
270/// This implementation is recursive; use [`toposort`] if an alternative is needed.
271///
272/// # Arguments:
273/// `g`: a directed graph.
274///
275/// # Returns
276/// `true`: if the input graph contains a cycle.
277/// `false`: otherwise.
278///
279/// # Complexity
280/// * Time complexity: **O(|V| + |E|)**.
281/// * Auxiliary space: **O(|V|)**.
282///
283/// where **|V|** is the number of nodes and **|E|** is the number of edges.
284pub fn is_cyclic_directed<G>(g: G) -> bool
285where
286    G: IntoNodeIdentifiers + IntoNeighbors + Visitable,
287{
288    use crate::visit::{depth_first_search, DfsEvent};
289
290    depth_first_search(g, g.node_identifiers(), |event| match event {
291        DfsEvent::BackEdge(_, _) => Err(()),
292        _ => Ok(()),
293    })
294    .is_err()
295}
296
297type DfsSpaceType<G> = DfsSpace<<G as GraphBase>::NodeId, <G as Visitable>::Map>;
298
299/// Workspace for a graph traversal.
300#[derive(Clone, Debug)]
301pub struct DfsSpace<N, VM> {
302    dfs: Dfs<N, VM>,
303}
304
305impl<N, VM> DfsSpace<N, VM>
306where
307    N: Copy + PartialEq,
308    VM: VisitMap<N>,
309{
310    pub fn new<G>(g: G) -> Self
311    where
312        G: GraphRef + Visitable<NodeId = N, Map = VM>,
313    {
314        DfsSpace { dfs: Dfs::empty(g) }
315    }
316}
317
318impl<N, VM> Default for DfsSpace<N, VM>
319where
320    VM: VisitMap<N> + Default,
321{
322    fn default() -> Self {
323        DfsSpace {
324            dfs: Dfs {
325                stack: <_>::default(),
326                discovered: <_>::default(),
327            },
328        }
329    }
330}
331
332/// Create a Dfs if it's needed
333fn with_dfs<G, F, R>(g: G, space: Option<&mut DfsSpaceType<G>>, f: F) -> R
334where
335    G: GraphRef + Visitable,
336    F: FnOnce(&mut Dfs<G::NodeId, G::Map>) -> R,
337{
338    let mut local_visitor;
339    let dfs = if let Some(v) = space {
340        &mut v.dfs
341    } else {
342        local_visitor = Dfs::empty(g);
343        &mut local_visitor
344    };
345    f(dfs)
346}
347
348/// Check if there exists a path starting at `from` and reaching `to`.
349///
350/// If `from` and `to` are equal, this function returns true.
351///
352/// # Arguments:
353/// * `g`: an input graph.
354/// * `from`: the first node of a desired path.
355/// * `to`: the last node of a desired path.
356/// * `space`: optional [`DfsSpace`]. If `space` is not `None`,
357///   it is used instead of creating a new workspace for graph traversal.
358///
359/// # Returns
360/// * `true`: if there exists a path starting at `from` and reaching
361///   `to` or `from` and `to` are equal.
362/// * `false`: otherwise.
363///
364/// # Complexity
365/// * Time complexity: **O(|V| + |E|)**.
366/// * Auxiliary space: **O(|V|)** or **O(1)** if `space` was provided.
367///
368/// where **|V|** is the number of nodes and **|E|** is the number of edges.
369pub fn has_path_connecting<G>(
370    g: G,
371    from: G::NodeId,
372    to: G::NodeId,
373    space: Option<&mut DfsSpace<G::NodeId, G::Map>>,
374) -> bool
375where
376    G: IntoNeighbors + Visitable,
377{
378    with_dfs(g, space, |dfs| {
379        dfs.reset(g);
380        dfs.move_to(from);
381        dfs.iter(g).any(|x| x == to)
382    })
383}
384
385/// [Graph] Condense every strongly connected component into a single node and return the result.
386///
387/// # Arguments
388/// * `g`: an input [`Graph`].
389/// * `make_acyclic`: if `true`, self-loops and multi edges are ignored, guaranteeing that
390///   the output is acyclic.
391///
392/// # Returns
393/// Returns a `Graph` with nodes `Vec<N>` representing strongly connected components.
394///
395/// # Complexity
396/// * Time complexity: **O(|V| + |E|)**.
397/// * Auxiliary space: **O(|V| + |E|)**.
398///
399/// where **|V|** is the number of nodes and **|E|** is the number of edges.
400///
401/// # Examples
402/// ```rust
403/// use petgraph::Graph;
404/// use petgraph::algo::condensation;
405/// use petgraph::prelude::*;
406///
407/// let mut graph : Graph<(),(),Directed> = Graph::new();
408/// let a = graph.add_node(()); // node with no weight
409/// let b = graph.add_node(());
410/// let c = graph.add_node(());
411/// let d = graph.add_node(());
412/// let e = graph.add_node(());
413/// let f = graph.add_node(());
414/// let g = graph.add_node(());
415/// let h = graph.add_node(());
416///
417/// graph.extend_with_edges(&[
418///     (a, b),
419///     (b, c),
420///     (c, d),
421///     (d, a),
422///     (b, e),
423///     (e, f),
424///     (f, g),
425///     (g, h),
426///     (h, e)
427/// ]);
428///
429/// // a ----> b ----> e ----> f
430/// // ^       |       ^       |
431/// // |       v       |       v
432/// // d <---- c       h <---- g
433///
434/// let condensed_graph = condensation(graph,false);
435/// let A = NodeIndex::new(0);
436/// let B = NodeIndex::new(1);
437/// assert_eq!(condensed_graph.node_count(), 2);
438/// assert_eq!(condensed_graph.edge_count(), 9);
439/// assert_eq!(condensed_graph.neighbors(A).collect::<Vec<_>>(), vec![A, A, A, A]);
440/// assert_eq!(condensed_graph.neighbors(B).collect::<Vec<_>>(), vec![A, B, B, B, B]);
441/// ```
442/// If `make_acyclic` is true, self-loops and multi edges are ignored:
443///
444/// ```rust
445/// # use petgraph::Graph;
446/// # use petgraph::algo::condensation;
447/// # use petgraph::prelude::*;
448/// #
449/// # let mut graph : Graph<(),(),Directed> = Graph::new();
450/// # let a = graph.add_node(()); // node with no weight
451/// # let b = graph.add_node(());
452/// # let c = graph.add_node(());
453/// # let d = graph.add_node(());
454/// # let e = graph.add_node(());
455/// # let f = graph.add_node(());
456/// # let g = graph.add_node(());
457/// # let h = graph.add_node(());
458/// #
459/// # graph.extend_with_edges(&[
460/// #    (a, b),
461/// #    (b, c),
462/// #    (c, d),
463/// #    (d, a),
464/// #    (b, e),
465/// #    (e, f),
466/// #    (f, g),
467/// #    (g, h),
468/// #    (h, e)
469/// # ]);
470/// let acyclic_condensed_graph = condensation(graph, true);
471/// let A = NodeIndex::new(0);
472/// let B = NodeIndex::new(1);
473/// assert_eq!(acyclic_condensed_graph.node_count(), 2);
474/// assert_eq!(acyclic_condensed_graph.edge_count(), 1);
475/// assert_eq!(acyclic_condensed_graph.neighbors(B).collect::<Vec<_>>(), vec![A]);
476/// ```
477pub fn condensation<N, E, Ty, Ix>(
478    g: Graph<N, E, Ty, Ix>,
479    make_acyclic: bool,
480) -> Graph<Vec<N>, E, Ty, Ix>
481where
482    Ty: EdgeType,
483    Ix: IndexType,
484{
485    let sccs = kosaraju_scc(&g);
486    let mut condensed: Graph<Vec<N>, E, Ty, Ix> = Graph::with_capacity(sccs.len(), g.edge_count());
487
488    // Build a map from old indices to new ones.
489    let mut node_map = vec![NodeIndex::end(); g.node_count()];
490    for comp in sccs {
491        let new_nix = condensed.add_node(Vec::new());
492        for nix in comp {
493            node_map[nix.index()] = new_nix;
494        }
495    }
496
497    // Consume nodes and edges of the old graph and insert them into the new one.
498    let (nodes, edges) = g.into_nodes_edges();
499    for (nix, node) in nodes.into_iter().enumerate() {
500        condensed[node_map[nix]].push(node.weight);
501    }
502    for edge in edges {
503        let source = node_map[edge.source().index()];
504        let target = node_map[edge.target().index()];
505        if make_acyclic {
506            if source != target {
507                condensed.update_edge(source, target, edge.weight);
508            }
509        } else {
510            condensed.add_edge(source, target, edge.weight);
511        }
512    }
513    condensed
514}
515
516/// An algorithm error: a cycle was found in the graph.
517#[derive(Clone, Debug, PartialEq)]
518pub struct Cycle<N>(pub(crate) N);
519
520impl<N> Cycle<N> {
521    /// Return a node id that participates in the cycle
522    pub fn node_id(&self) -> N
523    where
524        N: Copy,
525    {
526        self.0
527    }
528}
529
530/// An algorithm error: a cycle of negative weights was found in the graph.
531#[derive(Clone, Debug, PartialEq)]
532pub struct NegativeCycle(pub ());
533
534/// Return `true` if the graph\* is bipartite.
535///
536/// A graph is bipartite if its nodes can be divided into
537/// two disjoint and indepedent sets U and V such that every edge connects U to one in V.
538///
539/// This algorithm implements 2-coloring algorithm based on the BFS algorithm.
540/// Always treats the input graph as if undirected.
541///
542/// \* The algorithm checks only the subgraph that is reachable from the `start`.
543///
544/// # Arguments
545/// * `g`: an input graph.
546/// * `start`: some node of the graph.
547///
548/// # Returns
549/// * `true`: if the subgraph accessible from the start node is bipartite.
550/// * `false`: if such a subgraph is not bipartite.
551///
552/// # Complexity
553/// * Time complexity: **O(|V| + |E|)**.
554/// * Auxiliary space: **O(|V|)**.
555///
556/// where **|V|** is the number of nodes and **|E|** is the number of edges.
557pub fn is_bipartite_undirected<G, N, VM>(g: G, start: N) -> bool
558where
559    G: GraphRef + Visitable<NodeId = N, Map = VM> + IntoNeighbors<NodeId = N>,
560    N: Copy + PartialEq + core::fmt::Debug,
561    VM: VisitMap<N>,
562{
563    let mut red = g.visit_map();
564    red.visit(start);
565    let mut blue = g.visit_map();
566
567    let mut stack = ::alloc::collections::VecDeque::new();
568    stack.push_front(start);
569
570    while let Some(node) = stack.pop_front() {
571        let is_red = red.is_visited(&node);
572        let is_blue = blue.is_visited(&node);
573
574        assert!(is_red ^ is_blue);
575
576        for neighbour in g.neighbors(node) {
577            let is_neigbour_red = red.is_visited(&neighbour);
578            let is_neigbour_blue = blue.is_visited(&neighbour);
579
580            if (is_red && is_neigbour_red) || (is_blue && is_neigbour_blue) {
581                return false;
582            }
583
584            if !is_neigbour_red && !is_neigbour_blue {
585                //hasn't been visited yet
586
587                match (is_red, is_blue) {
588                    (true, false) => {
589                        blue.visit(neighbour);
590                    }
591                    (false, true) => {
592                        red.visit(neighbour);
593                    }
594                    (_, _) => {
595                        panic!("Invariant doesn't hold");
596                    }
597                }
598
599                stack.push_back(neighbour);
600            }
601        }
602    }
603
604    true
605}
606
607use core::fmt::Debug;
608use core::ops::Add;
609
610/// Associated data that can be used for measures (such as length).
611pub trait Measure: Debug + PartialOrd + Add<Self, Output = Self> + Default + Clone {}
612
613impl<M> Measure for M where M: Debug + PartialOrd + Add<M, Output = M> + Default + Clone {}
614
615/// A floating-point measure.
616pub trait FloatMeasure: Measure + Copy {
617    fn zero() -> Self;
618    fn infinite() -> Self;
619    fn from_f32(val: f32) -> Self;
620    fn from_f64(val: f64) -> Self;
621}
622
623impl FloatMeasure for f32 {
624    fn zero() -> Self {
625        0.
626    }
627    fn infinite() -> Self {
628        1. / 0.
629    }
630    fn from_f32(val: f32) -> Self {
631        val
632    }
633    fn from_f64(val: f64) -> Self {
634        val as f32
635    }
636}
637
638impl FloatMeasure for f64 {
639    fn zero() -> Self {
640        0.
641    }
642    fn infinite() -> Self {
643        1. / 0.
644    }
645    fn from_f32(val: f32) -> Self {
646        val as f64
647    }
648    fn from_f64(val: f64) -> Self {
649        val
650    }
651}
652
653pub trait BoundedMeasure: Measure + core::ops::Sub<Self, Output = Self> {
654    fn min() -> Self;
655    fn max() -> Self;
656    fn overflowing_add(self, rhs: Self) -> (Self, bool);
657    fn from_f32(val: f32) -> Self;
658    fn from_f64(val: f64) -> Self;
659}
660
661macro_rules! impl_bounded_measure_integer(
662    ( $( $t:ident ),* ) => {
663        $(
664            impl BoundedMeasure for $t {
665                fn min() -> Self {
666                    $t::MIN
667                }
668
669                fn max() -> Self {
670                    $t::MAX
671                }
672
673                fn overflowing_add(self, rhs: Self) -> (Self, bool) {
674                    self.overflowing_add(rhs)
675                }
676
677                fn from_f32(val: f32) -> Self {
678                    val as $t
679                }
680
681                fn from_f64(val: f64) -> Self {
682                    val as $t
683                }
684            }
685        )*
686    };
687);
688
689impl_bounded_measure_integer!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
690
691macro_rules! impl_bounded_measure_float(
692    ( $( $t:ident ),* ) => {
693        $(
694            impl BoundedMeasure for $t {
695                fn min() -> Self {
696                    $t::MIN
697                }
698
699                fn max() -> Self {
700                    $t::MAX
701                }
702
703                fn overflowing_add(self, rhs: Self) -> (Self, bool) {
704                    // for an overflow: a + b > max: both values need to be positive and a > max - b must be satisfied
705                    let overflow = self > Self::default() && rhs > Self::default() && self > $t::MAX - rhs;
706
707                    // for an underflow: a + b < min: overflow can not happen and both values must be negative and a < min - b must be satisfied
708                    let underflow = !overflow && self < Self::default() && rhs < Self::default() && self < $t::MIN - rhs;
709
710                    (self + rhs, overflow || underflow)
711                }
712
713                fn from_f32(val: f32) -> Self {
714                    val as $t
715                }
716
717                fn from_f64(val: f64) -> Self {
718                    val as $t
719                }
720            }
721        )*
722    };
723);
724
725impl_bounded_measure_float!(f32, f64);
726
727/// A floating-point measure that can be computed from `usize`
728/// and with a default measure of proximity.  
729pub trait UnitMeasure:
730    Measure
731    + core::ops::Sub<Self, Output = Self>
732    + core::ops::Mul<Self, Output = Self>
733    + core::ops::Div<Self, Output = Self>
734    + core::iter::Sum
735{
736    fn zero() -> Self;
737    fn one() -> Self;
738    fn from_usize(nb: usize) -> Self;
739    fn default_tol() -> Self;
740    fn from_f32(val: f32) -> Self;
741    fn from_f64(val: f64) -> Self;
742}
743
744macro_rules! impl_unit_measure(
745    ( $( $t:ident ),* )=> {
746        $(
747            impl UnitMeasure for $t {
748                fn zero() -> Self {
749                    0 as $t
750                }
751                fn one() -> Self {
752                    1 as $t
753                }
754
755                fn from_usize(nb: usize) -> Self {
756                    nb as $t
757                }
758
759                fn default_tol() -> Self {
760                    1e-6 as $t
761                }
762
763                fn from_f32(val: f32) -> Self {
764                    val as $t
765                }
766
767                fn from_f64(val: f64) -> Self {
768                    val as $t
769                }
770            }
771
772        )*
773    }
774);
775impl_unit_measure!(f32, f64);
776
777/// Some measure of positive numbers, assuming positive
778/// float-pointing numbers
779pub trait PositiveMeasure: Measure + Copy {
780    fn zero() -> Self;
781    fn max() -> Self;
782}
783
784macro_rules! impl_positive_measure(
785    ( $( $t:ident ),* )=> {
786        $(
787            impl PositiveMeasure for $t {
788                fn zero() -> Self {
789                    0 as $t
790                }
791                fn max() -> Self {
792                    $t::MAX
793                }
794            }
795
796        )*
797    }
798);
799
800impl_positive_measure!(u8, u16, u32, u64, u128, usize, f32, f64);