best_path/best_path_calculator/floyd_warshall/
calculator.rs1#[cfg(not(feature = "std"))]
2#[allow(unused_imports)]
3use alloc::{
4 borrow::ToOwned,
5 collections::{BTreeMap, BTreeSet},
6 string::String,
7 vec, vec::Vec,
8};
9use super::algo;
10use crate::types::*;
11use crate::*;
12#[cfg(feature = "std")]
13use std::collections::{BTreeMap, BTreeSet};
14
15impl From<algo::PathCalculationError> for CalculatorError {
16 fn from(err: algo::PathCalculationError) -> Self {
17 match err {
18 algo::PathCalculationError::NegativeCyclesError => CalculatorError::NegativeCyclesError
19 }
20 }
21}
22
23pub const SCALE: f64 = 1_000_000_000_000.0;
24
25pub struct FloydWarshallCalculator {}
26
27impl<C: Currency, A: Amount, P: Provider> BestPathCalculator<C, A, P> for FloydWarshallCalculator {
28
29 fn calc_best_paths(pairs_and_prices: &[(ProviderPair<C, P>, A)]) -> Result<PricePathGraph<C, A, P>, CalculatorError> {
58 let currencies = pairs_and_prices.iter().flat_map(|(ProviderPair { pair: Pair{source, target}, .. }, ..)| vec![source, target].into_iter())
60 .collect::<BTreeSet<_>>().into_iter().collect::<Vec<_>>();
61 let providers = pairs_and_prices.iter().map(|(ProviderPair { provider, .. }, ..)| provider)
62 .collect::<BTreeSet<_>>().into_iter().collect::<Vec<_>>();
63 let currencies_by_ind = currencies.iter().enumerate().map(|(i, &x)| (x, i)).collect::<BTreeMap<_, _>>();
64 let providers_by_ind = providers.iter().enumerate().map(|(i, &x)| (x, i)).collect::<BTreeMap<_, _>>();
65
66 let mut graph = Vec::new();
68 for &c in currencies.iter() {
69 for (pp, cost) in pairs_and_prices {
70 if c == &pp.pair.source {
71 graph.push(algo::Edge {
72 pair: algo::Pair{source: currencies_by_ind[&pp.pair.source], target: currencies_by_ind[&pp.pair.target]},
73 provider: providers_by_ind[&pp.provider],
74 cost: TryInto::<u128>::try_into(*cost).map_err(|_| CalculatorError::ConversionError)? as f64 / SCALE
75 });
76 }
77 }
78 }
79
80 let res = algo::longest_paths_mult(&graph)?;
82 let res_map = res.into_iter().map(|(algo::Pair{source, target}, algo::Path{total_cost, edges})| {
83 let pair = Pair{source: currencies[source].clone(), target: currencies[target].clone()};
84 let total_cost_u128 = (total_cost * SCALE) as u128;
85 let path = PricePath{ total_cost: total_cost_u128.try_into().ok().unwrap(), steps: edges.into_iter().map(|algo::Edge{pair: algo::Pair{source, target, ..}, provider, cost}|
86 PathStep{pair: Pair{source: currencies[source].clone(), target: currencies[target].clone()}, provider: providers[provider].clone(), cost: ((cost * SCALE) as u128).try_into().ok().unwrap()}).collect()
87 };
88 (pair, path)
89 }).collect::<BTreeMap<_, _>>();
90 Ok(res_map)
91 }
92}