Skip to content

Commit d2806cb

Browse files
committed
WIP: Log approximation
1 parent 2456bfd commit d2806cb

File tree

1 file changed

+77
-13
lines changed

1 file changed

+77
-13
lines changed

lightning/src/routing/scoring.rs

Lines changed: 77 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,35 @@ impl<L: DerefMut<Target = u64>, T: Time, U: DerefMut<Target = T>> DirectedChanne
717717
}
718718
}
719719

720+
const FRACTIONAL_BITS: u32 = 3;
721+
const FRACTIONAL_BITMASK: u64 = (1 << FRACTIONAL_BITS) - 1;
722+
const LOG2_FRACTIONAL_PART: [f64; 1 << FRACTIONAL_BITS] =
723+
[0.0, 0.17, 0.32, 0.46, 0.58, 0.70, 0.81, 0.91];
724+
const LOG2_10: f64 = 3.32;
725+
726+
fn log10_approx(numerator: u64, denominator: u64) -> f64 {
727+
(log2_approx(numerator) - log2_approx(denominator)) / LOG2_10
728+
}
729+
730+
#[inline]
731+
fn log2_approx(x: u64) -> f64 {
732+
let leading_zeros = x.leading_zeros();
733+
let integer_part = (63 - leading_zeros) as f64;
734+
let fractional_part = LOG2_FRACTIONAL_PART[
735+
(((x << leading_zeros) >> (63 - FRACTIONAL_BITS)) & FRACTIONAL_BITMASK) as usize
736+
];
737+
integer_part + fractional_part
738+
}
739+
740+
fn log10_approx_without_fractional(numerator: u64, denominator: u64) -> f64 {
741+
(log2_approx_without_fractional(numerator) - log2_approx_without_fractional(denominator)) / LOG2_10
742+
}
743+
744+
#[inline]
745+
fn log2_approx_without_fractional(x: u64) -> f64 {
746+
(63 - x.leading_zeros()) as f64
747+
}
748+
720749
impl<G: Deref<Target = NetworkGraph>, T: Time> Score for ProbabilisticScorerUsingTime<G, T> {
721750
fn channel_penalty_msat(
722751
&self, short_channel_id: u64, amount_msat: u64, capacity_msat: u64, source: &NodeId,
@@ -737,8 +766,8 @@ impl<G: Deref<Target = NetworkGraph>, T: Time> Score for ProbabilisticScorerUsin
737766
Probability::Zero => u64::max_value(),
738767
Probability::One => 0,
739768
Probability::Ratio { numerator, denominator } => {
740-
let success_probability = numerator as f64 / denominator as f64;
741-
(-(success_probability.log10()) * liquidity_penalty_multiplier_msat as f64) as u64
769+
let log_success_probability = log10_approx(numerator, denominator);
770+
(-log_success_probability * liquidity_penalty_multiplier_msat as f64) as u64
742771
},
743772
}
744773
}
@@ -1737,43 +1766,43 @@ mod tests {
17371766
let target = target_node_id();
17381767

17391768
assert_eq!(scorer.channel_penalty_msat(42, 0, 1_024, &source, &target), 0);
1740-
assert_eq!(scorer.channel_penalty_msat(42, 1_024, 1_024, &source, &target), 3_010);
1769+
assert_eq!(scorer.channel_penalty_msat(42, 1_024, 1_024, &source, &target), 3_012);
17411770

17421771
scorer.payment_path_failed(&payment_path_for_amount(768).iter().collect::<Vec<_>>(), 42);
17431772
scorer.payment_path_failed(&payment_path_for_amount(128).iter().collect::<Vec<_>>(), 43);
17441773

17451774
assert_eq!(scorer.channel_penalty_msat(42, 128, 1_024, &source, &target), 0);
1746-
assert_eq!(scorer.channel_penalty_msat(42, 256, 1_024, &source, &target), 92);
1747-
assert_eq!(scorer.channel_penalty_msat(42, 768, 1_024, &source, &target), 1_424);
1775+
assert_eq!(scorer.channel_penalty_msat(42, 256, 1_024, &source, &target), 96);
1776+
assert_eq!(scorer.channel_penalty_msat(42, 768, 1_024, &source, &target), 1_427);
17481777
assert_eq!(scorer.channel_penalty_msat(42, 896, 1_024, &source, &target), u64::max_value());
17491778

17501779
SinceEpoch::advance(Duration::from_secs(9));
17511780
assert_eq!(scorer.channel_penalty_msat(42, 128, 1_024, &source, &target), 0);
1752-
assert_eq!(scorer.channel_penalty_msat(42, 256, 1_024, &source, &target), 92);
1753-
assert_eq!(scorer.channel_penalty_msat(42, 768, 1_024, &source, &target), 1_424);
1781+
assert_eq!(scorer.channel_penalty_msat(42, 256, 1_024, &source, &target), 96);
1782+
assert_eq!(scorer.channel_penalty_msat(42, 768, 1_024, &source, &target), 1_427);
17541783
assert_eq!(scorer.channel_penalty_msat(42, 896, 1_024, &source, &target), u64::max_value());
17551784

17561785
SinceEpoch::advance(Duration::from_secs(1));
17571786
assert_eq!(scorer.channel_penalty_msat(42, 64, 1_024, &source, &target), 0);
1758-
assert_eq!(scorer.channel_penalty_msat(42, 128, 1_024, &source, &target), 34);
1759-
assert_eq!(scorer.channel_penalty_msat(42, 896, 1_024, &source, &target), 1_812);
1787+
assert_eq!(scorer.channel_penalty_msat(42, 128, 1_024, &source, &target), 36);
1788+
assert_eq!(scorer.channel_penalty_msat(42, 896, 1_024, &source, &target), 1_807);
17601789
assert_eq!(scorer.channel_penalty_msat(42, 960, 1_024, &source, &target), u64::max_value());
17611790

17621791
// Fully decay liquidity lower bound.
17631792
SinceEpoch::advance(Duration::from_secs(10 * 7));
17641793
assert_eq!(scorer.channel_penalty_msat(42, 0, 1_024, &source, &target), 0);
17651794
assert_eq!(scorer.channel_penalty_msat(42, 1, 1_024, &source, &target), 0);
1766-
assert_eq!(scorer.channel_penalty_msat(42, 1_023, 1_024, &source, &target), 2_709);
1767-
assert_eq!(scorer.channel_penalty_msat(42, 1_024, 1_024, &source, &target), 3_010);
1795+
assert_eq!(scorer.channel_penalty_msat(42, 1_023, 1_024, &source, &target), 2_710);
1796+
assert_eq!(scorer.channel_penalty_msat(42, 1_024, 1_024, &source, &target), 3_012);
17681797

17691798
// Fully decay liquidity upper bound.
17701799
SinceEpoch::advance(Duration::from_secs(10));
17711800
assert_eq!(scorer.channel_penalty_msat(42, 0, 1_024, &source, &target), 0);
1772-
assert_eq!(scorer.channel_penalty_msat(42, 1_024, 1_024, &source, &target), 3_010);
1801+
assert_eq!(scorer.channel_penalty_msat(42, 1_024, 1_024, &source, &target), 3_012);
17731802

17741803
SinceEpoch::advance(Duration::from_secs(10));
17751804
assert_eq!(scorer.channel_penalty_msat(42, 0, 1_024, &source, &target), 0);
1776-
assert_eq!(scorer.channel_penalty_msat(42, 1_024, 1_024, &source, &target), 3_010);
1805+
assert_eq!(scorer.channel_penalty_msat(42, 1_024, 1_024, &source, &target), 3_012);
17771806
}
17781807

