netoptim_rs/
parametric.rs

1// use std::collections::HashMap;
2// use std::cmp::Ordering;
3use std::hash::Hash;
4use std::ops::Add;
5use std::ops::Div;
6use std::ops::Mul;
7use std::ops::Neg;
8use std::ops::Sub;
9
10use petgraph::graph::{DiGraph, EdgeReference};
11// use petgraph::prelude::*;
12// use petgraph::visit::EdgeRef;
13// use petgraph::visit::IntoNodeIdentifiers;
14// use petgraph::Direction;
15
16// use num::traits::Float;
17use num::traits::Inv;
18use num::traits::One;
19use num::traits::Zero;
20
21use crate::neg_cycle::NegCycleFinder;
22
23/// The `ParametricAPI` trait defines two methods: `distance` and `zero_cancel`.
24pub trait ParametricAPI<E, R>
25where
26    R: Copy + PartialOrd,
27    E: Clone,
28{
29    fn distance(&self, ratio: &R, edge: &EdgeReference<R>) -> R;
30    fn zero_cancel(&self, cycle: &[EdgeReference<R>]) -> R;
31}
32
33/// The `MaxParametricSolver` struct is a generic type that takes in parameters `V`, `R`, and `P` and
34/// contains a `NegCycleFinder` and `omega` of type `P`.
35///
36/// Properties:
37///
38/// * `ncf`: NegCycleFinder is a struct that is used to find negative cycles in a graph. It takes three
39///             type parameters: 'a, V, and R. 'a represents the lifetime of the struct, V represents the type of
40///             the vertices in the graph, and R represents the type of the weights or
41/// * `omega`: The `omega` property is of type `P`, which is a generic type parameter that implements
42///             the `ParametricAPI` trait. This trait is not defined in the code snippet you provided, so it is
43///             likely defined elsewhere in the codebase.
44#[derive(Debug)]
45pub struct MaxParametricSolver<'a, V, R, P>
46where
47    R: Copy
48        + PartialOrd
49        + Add<Output = R>
50        + Sub<Output = R>
51        + Mul<Output = R>
52        + Div<Output = R>
53        + Neg<Output = R>
54        + Inv<Output = R>,
55    V: Eq + Hash + Clone,
56    P: ParametricAPI<V, R>,
57{
58    ncf: NegCycleFinder<'a, V, R>,
59    omega: P,
60}
61
62impl<'a, V, R, P> MaxParametricSolver<'a, V, R, P>
63where
64    R: Copy
65        + PartialOrd
66        + Zero
67        + One
68        + Add<Output = R>
69        + Sub<Output = R>
70        + Mul<Output = R>
71        + Div<Output = R>
72        + Neg<Output = R>
73        + Inv<Output = R>,
74    V: Eq + Hash + Clone,
75    P: ParametricAPI<V, R>,
76{
77    /// The function creates a new instance of a struct with a given directed graph and a value.
78    ///
79    /// Arguments:
80    ///
81    /// * `grph`: The `grph` parameter is a reference to a directed graph (`DiGraph`) with vertices of
82    ///             type `V` and edges of type `R`.
83    /// * `omega`: The `omega` parameter is of type `P`. It represents some value or parameter that is
84    ///             used in the implementation of the `new` function. The specific meaning or purpose of `omega`
85    ///             would depend on the context and the code that uses this function.
86    ///
87    /// Returns:
88    ///
89    /// The `new` function is returning an instance of the struct that it is defined in.
90    pub fn new(grph: &'a DiGraph<V, R>, omega: P) -> Self {
91        Self {
92            ncf: NegCycleFinder::new(grph),
93            omega,
94        }
95    }
96
97    /// The function `run` finds the minimum ratio and corresponding cycle in a given graph.
98    ///
99    /// Arguments:
100    ///
101    /// * `dist`: `dist` is a mutable reference to a slice of type `R`. It represents a distance matrix
102    ///             or array, where `R` is the type of the elements in the matrix.
103    /// * `ratio`: The `ratio` parameter is a mutable reference to a value of type `R`. It represents
104    ///             the current ratio value that is being used in the algorithm. The algorithm will update this
105    ///             value if it finds a smaller ratio during its execution.
106    ///
107    /// Returns:
108    ///
109    /// a vector of `EdgeReference<R>`.
110    pub fn run(&mut self, dist: &mut [R], ratio: &mut R) -> Vec<EdgeReference<R>> {
111        let mut r_min = *ratio;
112        let mut c_min = Vec::<EdgeReference<R>>::new();
113        let mut cycle = Vec::<EdgeReference<R>>::new();
114        loop {
115            if let Some(ci) = self.ncf.howard(dist, |e| self.omega.distance(ratio, &e)) {
116                let ri = self.omega.zero_cancel(&ci);
117                if r_min > ri {
118                    r_min = ri;
119                    c_min = ci;
120                }
121            }
122            if r_min >= *ratio {
123                break;
124            }
125            cycle.clone_from(&c_min);
126            *ratio = r_min;
127        }
128        cycle
129    }
130}