use digit_decomposition::{compose_value, decompose_value};
use crate::utils::pre_pad_vec;
fn adjust_prefix_size(
prefix: &[usize],
nb_digits: usize,
suffix_len: usize,
) -> Result<Vec<usize>, ()> {
let expected_len = nb_digits - suffix_len;
match prefix.len() {
len if len <= expected_len => Ok(pre_pad_vec(prefix.to_vec(), expected_len)),
len => {
let mut res = prefix.to_vec();
if !res.drain(..len - expected_len).all(|x| x == 0) {
return Err(());
}
Ok(res)
}
}
}
fn compute_interval_from_prefix(
prefix: &[usize],
num_digits: usize,
base: usize,
) -> (usize, usize) {
let suffix_len = num_digits - prefix.len();
let start = compose_value(
&prefix
.iter()
.cloned()
.chain((0..suffix_len).map(|_| 0))
.collect::<Vec<_>>(),
base,
);
let end = compose_value(
&prefix
.iter()
.cloned()
.chain((0..suffix_len).map(|_| base - 1))
.collect::<Vec<_>>(),
base,
);
(start, end)
}
fn num_to_vec(input: usize, nb_digits: usize, ignored_digits: usize, base: usize) -> Vec<usize> {
let decomposed = decompose_value(input, base, nb_digits);
let to_take = decomposed.len() - ignored_digits;
decomposed.into_iter().take(to_take).collect::<Vec<_>>()
}
fn compute_min_support_covering_prefix(
start: usize,
end: usize,
min_support: usize,
min_nb_digits: usize,
) -> Vec<usize> {
let left_bound = start - min_support;
let right_bound = end + min_support;
let left_bound = decompose_value(left_bound, 2, min_nb_digits);
let right_bound = decompose_value(right_bound, 2, min_nb_digits);
left_bound
.into_iter()
.zip(right_bound)
.take_while(|(x, y)| x == y)
.map(|(x, _)| x)
.collect()
}
fn compute_left_covering_prefix(
start: usize,
max_error_exp: usize,
min_support: usize,
nb_digits: usize,
) -> Vec<usize> {
let left_bound = start - min_support;
let left_bound = decompose_value(left_bound, 2, nb_digits);
let (prefix, suffix) = left_bound.split_at(nb_digits - max_error_exp);
prefix
.iter()
.chain(suffix.iter().take_while(|x| **x == 1))
.cloned()
.collect()
}
fn compute_right_covering_prefix(
end: usize,
max_error_exp: usize,
min_support: usize,
nb_digits: usize,
) -> Vec<usize> {
let left_bound = end + min_support;
let left_bound = decompose_value(left_bound, 2, nb_digits);
let (prefix, suffix) = left_bound.split_at(nb_digits - max_error_exp);
prefix
.iter()
.chain(suffix.iter().take_while(|x| **x == 0))
.cloned()
.collect()
}
fn single_covering_prefix_combinations(
main_outcome_prefix: &[usize],
secondary_outcomes_prefix: &[usize],
oracle_digits_infos: &[usize],
suffix_len: usize,
) -> Vec<Vec<usize>> {
let mut secondary = oracle_digits_infos
.iter()
.skip(1)
.map(|nb_digits| {
adjust_prefix_size(
secondary_outcomes_prefix,
*nb_digits,
main_outcome_prefix.len() - secondary_outcomes_prefix.len() + suffix_len,
)
.unwrap()
})
.collect::<Vec<Vec<_>>>();
let mut res =
vec![adjust_prefix_size(main_outcome_prefix, oracle_digits_infos[0], suffix_len).unwrap()];
res.append(&mut secondary);
res
}
fn double_covering_restricted_prefix_combinations(
main_outcome_prefix: &[usize],
other_interval_prefix: &[usize],
oracle_digits_infos: &[usize],
suffix_len: usize,
) -> Vec<Vec<Vec<usize>>> {
let mut combinations = double_covering_prefix_combinations(
main_outcome_prefix,
main_outcome_prefix,
other_interval_prefix,
oracle_digits_infos,
suffix_len,
);
if main_outcome_prefix > other_interval_prefix {
combinations.remove(combinations.len() - 1);
combinations
} else {
combinations.into_iter().skip(1).collect::<Vec<_>>()
}
}
fn double_covering_prefix_combinations(
main_outcome_prefix: &[usize],
left_interval_prefix: &[usize],
right_interval_prefix: &[usize],
oracle_digits_infos: &[usize],
suffix_len: usize,
) -> Vec<Vec<Vec<usize>>> {
let nb_oracles = oracle_digits_infos.len();
let mut res = Vec::with_capacity(nb_oracles);
let (first, second) = if left_interval_prefix <= right_interval_prefix {
(left_interval_prefix, right_interval_prefix)
} else {
(right_interval_prefix, left_interval_prefix)
};
for i in 0..(1 << (nb_oracles - 1)) {
let mut mid_res = Vec::with_capacity(nb_oracles);
for j in 0..(nb_oracles - 1) {
let val: Vec<usize> = match i & (1 << j) {
0 => first.to_vec(),
_ => second.to_vec(),
};
mid_res.push(val);
}
mid_res.push(main_outcome_prefix.to_vec());
mid_res.reverse();
let trimmed = mid_res
.into_iter()
.zip(oracle_digits_infos)
.map(|(x, y)| {
adjust_prefix_size(&x, *y, main_outcome_prefix.len() + suffix_len - x.len())
})
.collect::<Result<Vec<Vec<usize>>, ()>>();
if let Ok(mid_res) = trimmed {
res.push(mid_res)
}
}
res
}
pub fn compute_outcome_combinations(
oracle_digits_infos: &[usize],
main_outcome_prefix: &[usize],
max_error_exp: usize,
min_support_exp: usize,
maximize_coverage: bool,
) -> Vec<Vec<Vec<usize>>> {
let nb_oracles = oracle_digits_infos.len();
assert!(nb_oracles > 1 && max_error_exp > min_support_exp);
let min_num_digits = oracle_digits_infos[0];
let (min_num_digits, max_num, main_outcome_prefix) = if oracle_digits_infos
.iter()
.skip(1)
.all(|x| x == &min_num_digits)
{
(
min_num_digits,
(1 << min_num_digits) - 1,
main_outcome_prefix.to_vec(),
)
} else {
let mut new_main_outcome_prefix = vec![0];
new_main_outcome_prefix.extend_from_slice(main_outcome_prefix);
(
min_num_digits + 1,
(1 << (min_num_digits + 1)) - 1,
new_main_outcome_prefix,
)
};
let max_error: usize = 1 << max_error_exp;
let half_max_error: usize = max_error >> 1;
let min_support: usize = 1 << min_support_exp;
let suffix_len = min_num_digits - main_outcome_prefix.len();
let (start, end) = compute_interval_from_prefix(&main_outcome_prefix, min_num_digits, 2);
if suffix_len < max_error_exp {
let start_max_error_suffix = start & ((1 << max_error_exp) - 1);
let left_bound = (start >> max_error_exp) << max_error_exp;
let right_bound = left_bound | (max_error - 1);
let error_interval_prefix = num_to_vec(left_bound, min_num_digits, max_error_exp, 2);
if start_max_error_suffix >= min_support && end <= right_bound - min_support {
let support_interval_prefix = if maximize_coverage {
error_interval_prefix
} else {
compute_min_support_covering_prefix(start, end, min_support, min_num_digits)
};
return vec![single_covering_prefix_combinations(
&main_outcome_prefix,
&support_interval_prefix,
oracle_digits_infos,
suffix_len,
)];
} else if start_max_error_suffix < min_support {
let right_interval_prefix = if maximize_coverage {
error_interval_prefix
} else {
compute_right_covering_prefix(end, max_error_exp, min_support, min_num_digits)
};
return if left_bound == 0 {
vec![single_covering_prefix_combinations(
&main_outcome_prefix,
&right_interval_prefix,
oracle_digits_infos,
suffix_len,
)]
} else {
let left_interval_prefix = if maximize_coverage {
num_to_vec(
left_bound - half_max_error,
min_num_digits,
max_error_exp - 1,
2,
)
} else {
compute_left_covering_prefix(start, max_error_exp, min_support, min_num_digits)
};
double_covering_prefix_combinations(
&main_outcome_prefix,
&right_interval_prefix,
&left_interval_prefix,
oracle_digits_infos,
suffix_len,
)
};
} else if end > right_bound - min_support {
let left_interval_prefix = if maximize_coverage {
error_interval_prefix
} else {
compute_left_covering_prefix(start, max_error_exp, min_support, min_num_digits)
};
return if right_bound == max_num {
vec![single_covering_prefix_combinations(
&main_outcome_prefix,
&left_interval_prefix,
oracle_digits_infos,
suffix_len,
)]
} else {
let right_interval_prefix = if maximize_coverage {
num_to_vec(right_bound + 1, min_num_digits, max_error_exp - 1, 2)
} else {
compute_right_covering_prefix(end, max_error_exp, min_support, min_num_digits)
};
double_covering_prefix_combinations(
&main_outcome_prefix,
&left_interval_prefix,
&right_interval_prefix,
oracle_digits_infos,
suffix_len,
)
};
} else {
unreachable!();
}
}
let mut res = Vec::new();
if start != 0 {
let right_interval_prefix = if maximize_coverage {
num_to_vec(start, min_num_digits, max_error_exp - 1, 2)
} else {
num_to_vec(start, min_num_digits, min_support_exp, 2)
};
let left_interval_prefix = if maximize_coverage {
num_to_vec(start - half_max_error, min_num_digits, max_error_exp - 1, 2)
} else {
num_to_vec(start - min_support, min_num_digits, min_support_exp, 2)
};
let mut combination = double_covering_restricted_prefix_combinations(
&right_interval_prefix,
&left_interval_prefix,
oracle_digits_infos,
min_num_digits - right_interval_prefix.len(),
);
res.append(&mut combination);
}
res.push(single_covering_prefix_combinations(
&main_outcome_prefix,
&main_outcome_prefix,
oracle_digits_infos,
suffix_len,
));
if end != max_num {
let right_interval_prefix = if maximize_coverage {
num_to_vec(
end - half_max_error + 1,
min_num_digits,
max_error_exp - 1,
2,
)
} else {
num_to_vec(end - min_support + 1, min_num_digits, min_support_exp, 2)
};
let left_interval_prefix = if maximize_coverage {
num_to_vec(end + 1, min_num_digits, max_error_exp - 1, 2)
} else {
num_to_vec(end + 1, min_num_digits, min_support_exp, 2)
};
let mut combination = double_covering_restricted_prefix_combinations(
&right_interval_prefix,
&left_interval_prefix,
oracle_digits_infos,
min_num_digits - right_interval_prefix.len(),
);
res.append(&mut combination);
}
res
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_utils::{
get_variable_oracle_numeric_infos, same_num_digits_oracle_numeric_infos,
};
use secp256k1_zkp::rand::{thread_rng, RngCore};
type CoveringCetsMinMax = (Vec<(Vec<usize>, Vec<usize>)>, Vec<(Vec<usize>, Vec<usize>)>);
fn compute_covering_cets_min_and_max(
oracle_digits_infos: &[usize],
main_outcome_prefix: &[usize],
max_error_exp: usize,
min_support_exp: usize,
) -> CoveringCetsMinMax {
let covering_max = compute_outcome_combinations(
oracle_digits_infos,
main_outcome_prefix,
max_error_exp,
min_support_exp,
true,
);
let covering_min = compute_outcome_combinations(
oracle_digits_infos,
main_outcome_prefix,
max_error_exp,
min_support_exp,
false,
);
assert!(covering_max.iter().all(|x| x.len() == 2));
assert!(covering_min.iter().all(|x| x.len() == 2));
(
covering_max
.into_iter()
.map(|mut x| (x.remove(0), x.remove(x.len() - 1)))
.collect(),
covering_min
.into_iter()
.map(|mut x| (x.remove(0), x.remove(x.len() - 1)))
.collect(),
)
}
struct TestCase {
main_outcome_prefix: Vec<usize>,
nb_digits: usize,
max_error_exp: usize,
min_support_exp: usize,
expected_max: Vec<(Vec<usize>, Vec<usize>)>,
expected_min: Vec<(Vec<usize>, Vec<usize>)>,
}
fn outcome_prefixes() -> Vec<Vec<usize>> {
vec![
vec![0, 0, 1, 0, 1, 1, 0, 0, 1],
vec![0, 1, 0, 0, 0, 0, 0, 1, 1],
vec![0, 1, 1, 1, 1, 1, 0, 1, 0],
vec![0, 1],
vec![0, 0, 1],
vec![1, 1, 1, 1, 1, 1, 1, 1],
vec![0, 0],
vec![1, 1],
]
}
fn prefix(index: usize) -> Vec<usize> {
outcome_prefixes().remove(index)
}
fn test_cases() -> Vec<TestCase> {
vec![
TestCase {
main_outcome_prefix: prefix(0),
nb_digits: 14,
max_error_exp: 11,
min_support_exp: 7,
expected_max: vec![(prefix(0), vec![0, 0, 1])],
expected_min: vec![(prefix(0), vec![0, 0, 1, 0, 1])],
},
TestCase {
main_outcome_prefix: prefix(1),
nb_digits: 13,
max_error_exp: 11,
min_support_exp: 7,
expected_max: vec![(prefix(1), vec![0, 0, 1]), (prefix(1), vec![0, 1])],
expected_min: vec![
(prefix(1), vec![0, 0, 1, 1, 1, 1]),
(prefix(1), vec![0, 1, 0, 0, 0]),
],
},
TestCase {
main_outcome_prefix: prefix(2),
nb_digits: 13,
max_error_exp: 11,
min_support_exp: 7,
expected_max: vec![(prefix(2), vec![0, 1]), (prefix(2), vec![1, 0, 0])],
expected_min: vec![
(prefix(2), vec![0, 1, 1, 1, 1]),
(prefix(2), vec![1, 0, 0, 0, 0, 0, 0]),
],
},
TestCase {
main_outcome_prefix: prefix(3),
nb_digits: 13,
max_error_exp: 11,
min_support_exp: 7,
expected_max: vec![
(vec![0, 1, 0], vec![0, 0, 1]),
(prefix(3), prefix(3)),
(vec![0, 1, 1], vec![1, 0, 0]),
],
expected_min: vec![
(vec![0, 1, 0, 0, 0, 0], vec![0, 0, 1, 1, 1, 1]),
(prefix(3), prefix(3)),
(vec![0, 1, 1, 1, 1, 1], vec![1, 0, 0, 0, 0, 0]),
],
},
TestCase {
main_outcome_prefix: prefix(4),
nb_digits: 15,
max_error_exp: 11,
min_support_exp: 7,
expected_max: vec![
(vec![0, 0, 1, 0, 0], vec![0, 0, 0, 1, 1]),
(prefix(4), prefix(4)),
(vec![0, 0, 1, 1, 1], vec![0, 1, 0, 0, 0]),
],
expected_min: vec![
(vec![0, 0, 1, 0, 0, 0, 0, 0], vec![0, 0, 0, 1, 1, 1, 1, 1]),
(prefix(4), prefix(4)),
(vec![0, 0, 1, 1, 1, 1, 1, 1], vec![0, 1, 0, 0, 0, 0, 0, 0]),
],
},
TestCase {
main_outcome_prefix: prefix(5),
nb_digits: 13,
max_error_exp: 11,
min_support_exp: 7,
expected_max: vec![(prefix(5), vec![1, 1])],
expected_min: vec![(prefix(5), vec![1, 1, 1, 1, 1])],
},
TestCase {
main_outcome_prefix: prefix(6),
nb_digits: 13,
max_error_exp: 11,
min_support_exp: 7,
expected_max: vec![(prefix(6), prefix(6)), (vec![0, 0, 1], vec![0, 1, 0])],
expected_min: vec![
(prefix(6), prefix(6)),
(vec![0, 0, 1, 1, 1, 1], vec![0, 1, 0, 0, 0, 0]),
],
},
TestCase {
main_outcome_prefix: prefix(7),
nb_digits: 14,
max_error_exp: 11,
min_support_exp: 7,
expected_max: vec![(vec![1, 1, 0, 0], vec![1, 0, 1, 1]), (prefix(7), prefix(7))],
expected_min: vec![
(vec![1, 1, 0, 0, 0, 0, 0], vec![1, 0, 1, 1, 1, 1, 1]),
(prefix(7), prefix(7)),
],
},
]
}
#[test]
fn compute_outcome_combination_tests() {
for case in test_cases() {
let (max, min) = compute_covering_cets_min_and_max(
&same_num_digits_oracle_numeric_infos(2, case.nb_digits, 2).nb_digits,
&case.main_outcome_prefix,
case.max_error_exp,
case.min_support_exp,
);
assert_eq!(case.expected_max, max);
assert_eq!(case.expected_min, min);
}
}
#[test]
fn compute_outcome_three_oracles() {
let prefix = vec![0, 1, 0];
let res = compute_outcome_combinations(
&same_num_digits_oracle_numeric_infos(3, 3, 2).nb_digits,
&prefix,
2,
1,
true,
);
let expected = vec![
vec![vec![0, 1, 0], vec![0], vec![0]],
vec![vec![0, 1, 0], vec![0], vec![1, 0]],
vec![vec![0, 1, 0], vec![1, 0], vec![0]],
vec![vec![0, 1, 0], vec![1, 0], vec![1, 0]],
];
assert_eq!(res, expected);
}
#[test]
fn multiple_interval_within_bounds() {
let mut rng = thread_rng();
let nb_digits = (rng.next_u32() % 29) + 2;
let nb_digits_used = rng.next_u32() % nb_digits + 1;
let mut main_outcome_prefix = Vec::with_capacity(nb_digits_used as usize);
for _ in 0..nb_digits_used {
main_outcome_prefix.push((rng.next_u32() % 2) as usize);
}
let max_error_exp = (rng.next_u32() % (nb_digits - 1)) + 1;
let min_support_exp = rng.next_u32() % max_error_exp;
let nb_digits = nb_digits as usize;
let max_error_exp = max_error_exp as usize;
let min_support_exp = min_support_exp as usize;
let max_error = 1 << max_error_exp;
let min_support = 1 << min_support_exp;
let max_val = (1 << nb_digits) - 1;
let (cover_max, cover_min) = compute_covering_cets_min_and_max(
&same_num_digits_oracle_numeric_infos(2, nb_digits, 2).nb_digits,
&main_outcome_prefix,
max_error_exp,
min_support_exp,
);
assert_eq!(cover_min.len(), cover_max.len());
assert!(cover_min
.iter()
.map(|(a, _)| a)
.zip(cover_max.iter().map(|(a, _)| a))
.all(|(a, b)| a.iter().zip(b.iter()).all(|(c, d)| c == d)));
let relevant_primary_prefixes = cover_max.iter().map(|(a, _)| a).collect::<Vec<_>>();
let (left, right) = compute_interval_from_prefix(&main_outcome_prefix, nb_digits, 2);
let primary_and_covering_intervals_max: Vec<((usize, usize), (usize, usize))> = cover_max
.iter()
.map(|(a, b)| {
(
compute_interval_from_prefix(a, nb_digits, 2),
compute_interval_from_prefix(b, nb_digits, 2),
)
})
.collect();
let cover_intervals_min: Vec<(usize, usize)> = cover_max
.iter()
.map(|(_, b)| compute_interval_from_prefix(b, nb_digits, 2))
.collect();
for (
((primary_left, primary_right), (max_cover_left, max_cover_right)),
(min_cover_left, min_cover_right),
) in primary_and_covering_intervals_max
.iter()
.cloned()
.zip(cover_intervals_min.iter().cloned())
{
assert!(max_cover_left <= min_cover_left);
assert!(max_cover_right <= min_cover_right);
if primary_left == max_cover_left && primary_right == max_cover_right {
assert_eq!(min_cover_left, max_cover_left);
assert_eq!(min_cover_right, max_cover_right);
}
let assert_valid_cover = |cover_left: usize, cover_right: usize, max_coverage: bool| {
if primary_left == cover_left && primary_right == cover_right {
} else if primary_left >= cover_left && primary_right <= cover_right {
if max_coverage {
assert_eq!(cover_right - cover_left + 1, max_error);
} else {
let side_to_boundary = std::cmp::max(
primary_right % max_error,
max_error - (primary_left % max_error),
);
assert!(cover_right - cover_left < 2 * side_to_boundary);
assert!(cover_right - cover_left + 1 >= side_to_boundary);
}
assert!(
primary_left - cover_left >= min_support
|| cover_left == 0
|| relevant_primary_prefixes.len() == 2
);
assert!(primary_right - cover_left < max_error);
assert!(
cover_right - primary_right >= min_support
|| cover_right == max_val
|| relevant_primary_prefixes.len() == 2
);
} else {
let (most_inner, least_inner, most_outer) = if primary_left <= cover_left {
(primary_left, primary_right, cover_right)
} else {
(primary_right, primary_left, cover_left)
};
let diff = |x: usize, y: usize| -> usize {
if x > y {
x - y
} else {
y - x
}
};
assert!(diff(least_inner, most_outer) >= min_support);
assert!(diff(most_inner, most_outer) < max_error);
}
};
assert_valid_cover(max_cover_left, max_cover_right, true);
assert_valid_cover(min_cover_left, min_cover_right, false);
}
let primary_interval = primary_and_covering_intervals_max
.iter()
.map(|(a, _)| *a)
.fold((usize::MAX, 0), |(min, max), (start, end)| {
(std::cmp::min(min, start), std::cmp::max(max, end))
});
assert_eq!(primary_interval, (left, right));
let (max_cover_interval_left, max_cover_interval_right) =
primary_and_covering_intervals_max
.iter()
.map(|(_, b)| *b)
.fold((usize::MAX, 0), |(min, max), (start, end)| {
(std::cmp::min(min, start), std::cmp::max(max, end))
});
let (min_cover_interval_left, min_cover_interval_right) = cover_intervals_min
.iter()
.fold((usize::MAX, 0), |(min, max), (start, end)| {
(std::cmp::min(min, *start), std::cmp::max(max, *end))
});
assert!(max_cover_interval_left <= min_cover_interval_left);
assert!(max_cover_interval_right >= min_cover_interval_right);
assert!(left - max_cover_interval_left >= min_support || max_cover_interval_left == 0);
assert!(left - max_cover_interval_left < max_error);
assert!(
max_cover_interval_right - right >= min_support || max_cover_interval_right == max_val
);
assert!(max_cover_interval_right - right < max_error);
assert!(left - min_cover_interval_left >= min_support || min_cover_interval_left == 0);
assert!(left - min_cover_interval_left < max_error);
assert!(
min_cover_interval_right - right >= min_support || min_cover_interval_right == max_val
);
assert!(min_cover_interval_right - right < max_error);
}
struct VariableLengthTestCase {
main_outcome_prefix: Vec<usize>,
nb_digits: Vec<usize>,
max_error_exp: usize,
min_support_exp: usize,
expected_max: Vec<(Vec<usize>, Vec<usize>)>,
expected_min: Vec<(Vec<usize>, Vec<usize>)>,
}
impl From<TestCase> for VariableLengthTestCase {
fn from(test_case: TestCase) -> VariableLengthTestCase {
let to_add = ((thread_rng().next_u32() % 10) + 1) as usize;
let extend = |y: &[usize]| {
let mut new_y = Vec::with_capacity(y.len() + to_add);
new_y.resize(to_add, 0);
new_y.extend(y.iter());
new_y
};
let expected_max = test_case
.expected_max
.iter()
.map(|(x, y)| (x.clone(), extend(y)))
.collect();
let expected_min = test_case
.expected_min
.iter()
.map(|(x, y)| (x.clone(), extend(y)))
.collect();
VariableLengthTestCase {
main_outcome_prefix: test_case.main_outcome_prefix,
nb_digits: vec![test_case.nb_digits, test_case.nb_digits + to_add],
max_error_exp: test_case.max_error_exp,
min_support_exp: test_case.min_support_exp,
expected_max,
expected_min,
}
}
}
fn variable_len_test_cases() -> Vec<VariableLengthTestCase> {
let black_list = [5, 7];
let mut test_cases = test_cases()
.into_iter()
.enumerate()
.filter(|(i, _)| !black_list.contains(i))
.map(|(_, x)| x.into())
.collect::<Vec<VariableLengthTestCase>>();
test_cases.append(&mut vec![VariableLengthTestCase {
main_outcome_prefix: vec![1, 1, 1, 1],
nb_digits: vec![4, 5],
max_error_exp: 2,
min_support_exp: 1,
expected_max: vec![
(vec![1, 1, 1, 1], vec![0, 1, 1]),
(vec![1, 1, 1, 1], vec![1, 0, 0, 0]),
],
expected_min: vec![
(vec![1, 1, 1, 1], vec![0, 1, 1]),
(vec![1, 1, 1, 1], vec![1, 0, 0, 0]),
],
}]);
test_cases
}
#[test]
fn variable_nb_digit_tests() {
for case in variable_len_test_cases() {
let (max, min) = compute_covering_cets_min_and_max(
&get_variable_oracle_numeric_infos(&case.nb_digits, 2).nb_digits,
&case.main_outcome_prefix,
case.max_error_exp,
case.min_support_exp,
);
assert_eq!(case.expected_max, max);
assert_eq!(case.expected_min, min);
}
}
}