Skip to content

Commit e0177bb

Browse files
committed
Switch alias sampler tests to modular distribution sampling
1 parent 79c22a3 commit e0177bb

File tree

3 files changed

+165
-313
lines changed

3 files changed

+165
-313
lines changed

necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs

Lines changed: 3 additions & 156 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,18 @@
11
use alloc::{vec, vec::Vec};
2-
use core::num::{NonZeroU128, NonZeroU64, NonZeroUsize};
32

43
use hashbrown::HashMap;
54

6-
use necsim_core::cogs::{
7-
distribution::{IndexU128, IndexU64, IndexUsize, Length},
8-
Backup, DistributionSampler, Rng, RngCore, SeedableRng,
9-
};
5+
use necsim_core::cogs::{Backup, SeedableRng};
106
use necsim_core_bond::{NonNegativeF64, PositiveF64};
11-
use necsim_core_maths::MathsCore;
127

138
use crate::cogs::{
149
maths::intrinsics::IntrinsicsMathsCore,
1510
rng::{simple::SimpleRng, wyhash::WyHash},
1611
};
1712

1813
use super::{
19-
super::decompose_weight, DynamicAliasMethodIndexedSampler, EventLocation,
20-
RejectionSamplingGroup,
14+
super::{decompose_weight, tests::DummyRng},
15+
DynamicAliasMethodIndexedSampler, EventLocation, RejectionSamplingGroup,
2116
};
2217

2318
#[test]
@@ -1077,151 +1072,3 @@ fn debug_display_sampler() {
10771072
"DynamicAliasMethodIndexedSampler { exponents: [2, 1], total_weight: 20.0 }"
10781073
);
10791074
}
1080-
1081-
// GRCOV_EXCL_START
1082-
#[derive(Debug, serde::Serialize, serde::Deserialize)]
1083-
struct DummyRng(Vec<f64>);
1084-
1085-
impl DummyRng {
1086-
fn new(mut vec: Vec<f64>) -> Self {
1087-
vec.reverse();
1088-
1089-
Self(vec)
1090-
}
1091-
1092-
fn sample_f64(&mut self) -> f64 {
1093-
self.0.pop().unwrap()
1094-
}
1095-
}
1096-
1097-
impl RngCore for DummyRng {
1098-
type Seed = [u8; 0];
1099-
1100-
#[must_use]
1101-
fn from_seed(_seed: Self::Seed) -> Self {
1102-
Self(Vec::new())
1103-
}
1104-
1105-
#[must_use]
1106-
fn sample_u64(&mut self) -> u64 {
1107-
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
1108-
{
1109-
((self.sample_f64() / f64::from_bits(0x3CA0_0000_0000_0000_u64)) as u64) << 11
1110-
}
1111-
}
1112-
}
1113-
1114-
impl Rng<IntrinsicsMathsCore> for DummyRng {
1115-
type Generator = Self;
1116-
type Sampler = DummyDistributionSamplers;
1117-
1118-
fn generator(&mut self) -> &mut Self::Generator {
1119-
self
1120-
}
1121-
1122-
fn map_generator<F: FnOnce(Self::Generator) -> Self::Generator>(self, map: F) -> Self {
1123-
map(self)
1124-
}
1125-
1126-
fn with<F: FnOnce(&mut Self::Generator, &Self::Sampler) -> Q, Q>(&mut self, inner: F) -> Q {
1127-
let samplers = DummyDistributionSamplers;
1128-
1129-
inner(self, &samplers)
1130-
}
1131-
}
1132-
1133-
struct DummyDistributionSamplers;
1134-
1135-
impl DistributionSampler<IntrinsicsMathsCore, DummyRng, DummyDistributionSamplers, IndexUsize>
1136-
for DummyDistributionSamplers
1137-
{
1138-
type ConcreteSampler = Self;
1139-
1140-
fn concrete(&self) -> &Self::ConcreteSampler {
1141-
self
1142-
}
1143-
1144-
fn sample_distribution(
1145-
&self,
1146-
rng: &mut DummyRng,
1147-
_samplers: &DummyDistributionSamplers,
1148-
Length(length): Length<NonZeroUsize>,
1149-
) -> usize {
1150-
let u01 = rng.sample_f64();
1151-
1152-
// Safety: U[0, 1) * length in [0, 2^[32/64]) is a valid [u32/u64]
1153-
// since (1 - 2^-53) * 2^[32/64] <= (2^[32/64] - 1)
1154-
#[allow(clippy::cast_precision_loss)]
1155-
let index = unsafe {
1156-
IntrinsicsMathsCore::floor(u01 * (length.get() as f64)).to_int_unchecked::<usize>()
1157-
};
1158-
1159-
if cfg!(target_pointer_width = "32") {
1160-
// Note: [0, 2^32) is losslessly represented in f64
1161-
index
1162-
} else {
1163-
// Note: Ensure index < length despite
1164-
// usize->f64->usize precision loss
1165-
index.min(length.get() - 1)
1166-
}
1167-
}
1168-
}
1169-
1170-
impl DistributionSampler<IntrinsicsMathsCore, DummyRng, DummyDistributionSamplers, IndexU64>
1171-
for DummyDistributionSamplers
1172-
{
1173-
type ConcreteSampler = Self;
1174-
1175-
fn concrete(&self) -> &Self::ConcreteSampler {
1176-
self
1177-
}
1178-
1179-
fn sample_distribution(
1180-
&self,
1181-
rng: &mut DummyRng,
1182-
_samplers: &DummyDistributionSamplers,
1183-
Length(length): Length<NonZeroU64>,
1184-
) -> u64 {
1185-
let u01 = rng.sample_f64();
1186-
1187-
// Safety: U[0, 1) * length in [0, 2^64) is a valid u64
1188-
// since (1 - 2^-53) * 2^64 <= (2^64 - 1)
1189-
#[allow(clippy::cast_precision_loss)]
1190-
let index = unsafe {
1191-
IntrinsicsMathsCore::floor(u01 * (length.get() as f64)).to_int_unchecked::<u64>()
1192-
};
1193-
1194-
// Note: Ensure index < length despite u64->f64->u64 precision loss
1195-
index.min(length.get() - 1)
1196-
}
1197-
}
1198-
1199-
impl DistributionSampler<IntrinsicsMathsCore, DummyRng, DummyDistributionSamplers, IndexU128>
1200-
for DummyDistributionSamplers
1201-
{
1202-
type ConcreteSampler = Self;
1203-
1204-
fn concrete(&self) -> &Self::ConcreteSampler {
1205-
self
1206-
}
1207-
1208-
fn sample_distribution(
1209-
&self,
1210-
rng: &mut DummyRng,
1211-
_samplers: &DummyDistributionSamplers,
1212-
Length(length): Length<NonZeroU128>,
1213-
) -> u128 {
1214-
let u01 = rng.sample_f64();
1215-
1216-
// Safety: U[0, 1) * length in [0, 2^128) is a valid u128
1217-
// since (1 - 2^-53) * 2^128 <= (2^128 - 1)
1218-
#[allow(clippy::cast_precision_loss)]
1219-
let index = unsafe {
1220-
IntrinsicsMathsCore::floor(u01 * (length.get() as f64)).to_int_unchecked::<u128>()
1221-
};
1222-
1223-
// Note: Ensure index < length despite u128->f64->u128 precision loss
1224-
index.min(length.get() - 1)
1225-
}
1226-
}
1227-
// GRCOV_EXCL_STOP

necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs

Lines changed: 5 additions & 156 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
1-
use core::num::{NonZeroU128, NonZeroU64, NonZeroUsize};
2-
31
use alloc::{vec, vec::Vec};
42

5-
use necsim_core::cogs::{
6-
distribution::{IndexU128, IndexU64, IndexUsize, Length},
7-
Backup, DistributionSampler, Rng, RngCore, SeedableRng,
8-
};
3+
use necsim_core::cogs::{Backup, SeedableRng};
94
use necsim_core_bond::{NonNegativeF64, PositiveF64};
10-
use necsim_core_maths::MathsCore;
115

126
use crate::cogs::{
137
maths::intrinsics::IntrinsicsMathsCore,
148
rng::{simple::SimpleRng, wyhash::WyHash},
159
};
1610

17-
use super::{super::decompose_weight, DynamicAliasMethodStackSampler, RejectionSamplingGroup};
11+
use super::{
12+
super::{decompose_weight, tests::DummyRng},
13+
DynamicAliasMethodStackSampler, RejectionSamplingGroup,
14+
};
1815

1916
#[test]
2017
fn singular_event_group() {
@@ -576,151 +573,3 @@ fn debug_display_sampler() {
576573
"DynamicAliasMethodStackSampler { exponents: [2, 1], total_weight: 20.0 }"
577574
);
578575
}
579-
580-
// GRCOV_EXCL_START
581-
#[derive(Debug, serde::Serialize, serde::Deserialize)]
582-
struct DummyRng(Vec<f64>);
583-
584-
impl DummyRng {
585-
fn new(mut vec: Vec<f64>) -> Self {
586-
vec.reverse();
587-
588-
Self(vec)
589-
}
590-
591-
fn sample_f64(&mut self) -> f64 {
592-
self.0.pop().unwrap()
593-
}
594-
}
595-
596-
impl RngCore for DummyRng {
597-
type Seed = [u8; 0];
598-
599-
#[must_use]
600-
fn from_seed(_seed: Self::Seed) -> Self {
601-
Self(Vec::new())
602-
}
603-
604-
#[must_use]
605-
fn sample_u64(&mut self) -> u64 {
606-
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
607-
{
608-
((self.sample_f64() / f64::from_bits(0x3CA0_0000_0000_0000_u64)) as u64) << 11
609-
}
610-
}
611-
}
612-
613-
impl Rng<IntrinsicsMathsCore> for DummyRng {
614-
type Generator = Self;
615-
type Sampler = DummyDistributionSamplers;
616-
617-
fn generator(&mut self) -> &mut Self::Generator {
618-
self
619-
}
620-
621-
fn map_generator<F: FnOnce(Self::Generator) -> Self::Generator>(self, map: F) -> Self {
622-
map(self)
623-
}
624-
625-
fn with<F: FnOnce(&mut Self::Generator, &Self::Sampler) -> Q, Q>(&mut self, inner: F) -> Q {
626-
let samplers = DummyDistributionSamplers;
627-
628-
inner(self, &samplers)
629-
}
630-
}
631-
632-
struct DummyDistributionSamplers;
633-
634-
impl DistributionSampler<IntrinsicsMathsCore, DummyRng, DummyDistributionSamplers, IndexUsize>
635-
for DummyDistributionSamplers
636-
{
637-
type ConcreteSampler = Self;
638-
639-
fn concrete(&self) -> &Self::ConcreteSampler {
640-
self
641-
}
642-
643-
fn sample_distribution(
644-
&self,
645-
rng: &mut DummyRng,
646-
_samplers: &DummyDistributionSamplers,
647-
Length(length): Length<NonZeroUsize>,
648-
) -> usize {
649-
let u01 = rng.sample_f64();
650-
651-
// Safety: U[0, 1) * length in [0, 2^[32/64]) is a valid [u32/u64]
652-
// since (1 - 2^-53) * 2^[32/64] <= (2^[32/64] - 1)
653-
#[allow(clippy::cast_precision_loss)]
654-
let index = unsafe {
655-
IntrinsicsMathsCore::floor(u01 * (length.get() as f64)).to_int_unchecked::<usize>()
656-
};
657-
658-
if cfg!(target_pointer_width = "32") {
659-
// Note: [0, 2^32) is losslessly represented in f64
660-
index
661-
} else {
662-
// Note: Ensure index < length despite
663-
// usize->f64->usize precision loss
664-
index.min(length.get() - 1)
665-
}
666-
}
667-
}
668-
669-
impl DistributionSampler<IntrinsicsMathsCore, DummyRng, DummyDistributionSamplers, IndexU64>
670-
for DummyDistributionSamplers
671-
{
672-
type ConcreteSampler = Self;
673-
674-
fn concrete(&self) -> &Self::ConcreteSampler {
675-
self
676-
}
677-
678-
fn sample_distribution(
679-
&self,
680-
rng: &mut DummyRng,
681-
_samplers: &DummyDistributionSamplers,
682-
Length(length): Length<NonZeroU64>,
683-
) -> u64 {
684-
let u01 = rng.sample_f64();
685-
686-
// Safety: U[0, 1) * length in [0, 2^64) is a valid u64
687-
// since (1 - 2^-53) * 2^64 <= (2^64 - 1)
688-
#[allow(clippy::cast_precision_loss)]
689-
let index = unsafe {
690-
IntrinsicsMathsCore::floor(u01 * (length.get() as f64)).to_int_unchecked::<u64>()
691-
};
692-
693-
// Note: Ensure index < length despite u64->f64->u64 precision loss
694-
index.min(length.get() - 1)
695-
}
696-
}
697-
698-
impl DistributionSampler<IntrinsicsMathsCore, DummyRng, DummyDistributionSamplers, IndexU128>
699-
for DummyDistributionSamplers
700-
{
701-
type ConcreteSampler = Self;
702-
703-
fn concrete(&self) -> &Self::ConcreteSampler {
704-
self
705-
}
706-
707-
fn sample_distribution(
708-
&self,
709-
rng: &mut DummyRng,
710-
_samplers: &DummyDistributionSamplers,
711-
Length(length): Length<NonZeroU128>,
712-
) -> u128 {
713-
let u01 = rng.sample_f64();
714-
715-
// Safety: U[0, 1) * length in [0, 2^128) is a valid u128
716-
// since (1 - 2^-53) * 2^128 <= (2^128 - 1)
717-
#[allow(clippy::cast_precision_loss)]
718-
let index = unsafe {
719-
IntrinsicsMathsCore::floor(u01 * (length.get() as f64)).to_int_unchecked::<u128>()
720-
};
721-
722-
// Note: Ensure index < length despite u128->f64->u128 precision loss
723-
index.min(length.get() - 1)
724-
}
725-
}
726-
// GRCOV_EXCL_STOP

0 commit comments

Comments
 (0)