17791808
#[test]
@@ -1899,3 +1928,38 @@ mod tests {
18991928
assert_eq!(deserialized_scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), 367);
19001929
}
19011930
}
1931+
1932+
#[cfg(all(test, feature = "unstable", not(feature = "no-std")))]
1933+
mod benches {
1934+
use super::*;
1935+
1936+
use test::black_box;
1937+
use test::Bencher;
1938+
1939+
#[bench]
1940+
fn log10_bench(bench: &mut Bencher) {
1941+
bench.iter(|| {
1942+
for i in 1..85_184 {
1943+
black_box((i as f64 / 85_184 as f64).log10());
1944+
}
1945+
});
1946+
}
1947+
1948+
#[bench]
1949+
fn log10_approx_bench(bench: &mut Bencher) {
1950+
bench.iter(|| {
1951+
for i in 1..85_184 {
1952+
black_box(log10_approx(i, 85_184));
1953+
}
1954+
});
1955+
}
1956+
1957+
#[bench]
1958+
fn log10_approx_without_fractional_bench(bench: &mut Bencher) {
1959+
bench.iter(|| {
1960+
for i in 1..85_184 {
1961+
black_box(log10_approx_without_fractional(i, 85_184));
1962+
}
1963+
});
1964+
}
1965+
}

0 commit comments

Comments
 (0)