diff --git a/CHANGELOG.md b/CHANGELOG.md index 85827b7f3..968ee2950 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,10 @@ are already published. So, I stick to it for now. * apply some performance optimizations * refactor dbscan clustering api +### Removed + +* replace `compare_floats` with built-in `total_cmp` + ## [1.24.0] 2024-07-13 diff --git a/experiments/heuristic-research/src/plots/drawing/draw_population.rs b/experiments/heuristic-research/src/plots/drawing/draw_population.rs index 5b4ec903b..bd4988ec6 100644 --- a/experiments/heuristic-research/src/plots/drawing/draw_population.rs +++ b/experiments/heuristic-research/src/plots/drawing/draw_population.rs @@ -1,6 +1,6 @@ use super::*; use itertools::{Itertools, MinMaxResult}; -use rosomaxa::prelude::{compare_floats, compare_floats_refs, Float}; +use rosomaxa::prelude::Float; use std::cmp::Ordering; /// Draws rosomaxa population state. @@ -35,10 +35,8 @@ pub(crate) fn draw_on_area( series: &Series2D| -> DrawResult<()> { let matrix: MatrixData = (series.matrix_fn)(); - let (min, max, size) = match matrix.iter().minmax_by(|(_, &a), (_, &b)| compare_floats(a, b)) { - MinMaxResult::OneElement((_, &value)) if compare_floats(value, 0.) != Ordering::Equal => { - (value, value, value) - } + let (min, max, size) = match matrix.iter().minmax_by(|(_, a), (_, b)| a.total_cmp(b)) { + MinMaxResult::OneElement((_, &value)) if value != 0. => (value, value, value), MinMaxResult::MinMax((_, &min), (_, &max)) => (min, max, max - min), _ => (1., 1., 1.), }; @@ -91,7 +89,7 @@ pub(crate) fn draw_on_area( let compare_fitness = |left: &[Float], right: &[Float]| { (left.iter()) .zip(right.iter()) - .map(|(lhs, rhs)| compare_floats_refs(lhs, rhs)) + .map(|(lhs, rhs)| lhs.total_cmp(rhs)) .find_or_first(|ord| *ord != Ordering::Equal) .unwrap_or(Ordering::Equal) }; diff --git a/experiments/heuristic-research/src/plots/drawing/draw_search.rs b/experiments/heuristic-research/src/plots/drawing/draw_search.rs index ba7ccba09..0b1ff63fa 100644 --- a/experiments/heuristic-research/src/plots/drawing/draw_search.rs +++ b/experiments/heuristic-research/src/plots/drawing/draw_search.rs @@ -1,6 +1,6 @@ use super::*; use plotters::style::full_palette::BLUE_200; -use rosomaxa::prelude::{compare_floats_refs, Float}; +use rosomaxa::prelude::Float; const TOP_SIZE: usize = 25; @@ -59,7 +59,7 @@ fn draw_bar_plot( ) -> DrawResult<()> { area.fill(&WHITE)?; - let max_x = data.iter().copied().max_by(compare_floats_refs).unwrap_or(1.); + let max_x = data.iter().copied().max_by(|a, b| a.total_cmp(b)).unwrap_or(1.); let max_y = data.len() - 1; // TODO: improve font size detection let font_size = if max_y < TOP_SIZE { 16 } else { 6 }; diff --git a/rosomaxa/src/algorithms/gsom/network.rs b/rosomaxa/src/algorithms/gsom/network.rs index 9ba795b39..70b4a9998 100644 --- a/rosomaxa/src/algorithms/gsom/network.rs +++ b/rosomaxa/src/algorithms/gsom/network.rs @@ -183,7 +183,7 @@ where /// Returns max unified distance of the network. pub fn max_unified_distance(&self) -> Float { - self.get_nodes().map(|node| node.unified_distance(self, 1)).max_by(compare_floats_refs).unwrap_or(0.) + self.get_nodes().map(|node| node.unified_distance(self, 1)).max_by(|a, b| a.total_cmp(b)).unwrap_or(0.) } /// Trains network on an input. @@ -243,10 +243,7 @@ where } let node = self.nodes.get(coord).unwrap(); - ( - matches!(compare_floats(node.error, self.growing_threshold), Ordering::Equal | Ordering::Greater), - node.is_boundary(self) && is_new_input, - ) + (node.error >= self.growing_threshold, node.is_boundary(self) && is_new_input) }; match (exceeds_ae, can_grow) { @@ -444,7 +441,7 @@ where fn compare_input(left: &I, right: &I) -> Ordering { (left.weights().iter()) .zip(right.weights().iter()) - .map(|(lhs, rhs)| compare_floats_refs(lhs, rhs)) + .map(|(lhs, rhs)| lhs.total_cmp(rhs)) .find(|ord| *ord != Ordering::Equal) .unwrap_or(Ordering::Equal) } diff --git a/rosomaxa/src/algorithms/math/distance.rs b/rosomaxa/src/algorithms/math/distance.rs index 32b4a5241..ef7b21c01 100644 --- a/rosomaxa/src/algorithms/math/distance.rs +++ b/rosomaxa/src/algorithms/math/distance.rs @@ -3,8 +3,6 @@ mod distance_test; use crate::prelude::Float; -use crate::utils::compare_floats; -use std::cmp::Ordering; /// Calculates relative distance between two vectors. As weights are not normalized, apply /// standardization using relative change: D = |x - y| / max(|x|, |y|) @@ -16,7 +14,7 @@ where a.zip(b) .fold(Float::default(), |acc, (a, b)| { let divider = a.abs().max(b.abs()); - let change = if compare_floats(divider, 0.) == Ordering::Equal { 0. } else { (a - b).abs() / divider }; + let change = if divider == 0. { 0. } else { (a - b).abs() / divider }; acc + change * change }) diff --git a/rosomaxa/src/algorithms/math/statistics.rs b/rosomaxa/src/algorithms/math/statistics.rs index b4b059d4d..f5a115f25 100644 --- a/rosomaxa/src/algorithms/math/statistics.rs +++ b/rosomaxa/src/algorithms/math/statistics.rs @@ -1,11 +1,9 @@ use crate::prelude::Float; -use crate::utils::compare_floats; -use std::cmp::Ordering; /// Returns coefficient variation. pub fn get_cv(values: &[Float]) -> Float { let (variance, mean) = get_variance_mean(values); - if compare_floats(mean, 0.) == Ordering::Equal { + if mean == 0. { return 0.; } let sdev = variance.sqrt(); diff --git a/rosomaxa/src/evolution/telemetry.rs b/rosomaxa/src/evolution/telemetry.rs index e79acbcae..5f3c73c45 100644 --- a/rosomaxa/src/evolution/telemetry.rs +++ b/rosomaxa/src/evolution/telemetry.rs @@ -8,7 +8,6 @@ use crate::algorithms::math::relative_distance; use crate::prelude::*; use crate::utils::Timer; use crate::{DynHeuristicPopulation, RemedianUsize}; -use std::cmp::Ordering; use std::fmt::Write; use std::marker::PhantomData; @@ -414,7 +413,7 @@ impl SpeedTracker { _ => 1., }; - let is_slow = compare_floats(ratio, 1.) == Ordering::Less; + let is_slow = ratio < 1.; let median = self.median.approx_median(); self.speed = match &self.speed { diff --git a/rosomaxa/src/example.rs b/rosomaxa/src/example.rs index 1aade7ad6..6bbf63054 100644 --- a/rosomaxa/src/example.rs +++ b/rosomaxa/src/example.rs @@ -133,7 +133,7 @@ impl HeuristicObjective for VectorObjective { type Solution = VectorSolution; fn total_order(&self, a: &Self::Solution, b: &Self::Solution) -> Ordering { - a.fitness().next().zip(b.fitness().next()).map(|(a, b)| compare_floats(a, b)).expect("expecting fitness") + a.fitness().next().zip(b.fitness().next()).map(|(a, b)| a.total_cmp(&b)).expect("expecting fitness") } } diff --git a/rosomaxa/src/hyper/dynamic_selective.rs b/rosomaxa/src/hyper/dynamic_selective.rs index 6dc50ef39..f5b715dd1 100644 --- a/rosomaxa/src/hyper/dynamic_selective.rs +++ b/rosomaxa/src/hyper/dynamic_selective.rs @@ -5,7 +5,7 @@ mod dynamic_selective_test; use super::*; use crate::algorithms::math::RemedianUsize; use crate::algorithms::rl::{SlotAction, SlotFeedback, SlotMachine}; -use crate::utils::{compare_floats, random_argmax, DefaultDistributionSampler}; +use crate::utils::{random_argmax, DefaultDistributionSampler}; use crate::Timer; use std::cmp::Ordering; use std::collections::HashMap; @@ -350,7 +350,7 @@ where let distance_best = get_relative_distance(objective, new_solution, best_known); // NOTE remap distances to range [0, 2] - match (compare_floats(distance_initial, 0.), compare_floats(distance_best, 0.)) { + match (distance_initial.total_cmp(&0.), distance_best.total_cmp(&0.)) { (Ordering::Greater, Ordering::Greater) => { (distance_initial + 1.) + (distance_best + 1.) * BEST_DISCOVERY_REWARD_MULTIPLIER } @@ -417,7 +417,7 @@ where .fitness() .zip(b.fitness()) .enumerate() - .find(|(_, (fitness_a, fitness_b))| compare_floats_refs(fitness_a, fitness_b) != Ordering::Equal) + .find(|(_, (fitness_a, fitness_b))| fitness_a != fitness_b) .map(|(idx, _)| idx); let idx = if let Some(idx) = idx { diff --git a/rosomaxa/src/population/elitism.rs b/rosomaxa/src/population/elitism.rs index 88083ee61..f50d3a74c 100644 --- a/rosomaxa/src/population/elitism.rs +++ b/rosomaxa/src/population/elitism.rs @@ -177,10 +177,7 @@ where fn is_improved(&self, best_known_fitness: Option>) -> bool { best_known_fitness.zip(self.individuals.first()).map_or(true, |(best_known_fitness, new_best_known)| { - best_known_fitness - .into_iter() - .zip(new_best_known.fitness()) - .any(|(a, b)| compare_floats(a, b) != Ordering::Equal) + best_known_fitness.into_iter().zip(new_best_known.fitness()).any(|(a, b)| a != b) }) } } diff --git a/rosomaxa/src/population/rosomaxa.rs b/rosomaxa/src/population/rosomaxa.rs index 0dddbeac7..41c511ab2 100644 --- a/rosomaxa/src/population/rosomaxa.rs +++ b/rosomaxa/src/population/rosomaxa.rs @@ -539,7 +539,7 @@ where let fitness_a = a.fitness(); let fitness_b = b.fitness(); - fitness_a.zip(fitness_b).all(|(a, b)| compare_floats(a, b) == Ordering::Equal) + fitness_a.zip(fitness_b).all(|(a, b)| a == b) } _ => { let weights_a = a.weights(); diff --git a/rosomaxa/src/prelude.rs b/rosomaxa/src/prelude.rs index a64b0a84b..fd66051df 100644 --- a/rosomaxa/src/prelude.rs +++ b/rosomaxa/src/prelude.rs @@ -25,6 +25,7 @@ pub use crate::hyper::HyperHeuristic; pub use crate::termination::Termination; +pub use crate::utils::short_type_name; pub use crate::utils::DefaultRandom; pub use crate::utils::Environment; pub use crate::utils::Float; @@ -32,6 +33,5 @@ pub use crate::utils::InfoLogger; pub use crate::utils::Noise; pub use crate::utils::Quota; pub use crate::utils::UnwrapValue; -pub use crate::utils::{compare_floats, compare_floats_refs, short_type_name}; pub use crate::utils::{GenericError, GenericResult}; pub use crate::utils::{Random, RandomGen}; diff --git a/rosomaxa/src/termination/mod.rs b/rosomaxa/src/termination/mod.rs index 2aee0e7f0..98228c566 100644 --- a/rosomaxa/src/termination/mod.rs +++ b/rosomaxa/src/termination/mod.rs @@ -66,6 +66,6 @@ where } fn estimate(&self, heuristic_ctx: &Self::Context) -> Float { - self.terminations.iter().map(|t| t.estimate(heuristic_ctx)).max_by(compare_floats_refs).unwrap_or(0.) + self.terminations.iter().map(|t| t.estimate(heuristic_ctx)).max_by(|a, b| a.total_cmp(b)).unwrap_or(0.) } } diff --git a/rosomaxa/src/utils/comparison.rs b/rosomaxa/src/utils/comparison.rs deleted file mode 100644 index 5f36dea69..000000000 --- a/rosomaxa/src/utils/comparison.rs +++ /dev/null @@ -1,27 +0,0 @@ -use crate::utils::Float; -use std::cmp::{Ordering, PartialOrd}; - -macro_rules! compare_float_types { - ($fn_name_: ident, $type_: ty) => { - /// Compares floating point numbers. - #[inline] - pub fn $fn_name_(a: $type_, b: $type_) -> Ordering { - match a.partial_cmp(&b) { - Some(ordering) => ordering, - None => match (a.is_nan(), b.is_nan()) { - (true, false) => Ordering::Greater, - (false, true) => Ordering::Less, - _ => Ordering::Equal, - }, - } - } - }; -} - -compare_float_types! { compare_floats, Float} -compare_float_types! { compare_floats_refs, &Float} - -compare_float_types! { compare_floats_f32, f32} -compare_float_types! { compare_floats_f32_refs, &f32} -compare_float_types! { compare_floats_f64, f64} -compare_float_types! { compare_floats_f64_refs, &f64} diff --git a/rosomaxa/src/utils/mod.rs b/rosomaxa/src/utils/mod.rs index 8e2c79e3c..f32ca7e7c 100644 --- a/rosomaxa/src/utils/mod.rs +++ b/rosomaxa/src/utils/mod.rs @@ -1,8 +1,5 @@ //! This module contains helper functionality. -mod comparison; -pub use self::comparison::*; - mod environment; pub use self::environment::*; diff --git a/rosomaxa/tests/unit/algorithms/gsom/network_test.rs b/rosomaxa/tests/unit/algorithms/gsom/network_test.rs index 4e375b21c..858ac27f9 100644 --- a/rosomaxa/tests/unit/algorithms/gsom/network_test.rs +++ b/rosomaxa/tests/unit/algorithms/gsom/network_test.rs @@ -7,8 +7,7 @@ type NetworkType = Network; mod common { use super::*; use crate::helpers::algorithms::gsom::create_test_network; - use crate::utils::{compare_floats, DefaultRandom}; - use std::cmp::Ordering; + use crate::utils::DefaultRandom; #[test] fn can_train_network() { @@ -112,7 +111,7 @@ mod common { // -1-1 0-1 +1-1 assert_eq!(network.nodes.len(), 9); network.nodes.iter().filter(|(coord, _)| **coord != Coordinate(0, 0)).for_each(|(coord, node)| { - if compare_floats(node.error, 42.) != Ordering::Equal { + if node.error != 42. { unreachable!("node is not updated: ({},{}), value: {}", coord.0, coord.1, node.error); } }); diff --git a/rosomaxa/tests/unit/evolution/telemetry_test.rs b/rosomaxa/tests/unit/evolution/telemetry_test.rs index d492d3047..bea5b0d22 100644 --- a/rosomaxa/tests/unit/evolution/telemetry_test.rs +++ b/rosomaxa/tests/unit/evolution/telemetry_test.rs @@ -1,15 +1,13 @@ use super::*; use crate::example::*; use crate::helpers::example::create_example_objective; -use crate::utils::compare_floats; use crate::{get_default_population, get_default_selection_size}; -use std::cmp::Ordering; use std::sync::Arc; fn compare_statistic(statistics: &HeuristicStatistics, expected: (usize, Float, Float)) { assert_eq!(statistics.generation, expected.0); - assert_eq!(compare_floats(statistics.improvement_all_ratio, expected.1), Ordering::Equal); - assert_eq!(compare_floats(statistics.improvement_1000_ratio, expected.2), Ordering::Equal); + assert_eq!(statistics.improvement_all_ratio, expected.1); + assert_eq!(statistics.improvement_1000_ratio, expected.2); } #[test] diff --git a/vrp-core/src/algorithms/geometry/point.rs b/vrp-core/src/algorithms/geometry/point.rs index 64f917eb1..24fa6b994 100644 --- a/vrp-core/src/algorithms/geometry/point.rs +++ b/vrp-core/src/algorithms/geometry/point.rs @@ -2,8 +2,7 @@ #[path = "../../../tests/unit/algorithms/geometry/point_test.rs"] mod point_test; -use rosomaxa::prelude::{compare_floats, Float}; -use std::cmp::Ordering; +use rosomaxa::prelude::Float; use std::hash::{Hash, Hasher}; /// Represents a point in 2D space. @@ -33,7 +32,7 @@ impl Point { pub fn distance_to_line(&self, a: &Point, b: &Point) -> Float { let a_b_distance = a.distance_to_point(b); - if compare_floats(a_b_distance, 0.) == Ordering::Equal { + if a_b_distance == 0. { 0. } else { (Self::cross_product(a, b, self) / a_b_distance).abs() diff --git a/vrp-core/src/construction/clustering/dbscan/mod.rs b/vrp-core/src/construction/clustering/dbscan/mod.rs index 6bb7aae59..23abb76d0 100644 --- a/vrp-core/src/construction/clustering/dbscan/mod.rs +++ b/vrp-core/src/construction/clustering/dbscan/mod.rs @@ -10,7 +10,6 @@ use crate::models::common::Profile; use crate::models::problem::{Job, Single}; use crate::prelude::{Cost, Fleet}; use rosomaxa::prelude::*; -use std::cmp::Ordering; use std::collections::HashSet; use std::sync::Arc; @@ -82,8 +81,8 @@ where costs.iter_mut().for_each(|cost| *cost /= fleet.profiles.len() as Float); // sort all distances in ascending order - costs.sort_unstable_by(compare_floats_refs); - costs.dedup_by(|a, b| compare_floats(*a, *b) == Ordering::Equal); + costs.sort_unstable_by(|a, b| a.total_cmp(b)); + costs.dedup_by(|a, b| a == b); costs } diff --git a/vrp-core/src/construction/clustering/vicinity/estimations.rs b/vrp-core/src/construction/clustering/vicinity/estimations.rs index 9ec5bb7a0..62b4fd6f5 100644 --- a/vrp-core/src/construction/clustering/vicinity/estimations.rs +++ b/vrp-core/src/construction/clustering/vicinity/estimations.rs @@ -141,7 +141,7 @@ fn get_dissimilarities( outer_time.overlapping(inner_time).map(|tw| tw.duration()) }) }) - .max_by(compare_floats_refs) + .max_by(|a, b| a.total_cmp(b)) .unwrap_or(0.); if shared_time > min_shared_time { @@ -151,8 +151,7 @@ fn get_dissimilarities( let bck_distance = transport.distance_approx(&config.profile, inner_loc, outer_loc); let bck_duration = transport.duration_approx(&config.profile, inner_loc, outer_loc); - let reachable = compare_floats(fwd_distance, 0.) != Ordering::Less - && compare_floats(bck_distance, 0.) != Ordering::Less; + let reachable = fwd_distance >= 0. && bck_distance >= 0.; let reachable = reachable && (fwd_duration - config.threshold.moving_duration < 0.) diff --git a/vrp-core/src/construction/enablers/departure_time.rs b/vrp-core/src/construction/enablers/departure_time.rs index 60942b58e..2fff562f3 100644 --- a/vrp-core/src/construction/enablers/departure_time.rs +++ b/vrp-core/src/construction/enablers/departure_time.rs @@ -6,8 +6,7 @@ use crate::construction::enablers::*; use crate::construction::heuristics::RouteContext; use crate::models::common::Timestamp; use crate::models::problem::{ActivityCost, TransportCost, TravelTime}; -use rosomaxa::prelude::{compare_floats, Float}; -use std::cmp::Ordering; +use rosomaxa::prelude::Float; /// Tries to move forward route's departure time. pub fn advance_departure_time( @@ -93,8 +92,9 @@ fn try_recede_departure_time(route_ctx: &RouteContext) -> Option { .map(|(&total, &limit)| (limit - total).min(max_change)) .unwrap_or(max_change); - match compare_floats(max_change, 0.) { - Ordering::Greater => Some(start.schedule.departure - max_change), - _ => None, + if max_change > 0. { + Some(start.schedule.departure - max_change) + } else { + None } } diff --git a/vrp-core/src/construction/enablers/reserved_time.rs b/vrp-core/src/construction/enablers/reserved_time.rs index b27127f98..a5841c29b 100644 --- a/vrp-core/src/construction/enablers/reserved_time.rs +++ b/vrp-core/src/construction/enablers/reserved_time.rs @@ -5,8 +5,7 @@ mod reserved_time_test; use crate::models::common::*; use crate::models::problem::{ActivityCost, Actor, TransportCost, TravelTime}; use crate::models::solution::{Activity, Route}; -use rosomaxa::prelude::{compare_floats, Float, GenericError}; -use std::cmp::Ordering; +use rosomaxa::prelude::{Float, GenericError}; use std::collections::HashMap; use std::sync::Arc; @@ -204,7 +203,7 @@ pub(crate) fn create_reserved_times_fn( (TimeSpan::Offset(a), TimeSpan::Offset(b)) => (a.start, b.start), _ => unreachable!(), }; - compare_floats(a, b) + a.total_cmp(&b) }); let has_no_intersections = times.windows(2).all(|pair| { if let [ReservedTimeSpan { time: a, .. }, ReservedTimeSpan { time: b, .. }] = pair { @@ -260,8 +259,7 @@ pub(crate) fn create_reserved_times_fn( }; // NOTE use exclusive intersection - compare_floats(interval_start, reserved_end) == Ordering::Less - && compare_floats(reserved_start, interval_end) == Ordering::Less + interval_start < reserved_end && reserved_start < interval_end }) }) .flatten(), diff --git a/vrp-core/src/construction/features/recharge.rs b/vrp-core/src/construction/features/recharge.rs index 0e454398c..3079d3d40 100644 --- a/vrp-core/src/construction/features/recharge.rs +++ b/vrp-core/src/construction/features/recharge.rs @@ -8,7 +8,6 @@ mod recharge_test; use super::*; use crate::construction::enablers::*; use crate::models::solution::Route; -use std::cmp::Ordering; use std::collections::HashSet; use std::sync::Arc; @@ -148,7 +147,7 @@ impl RechargeFeatureBuilder { + get_distance(route_ctx.route(), left.end, right.start + 1); (distance_limit_fn)(route_ctx.route().actor.as_ref()) - .map_or(false, |threshold| compare_floats(new_distance, threshold) != Ordering::Greater) + .map_or(false, |threshold| new_distance <= threshold) } }), is_assignable_fn, diff --git a/vrp-core/src/construction/features/total_value.rs b/vrp-core/src/construction/features/total_value.rs index dedf21657..57becd7ef 100644 --- a/vrp-core/src/construction/features/total_value.rs +++ b/vrp-core/src/construction/features/total_value.rs @@ -7,7 +7,6 @@ mod total_value_test; use super::*; use crate::models::problem::Actor; use crate::utils::Either; -use std::cmp::Ordering; /// Specifies a job value function which takes into account actor and job. pub type ActorValueFn = Arc Float + Send + Sync>; @@ -82,11 +81,7 @@ impl FeatureConstraint for MaximizeTotalValueConstraint { let candidate_value = (left_fn)(&candidate); let new_value = source_value + candidate_value; - Ok(if compare_floats(new_value, source_value) != Ordering::Equal { - (self.job_write_value_fn)(source, new_value) - } else { - source - }) + Ok(if new_value != source_value { (self.job_write_value_fn)(source, new_value) } else { source }) } JobReadValueFn::Right(_) => Err(self.merge_code), } diff --git a/vrp-core/src/construction/features/tour_order.rs b/vrp-core/src/construction/features/tour_order.rs index 351779a69..aff3ab4e6 100644 --- a/vrp-core/src/construction/features/tour_order.rs +++ b/vrp-core/src/construction/features/tour_order.rs @@ -79,7 +79,7 @@ impl FeatureConstraint for TourOrderConstraint { let source = (order_fn)(source); let candidate = (order_fn)(candidate); match (source, candidate) { - (OrderResult::Value(s), OrderResult::Value(c)) => compare_floats(s, c) == Ordering::Equal, + (OrderResult::Value(s), OrderResult::Value(c)) => s == c, (OrderResult::Default, OrderResult::Default) | (OrderResult::Ignored, OrderResult::Ignored) => { true } @@ -226,7 +226,7 @@ fn get_single(activity: &Activity) -> Option<&Single> { fn compare_order_results(left: OrderResult, right: OrderResult) -> Ordering { match (left, right) { - (OrderResult::Value(left), OrderResult::Value(right)) => compare_floats(left, right), + (OrderResult::Value(left), OrderResult::Value(right)) => left.total_cmp(&right), (OrderResult::Value(_), OrderResult::Default) => Ordering::Less, (OrderResult::Default, OrderResult::Value(_)) => Ordering::Greater, _ => Ordering::Equal, diff --git a/vrp-core/src/construction/heuristics/metrics.rs b/vrp-core/src/construction/heuristics/metrics.rs index 950f27b73..4a858e08c 100644 --- a/vrp-core/src/construction/heuristics/metrics.rs +++ b/vrp-core/src/construction/heuristics/metrics.rs @@ -128,7 +128,7 @@ pub fn get_longest_distance_between_depot_customer_mean(insertion_ctx: &Insertio TravelTime::Departure(depot.schedule.departure), ) }) - .max_by(compare_floats_refs) + .max_by(|a, b| a.total_cmp(b)) })) } @@ -222,7 +222,7 @@ pub fn group_routes_by_proximity(insertion_ctx: &InsertionContext) -> Option>(); route_distances.sort_unstable_by(|(_, a_distance), (_, b_distance)| match (a_distance, b_distance) { - (Some(a_distance), Some(b_distance)) => compare_floats(*a_distance, *b_distance), + (Some(a_distance), Some(b_distance)) => a_distance.total_cmp(b_distance), (Some(_), None) => Ordering::Less, _ => Ordering::Greater, }); diff --git a/vrp-core/src/construction/probing/repair_solution.rs b/vrp-core/src/construction/probing/repair_solution.rs index 5e4952018..5e0886b46 100644 --- a/vrp-core/src/construction/probing/repair_solution.rs +++ b/vrp-core/src/construction/probing/repair_solution.rs @@ -8,7 +8,6 @@ use crate::models::problem::{Job, Multi, Single}; use crate::models::solution::Activity; use crate::models::GoalContext; use rosomaxa::prelude::*; -use std::cmp::Ordering; use std::collections::{HashMap, HashSet}; use std::ops::ControlFlow; use std::sync::Arc; @@ -144,7 +143,7 @@ fn is_activity_to_single_match(activity: &Activity, single: &Single) -> bool { .places .iter() .try_fold(false, |_, place| { - let is_same_duration = compare_floats(activity.place.duration, place.duration) == Ordering::Equal; + let is_same_duration = activity.place.duration == place.duration; let is_same_location = place.location.map_or(true, |location| location == activity.place.location); let is_same_time_window = place.times.iter().any(|time| { match time { diff --git a/vrp-core/src/models/common/domain.rs b/vrp-core/src/models/common/domain.rs index faa6198e2..20d614b7b 100644 --- a/vrp-core/src/models/common/domain.rs +++ b/vrp-core/src/models/common/domain.rs @@ -3,8 +3,7 @@ mod domain_test; use crate::models::common::{Duration, Timestamp}; -use rosomaxa::prelude::{compare_floats, Float}; -use std::cmp::Ordering; +use rosomaxa::prelude::Float; use std::hash::{Hash, Hasher}; /// Specifies location type. @@ -36,7 +35,7 @@ impl Default for Profile { pub type Cost = Float; /// Represents a time window. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] pub struct TimeWindow { /// Start of time window. pub start: Timestamp, @@ -45,7 +44,7 @@ pub struct TimeWindow { } /// Represents a time offset. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] pub struct TimeOffset { /// Offset value to start time. pub start: Timestamp, @@ -63,7 +62,7 @@ pub enum TimeSpan { } /// Specifies a flexible time interval. -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug, Default, PartialEq)] pub struct TimeInterval { /// Earliest possible time to start. pub earliest: Option, @@ -84,19 +83,17 @@ impl TimeWindow { /// Checks whether time window has intersection with another one (inclusive). pub fn intersects(&self, other: &Self) -> bool { - compare_floats(self.start, other.end) != Ordering::Greater - && compare_floats(other.start, self.end) != Ordering::Greater + self.start <= other.end && other.start <= self.end } /// Checks whether time window has intersection with another one (exclusive). pub fn intersects_exclusive(&self, other: &Self) -> bool { - compare_floats(self.start, other.end) == Ordering::Less - && compare_floats(other.start, self.end) == Ordering::Less + self.start < other.end && other.start < self.end } /// Checks whether time window contains given time. pub fn contains(&self, time: Timestamp) -> bool { - compare_floats(time, self.start) != Ordering::Less && compare_floats(time, self.end) != Ordering::Greater + time >= self.start && time <= self.end } /// Returns distance between two time windows. @@ -132,13 +129,6 @@ impl TimeWindow { } } -impl PartialEq for TimeWindow { - fn eq(&self, other: &TimeWindow) -> bool { - compare_floats(self.start, other.start) == Ordering::Equal - && compare_floats(self.end, other.end) == Ordering::Equal - } -} - impl Eq for TimeWindow {} impl Hash for TimeWindow { @@ -189,7 +179,7 @@ impl TimeInterval { } /// Represents a schedule. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] pub struct Schedule { /// Arrival time. pub arrival: Timestamp, @@ -204,13 +194,6 @@ impl Schedule { } } -impl PartialEq for Schedule { - fn eq(&self, other: &Schedule) -> bool { - compare_floats(self.arrival, other.arrival) == Ordering::Equal - && compare_floats(self.departure, other.departure) == Ordering::Equal - } -} - impl Eq for Schedule {} impl Hash for TimeInterval { @@ -224,9 +207,3 @@ impl Hash for TimeInterval { } impl Eq for TimeInterval {} - -impl PartialEq for TimeInterval { - fn eq(&self, other: &Self) -> bool { - self.earliest == other.earliest && self.latest == other.latest - } -} diff --git a/vrp-core/src/models/goal.rs b/vrp-core/src/models/goal.rs index a61d8282e..3cfff9330 100644 --- a/vrp-core/src/models/goal.rs +++ b/vrp-core/src/models/goal.rs @@ -205,7 +205,7 @@ impl GoalBuilder { let fitness_a = objectives[0].fitness(a); let fitness_b = objectives[0].fitness(b); - compare_floats(fitness_a, fitness_b) + fitness_a.total_cmp(&fitness_b) }), Arc::new(|objectives, move_ctx| objectives[0].estimate(move_ctx)), vec![objective], diff --git a/vrp-core/src/models/problem/jobs.rs b/vrp-core/src/models/problem/jobs.rs index f804c98ee..6372a49b1 100644 --- a/vrp-core/src/models/problem/jobs.rs +++ b/vrp-core/src/models/problem/jobs.rs @@ -7,7 +7,7 @@ use crate::models::common::*; use crate::models::problem::{Costs, Fleet, TransportCost}; use crate::utils::{short_type_name, Either}; use rosomaxa::prelude::{Float, GenericResult, InfoLogger}; -use rosomaxa::utils::{compare_floats_f32, compare_floats_f32_refs, parallel_collect, Timer}; +use rosomaxa::utils::{parallel_collect, Timer}; use std::cmp::Ordering::Less; use std::collections::{HashMap, HashSet}; use std::fmt::{Debug, Formatter}; @@ -354,7 +354,7 @@ fn create_index( .filter(|j| **j != *job) .map(|j| (j.clone(), get_cost_between_jobs(profile, avg_costs, transport, job, j))) .collect(); - sorted_job_costs.sort_unstable_by(|(_, a), (_, b)| compare_floats_f32_refs(a, b)); + sorted_job_costs.sort_unstable_by(|(_, a), (_, b)| a.total_cmp(b)); sorted_job_costs.truncate(MAX_NEIGHBOURS); sorted_job_costs.shrink_to_fit(); @@ -430,7 +430,7 @@ fn get_cost_between_jobs( (Some(from), Some(to)) => get_cost_between_locations(profile, costs, transport, from, to), _ => DEFAULT_COST, }) - .min_by(|a, b| compare_floats_f32(*a, *b)) + .min_by(|a, b| a.total_cmp(b)) .unwrap_or(DEFAULT_COST); // NOTE: ignore time window difference costs as it is hard to balance with routing costs diff --git a/vrp-core/src/models/solution/route.rs b/vrp-core/src/models/solution/route.rs index 237998ee1..9d524a8da 100644 --- a/vrp-core/src/models/solution/route.rs +++ b/vrp-core/src/models/solution/route.rs @@ -2,8 +2,7 @@ use crate::models::common::{Distance, Duration, Location, Schedule, TimeWindow}; use crate::models::problem::{Actor, Job, Multi, Single}; use crate::models::solution::Tour; use crate::utils::short_type_name; -use rosomaxa::prelude::{compare_floats, Float}; -use std::cmp::Ordering; +use rosomaxa::prelude::Float; use std::fmt::{Debug, Formatter}; use std::sync::Arc; @@ -146,9 +145,9 @@ impl Default for CommuteInfo { impl CommuteInfo { /// Checks whether there is no distance costs for part of commute. pub fn is_zero_distance(&self) -> bool { - let is_zero_distance = compare_floats(self.distance, 0.) == Ordering::Equal; + let is_zero_distance = self.distance == 0.; - if is_zero_distance && compare_floats(self.duration, 0.) != Ordering::Equal { + if is_zero_distance && self.duration != 0. { unreachable!("expected to have duration to be zero, got: {}", self.duration); } diff --git a/vrp-core/src/prelude.rs b/vrp-core/src/prelude.rs index 461c4c459..49c062397 100644 --- a/vrp-core/src/prelude.rs +++ b/vrp-core/src/prelude.rs @@ -24,5 +24,5 @@ pub use crate::models::{ // Reimport rosomaxa types pub use rosomaxa::{ evolution::EvolutionConfigBuilder, - utils::{compare_floats, DefaultRandom, Environment, Float, GenericError, GenericResult, InfoLogger, Random}, + utils::{DefaultRandom, Environment, Float, GenericError, GenericResult, InfoLogger, Random}, }; diff --git a/vrp-core/src/solver/search/local/reschedule_departure.rs b/vrp-core/src/solver/search/local/reschedule_departure.rs index b3d5cbe70..95c72593c 100644 --- a/vrp-core/src/solver/search/local/reschedule_departure.rs +++ b/vrp-core/src/solver/search/local/reschedule_departure.rs @@ -4,7 +4,6 @@ use crate::models::solution::Activity; use crate::solver::search::LocalOperator; use crate::solver::RefinementContext; use rosomaxa::prelude::*; -use std::cmp::Ordering; /// Reschedules departure time of the routes in the solution. #[derive(Default)] @@ -45,5 +44,5 @@ impl LocalOperator for RescheduleDeparture { } fn can_recede_departure(start: &Activity, earliest: Float) -> bool { - compare_floats(start.schedule.departure, earliest) != Ordering::Equal + start.schedule.departure != earliest } diff --git a/vrp-core/src/solver/search/recreate/recreate_with_blinks.rs b/vrp-core/src/solver/search/recreate/recreate_with_blinks.rs index 72b484478..2de644d39 100644 --- a/vrp-core/src/solver/search/recreate/recreate_with_blinks.rs +++ b/vrp-core/src/solver/search/recreate/recreate_with_blinks.rs @@ -39,7 +39,7 @@ impl RankedJobSelector { .profiles .iter() .map(|profile| problem.jobs.rank(profile, job).unwrap_or(Cost::MAX)) - .min_by(|a, b| compare_floats(*a, *b)) + .min_by(|a, b| a.total_cmp(b)) .unwrap_or_default() } } @@ -51,7 +51,7 @@ impl JobSelector for RankedJobSelector { insertion_ctx .solution .required - .sort_by(|a, b| compare_floats(Self::rank_job(problem, a), Self::rank_job(problem, b))); + .sort_by(|a, b| Self::rank_job(problem, a).total_cmp(&Self::rank_job(problem, b))); if self.asc_order { insertion_ctx.solution.required.reverse(); diff --git a/vrp-core/src/solver/search/ruin/worst_jobs_removal.rs b/vrp-core/src/solver/search/ruin/worst_jobs_removal.rs index d2c681666..e7ce3df29 100644 --- a/vrp-core/src/solver/search/ruin/worst_jobs_removal.rs +++ b/vrp-core/src/solver/search/ruin/worst_jobs_removal.rs @@ -102,7 +102,7 @@ fn get_routes_cost_savings(insertion_ctx: &InsertionContext) -> Vec<(Profile, Ve }) .drain() .collect(); - savings.sort_by(|(_, a), (_, b)| compare_floats_refs(b, a)); + savings.sort_by(|(_, a), (_, b)| b.total_cmp(a)); (route_ctx.route().actor.vehicle.profile.clone(), savings) }) diff --git a/vrp-core/tests/helpers/construction/clustering/vicinity.rs b/vrp-core/tests/helpers/construction/clustering/vicinity.rs index a428ce9c3..11989346b 100644 --- a/vrp-core/tests/helpers/construction/clustering/vicinity.rs +++ b/vrp-core/tests/helpers/construction/clustering/vicinity.rs @@ -5,7 +5,7 @@ use crate::helpers::models::problem::{get_job_id, TestSingleBuilder}; use crate::models::common::{Dimensions, Duration, Location, Profile}; use crate::models::problem::{Job, JobIdDimension}; use crate::models::*; -use rosomaxa::prelude::{compare_floats, Float}; +use rosomaxa::prelude::Float; use std::cmp::Ordering; use std::collections::HashSet; use std::sync::Arc; @@ -118,7 +118,7 @@ pub fn create_cluster_config() -> ClusterConfig { }), ordering_local_fn: Arc::new(move |left, right| { ordering_rule( - compare_floats(left.commute.forward.duration, right.commute.forward.duration), + left.commute.forward.duration.total_cmp(&right.commute.forward.duration), &left.job, &right.job, ) diff --git a/vrp-core/tests/unit/algorithms/clustering/dbscan_test.rs b/vrp-core/tests/unit/algorithms/clustering/dbscan_test.rs index d50452b90..4f0284357 100644 --- a/vrp-core/tests/unit/algorithms/clustering/dbscan_test.rs +++ b/vrp-core/tests/unit/algorithms/clustering/dbscan_test.rs @@ -1,7 +1,7 @@ use super::*; use crate::algorithms::geometry::Point; use crate::helpers::construction::clustering::p; -use rosomaxa::prelude::{compare_floats, Float}; +use rosomaxa::prelude::Float; fn create_index(points: &[Point]) -> HashMap<&Point, Vec<(&Point, Float)>> { points.iter().fold(HashMap::new(), |mut acc, point| { @@ -13,7 +13,7 @@ fn create_index(points: &[Point]) -> HashMap<&Point, Vec<(&Point, Float)>> { .map(|other| (other, point.distance_to_point(other))) .collect::>(); - pairs.sort_by(|(_, a), (_, b)| compare_floats(*a, *b)); + pairs.sort_by(|(_, a), (_, b)| a.total_cmp(b)); acc.insert(point, pairs); @@ -25,8 +25,8 @@ fn assert_non_ordered(actual: Vec<&Point>, expected: Vec<&Point>) { let mut actual = actual; let mut expected = expected; - actual.sort_by(|a, b| compare_floats(a.x, b.x)); - expected.sort_by(|a, b| compare_floats(a.x, b.x)); + actual.sort_by(|a, b| a.x.total_cmp(&b.x)); + expected.sort_by(|a, b| a.x.total_cmp(&b.x)); assert_eq!(actual, expected); } diff --git a/vrp-core/tests/unit/construction/features/transport_test.rs b/vrp-core/tests/unit/construction/features/transport_test.rs index 8d45f0732..1490479ad 100644 --- a/vrp-core/tests/unit/construction/features/transport_test.rs +++ b/vrp-core/tests/unit/construction/features/transport_test.rs @@ -29,8 +29,6 @@ mod timing { use crate::helpers::construction::heuristics::TestInsertionContextBuilder; use crate::helpers::models::domain::test_random; use crate::models::solution::{Activity, Place, Registry}; - use rosomaxa::prelude::compare_floats; - use std::cmp::Ordering; fn create_feature() -> Feature { TransportFeatureBuilder::new("transport") @@ -202,7 +200,7 @@ mod timing { let result = create_feature().objective.unwrap().estimate(&MoveContext::activity(&route_ctx, &activity_ctx)); - assert_eq!(compare_floats(result, 21.0), Ordering::Equal); + assert_eq!(result, 21.0); } #[test] @@ -254,7 +252,7 @@ mod timing { let result = create_feature().objective.unwrap().estimate(&MoveContext::activity(&route_ctx, &activity_ctx)); - assert_eq!(compare_floats(result, 30.0), Ordering::Equal); + assert_eq!(result, 30.0); } #[test] diff --git a/vrp-core/tests/unit/construction/heuristics/metrics_test.rs b/vrp-core/tests/unit/construction/heuristics/metrics_test.rs index 1297da538..7896fa621 100644 --- a/vrp-core/tests/unit/construction/heuristics/metrics_test.rs +++ b/vrp-core/tests/unit/construction/heuristics/metrics_test.rs @@ -4,8 +4,6 @@ use crate::construction::heuristics::*; use crate::helpers::construction::heuristics::TestInsertionContextBuilder; use crate::helpers::models::solution::RouteContextBuilder; use crate::models::Problem; -use rosomaxa::prelude::compare_floats; -use std::cmp::Ordering; fn create_insertion_ctx( route_amount: usize, @@ -37,7 +35,7 @@ fn can_get_max_load_variance() { let variance = get_max_load_variance(&insertion_ctx); - assert_eq!(compare_floats(variance, 6.6875), Ordering::Equal); + assert_eq!(variance, 6.6875); } #[test] @@ -53,7 +51,7 @@ fn can_get_duration_mean() { let mean = get_duration_mean(&insertion_ctx); - assert_eq!(compare_floats(mean, 5.), Ordering::Equal); + assert_eq!(mean, 5.); } #[test] @@ -69,5 +67,5 @@ fn can_get_distance_mean() { let mean = get_distance_mean(&insertion_ctx); - assert_eq!(compare_floats(mean, 7.), Ordering::Equal); + assert_eq!(mean, 7.); } diff --git a/vrp-pragmatic/src/checker/assignment.rs b/vrp-pragmatic/src/checker/assignment.rs index 977b74a3d..3e377fa1f 100644 --- a/vrp-pragmatic/src/checker/assignment.rs +++ b/vrp-pragmatic/src/checker/assignment.rs @@ -6,11 +6,10 @@ use super::*; use crate::format::get_indices; use crate::format::solution::activity_matcher::*; use crate::utils::combine_error_results; -use std::cmp::Ordering; use std::collections::HashSet; use vrp_core::construction::clustering::vicinity::ServingPolicy; use vrp_core::models::solution::Place; -use vrp_core::prelude::{compare_floats, GenericResult}; +use vrp_core::prelude::GenericResult; use vrp_core::utils::GenericError; /// Checks assignment of jobs and vehicles. @@ -215,7 +214,7 @@ fn is_valid_job_info( place: Place, time: TimeWindow, ) -> bool { - let not_equal = |left: Float, right: Float| compare_floats(left, right) != Ordering::Equal; + let not_equal = |left: Float, right: Float| left != right; let parking = ctx.clustering.as_ref().map(|config| config.serving.get_parking()).unwrap_or(0.); let commute_profile = ctx.clustering.as_ref().map(|config| config.profile.clone()); let domain_commute = ctx.get_commute_info(commute_profile, parking, stop, activity_idx); diff --git a/vrp-pragmatic/src/format/problem/clustering_reader.rs b/vrp-pragmatic/src/format/problem/clustering_reader.rs index 21e5659cf..1efe0ed0f 100644 --- a/vrp-pragmatic/src/format/problem/clustering_reader.rs +++ b/vrp-pragmatic/src/format/problem/clustering_reader.rs @@ -68,7 +68,7 @@ fn get_builder_policy() -> BuilderPolicy { }), ordering_local_fn: Arc::new(move |left, right| { ordering_rule( - compare_floats(left.commute.forward.duration, right.commute.forward.duration), + left.commute.forward.duration.total_cmp(&right.commute.forward.duration), &left.job, &right.job, ) diff --git a/vrp-pragmatic/src/format/problem/fleet_reader.rs b/vrp-pragmatic/src/format/problem/fleet_reader.rs index 49bca9f63..fe8ab6140 100644 --- a/vrp-pragmatic/src/format/problem/fleet_reader.rs +++ b/vrp-pragmatic/src/format/problem/fleet_reader.rs @@ -7,7 +7,6 @@ use crate::format::UnknownLocationFallback; use crate::get_unique_locations; use crate::utils::get_approx_transportation; use crate::Location as ApiLocation; -use std::cmp::Ordering; use std::collections::HashSet; use vrp_core::construction::enablers::create_typed_actor_groups; use vrp_core::construction::features::{VehicleCapacityDimension, VehicleSkillsDimension}; @@ -215,10 +214,7 @@ pub fn create_approx_matrices(problem: &ApiProblem) -> Vec { .iter() .map(move |profile| { let speed = profile.speed.unwrap_or(DEFAULT_SPEED); - let idx = speeds - .iter() - .position(|s| compare_floats(*s, speed) == Ordering::Equal) - .expect("Cannot find profile speed"); + let idx = speeds.iter().position(|&s| s == speed).expect("Cannot find profile speed"); Matrix { profile: Some(profile.name.clone()), diff --git a/vrp-pragmatic/src/format/problem/goal_reader.rs b/vrp-pragmatic/src/format/problem/goal_reader.rs index 789050032..6c278dec3 100644 --- a/vrp-pragmatic/src/format/problem/goal_reader.rs +++ b/vrp-pragmatic/src/format/problem/goal_reader.rs @@ -274,7 +274,7 @@ fn eval_multi_objective_strategy( Ok(match composition_type { MultiStrategy::Sum => builder.add_multi( objectives, - |os, a, b| dominance_order(a, b, os.iter().map(|o| |a, b| compare_floats(o.fitness(a), o.fitness(b)))), + |os, a, b| dominance_order(a, b, os.iter().map(|o| |a, b| o.fitness(a).total_cmp(&o.fitness(b)))), |os, move_ctx| os.iter().map(|o| o.estimate(move_ctx)).sum(), ), @@ -290,7 +290,7 @@ fn eval_multi_objective_strategy( builder.add_multi( objectives, - |os, a, b| dominance_order(a, b, os.iter().map(|o| |a, b| compare_floats(o.fitness(a), o.fitness(b)))), + |os, a, b| dominance_order(a, b, os.iter().map(|o| |a, b| o.fitness(a).total_cmp(&o.fitness(b)))), { let weights = weights.clone(); move |os, move_ctx| os.iter().enumerate().map(|(idx, o)| o.estimate(move_ctx) * weights[idx]).sum() diff --git a/vrp-pragmatic/src/format/solution/activity_matcher.rs b/vrp-pragmatic/src/format/solution/activity_matcher.rs index 3d1cbe6ee..70225b371 100644 --- a/vrp-pragmatic/src/format/solution/activity_matcher.rs +++ b/vrp-pragmatic/src/format/solution/activity_matcher.rs @@ -4,7 +4,6 @@ use crate::format::solution::{Activity as FormatActivity, Schedule as FormatSche use crate::format::solution::{PointStop, TransitStop}; use crate::format::{CoordIndex, JobIndex, PlaceTagsDimension}; use crate::parse_time; -use std::cmp::Ordering; use std::collections::HashSet; use std::iter::once; use std::sync::Arc; @@ -190,7 +189,7 @@ pub(crate) fn get_extra_time(stop: &PointStop, activity: &FormatActivity, place: let activity_time = TimeWindow::new(activity_time.start, activity_time.start + place.duration); activity_time .overlapping(&break_time) - .filter(|overlap| compare_floats(overlap.start, overlap.end) != Ordering::Equal) + .filter(|overlap| overlap.start != overlap.end) .map(|overlap| break_time.end - overlap.end + overlap.duration()) }) } else { diff --git a/vrp-pragmatic/src/format/solution/break_writer.rs b/vrp-pragmatic/src/format/solution/break_writer.rs index 703effb32..26e60f91b 100644 --- a/vrp-pragmatic/src/format/solution/break_writer.rs +++ b/vrp-pragmatic/src/format/solution/break_writer.rs @@ -4,7 +4,6 @@ use vrp_core::construction::enablers::ReservedTimesIndex; use vrp_core::models::common::{Cost, TimeWindow}; use vrp_core::models::solution::Route; use vrp_core::prelude::Float; -use vrp_core::utils::compare_floats; /// Converts reserved time duration applied to activity or travel time to break activity. pub(super) fn insert_reserved_times_as_breaks( @@ -155,7 +154,7 @@ fn insert_break( }); activities.sort_by(|a, b| match (&a.time, &b.time) { - (Some(a), Some(b)) => compare_floats(parse_time(&a.start), parse_time(&b.start)), + (Some(a), Some(b)) => parse_time(&a.start).total_cmp(&parse_time(&b.start)), (Some(_), None) => Ordering::Greater, (None, Some(_)) => Ordering::Less, (None, None) => Ordering::Equal, diff --git a/vrp-pragmatic/src/validation/common.rs b/vrp-pragmatic/src/validation/common.rs index 793f6b1a1..af8dd8419 100644 --- a/vrp-pragmatic/src/validation/common.rs +++ b/vrp-pragmatic/src/validation/common.rs @@ -1,7 +1,6 @@ use crate::parse_time_safe; use std::collections::HashSet; use vrp_core::models::common::TimeWindow; -use vrp_core::utils::compare_floats; /// Checks time window rules. pub fn check_raw_time_windows(tws: &[Vec], skip_intersection_check: bool) -> bool { @@ -18,7 +17,7 @@ pub fn check_time_windows(tws: &[Option], skip_intersection_check: b if let [a] = tws.as_slice() { a.start <= a.end } else { - tws.sort_by(|a, b| compare_floats(a.start, b.start)); + tws.sort_by(|a, b| a.start.total_cmp(&b.start)); tws.windows(2).any(|pair| { if let [a, b] = pair { a.start <= a.end && b.start <= b.end && (skip_intersection_check || !a.intersects(b)) diff --git a/vrp-pragmatic/src/validation/vehicles.rs b/vrp-pragmatic/src/validation/vehicles.rs index c1fc10d40..de355dd40 100644 --- a/vrp-pragmatic/src/validation/vehicles.rs +++ b/vrp-pragmatic/src/validation/vehicles.rs @@ -6,10 +6,8 @@ use super::*; use crate::utils::combine_error_results; use crate::validation::common::get_time_windows; use crate::{parse_time, parse_time_safe}; -use std::cmp::Ordering; use std::collections::HashSet; use vrp_core::models::common::TimeWindow; -use vrp_core::utils::compare_floats; /// Checks that fleet has no vehicle with duplicate type ids. fn check_e1300_no_vehicle_types_with_duplicate_type_ids(ctx: &ValidationContext) -> Result<(), FormatError> { @@ -158,10 +156,7 @@ fn check_e1304_vehicle_reload_time_is_correct(ctx: &ValidationContext) -> Result fn check_e1306_vehicle_has_no_zero_costs(ctx: &ValidationContext) -> Result<(), FormatError> { let type_ids = ctx .vehicles() - .filter(|vehicle| { - compare_floats(vehicle.costs.time, 0.) == Ordering::Equal - && compare_floats(vehicle.costs.distance, 0.) == Ordering::Equal - }) + .filter(|vehicle| vehicle.costs.time == 0. && vehicle.costs.distance == 0.) .map(|vehicle| vehicle.type_id.to_string()) .collect::>(); diff --git a/vrp-pragmatic/tests/features/fleet/basic_multi_shift.rs b/vrp-pragmatic/tests/features/fleet/basic_multi_shift.rs index 7c596a0c9..20063c53e 100644 --- a/vrp-pragmatic/tests/features/fleet/basic_multi_shift.rs +++ b/vrp-pragmatic/tests/features/fleet/basic_multi_shift.rs @@ -1,7 +1,6 @@ use crate::format::problem::*; use crate::helpers::*; use crate::{format_time, parse_time}; -use vrp_core::utils::compare_floats_refs; #[test] fn can_use_multiple_times_from_vehicle_and_job() { @@ -137,6 +136,6 @@ fn can_prefer_first_days_with_minimize_arrival_time_objective() { .filter_map(|tour| tour.stops.first()) .map(|stop| parse_time(&stop.schedule().departure)) .collect::>(); - departures.sort_by(compare_floats_refs); + departures.sort_by(|a, b| a.total_cmp(b)); assert_eq!(departures, vec![0., 100.]); } diff --git a/vrp-pragmatic/tests/generator/common.rs b/vrp-pragmatic/tests/generator/common.rs index 55d5f4590..a0ffb9419 100644 --- a/vrp-pragmatic/tests/generator/common.rs +++ b/vrp-pragmatic/tests/generator/common.rs @@ -4,7 +4,7 @@ use crate::{format_time, parse_time}; use std::ops::Range; use std::time::Duration; use vrp_core::models::common::TimeWindow; -use vrp_core::prelude::{compare_floats, Float}; +use vrp_core::prelude::Float; /// Creates `Duration` from hours amount. pub fn from_hours(hours: i32) -> Duration { @@ -59,7 +59,7 @@ prop_compose! { })) -> Vec> { let mut time_windows = time_windows; - time_windows.sort_by(|a, b| compare_floats(a.start, b.start)); + time_windows.sort_by(|a, b| a.start.total_cmp(&b.start)); time_windows.iter().map(|tw| vec![format_time(tw.start), format_time(tw.end)]).collect() } diff --git a/vrp-pragmatic/tests/unit/format/solution/writer_test.rs b/vrp-pragmatic/tests/unit/format/solution/writer_test.rs index 9b8132963..46c9d028e 100644 --- a/vrp-pragmatic/tests/unit/format/solution/writer_test.rs +++ b/vrp-pragmatic/tests/unit/format/solution/writer_test.rs @@ -2,12 +2,10 @@ use crate::format::problem::*; use crate::format::solution::solution_writer::create_tour; use crate::format::solution::*; use crate::helpers::*; -use std::cmp::Ordering; use std::sync::Arc; use vrp_core::construction::enablers::ReservedTimeSpan; use vrp_core::models::common::{TimeSpan, TimeWindow}; use vrp_core::models::examples::create_example_problem; -use vrp_core::utils::compare_floats; type DomainProblem = vrp_core::models::Problem; type DomainActivity = vrp_core::models::solution::Activity; @@ -170,7 +168,7 @@ fn can_merge_activities_with_commute_in_one_stop_impl( match (commute, &actual.commute) { (Some(expected), Some(actual)) => { let check_commute = |expected: Float, info: Option<&CommuteInfo>| { - if compare_floats(expected, 0.) == Ordering::Equal { + if expected == 0. { assert!(info.is_none()) } else { assert_eq!(expected, info.unwrap().time.duration());