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);