rink_core/commands/
factorize.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
5use crate::types::{Dimensionality, Number, Numeric};
6use std::cmp;
7use std::collections::{BTreeMap, BinaryHeap};
8use std::rc::Rc;
9
10#[derive(PartialEq, Ord, Eq, Debug)]
11pub struct Factors(pub usize, pub Vec<Rc<String>>);
12
13impl cmp::PartialOrd for Factors {
14    fn partial_cmp(&self, other: &Factors) -> Option<cmp::Ordering> {
15        Some(self.0.cmp(&other.0))
16    }
17}
18
19pub fn factorize(
20    value: &Number,
21    quantities: &BTreeMap<Dimensionality, Rc<String>>,
22) -> BinaryHeap<Factors> {
23    if value.dimless() {
24        let mut map = BinaryHeap::new();
25        map.push(Factors(0, vec![]));
26        return map;
27    }
28    let mut candidates: BinaryHeap<Factors> = BinaryHeap::new();
29    let value_score = value.complexity_score();
30    for (unit, name) in quantities.iter().rev() {
31        let num = Number {
32            value: Numeric::one(),
33            unit: unit.clone(),
34        };
35        let res = (value / &num).unwrap();
36        //if res.unit.len() >= value.unit.len() {
37        let score = res.complexity_score();
38        // we are not making the unit any simpler
39        if score >= value_score {
40            continue;
41        }
42        let res = factorize(&res, quantities);
43        for Factors(score, mut vec) in res {
44            vec.push(name.clone());
45            vec.sort();
46            candidates.push(Factors(score + 1, vec));
47        }
48        let mut next = candidates.into_sorted_vec();
49        next.dedup();
50        candidates = next.into_iter().take(10).collect();
51    }
52    assert!(candidates.len() <= 10);
53    candidates
54}