use implicit_predicates_gen::{
Error, ExactPlan, Leaves, MAX_COORD_COMPONENTS, difference_graph, exact_plan_differences,
exact_plan_raw, exact_plan_spans_translated, exact_plan_spans_untranslated, parse,
};
const ORIENT3D: &str = include_str!("fixtures/orient3d.pred");
const INSPHERE: &str = include_str!("fixtures/insphere.pred");
const INSPHERE_RAW: &str = include_str!("fixtures/insphere_raw.pred");
const DIFFERENCE: &str = "fn p(a: Point3, b: Point3) -> Sign { a.x - b.x }";
fn domain() -> (f64, f64) {
(2f64.powi(-480), 2f64.powi(480))
}
fn try_translated(source: &str, components: usize) -> Result<ExactPlan, Error> {
let p = parse(source, "t.pred").unwrap().remove(0);
let g = difference_graph(&p.main, "t.pred", p.position).unwrap();
let (min, max) = domain();
exact_plan_spans_translated(&g, components, "t.pred", p.position, min, max)
}
fn try_untranslated(source: &str, components: usize) -> Result<ExactPlan, Error> {
let p = parse(source, "t.pred").unwrap().remove(0);
let position = p.exact_position.unwrap_or(p.position);
let g = p.exact.unwrap_or(p.main);
let (min, max) = domain();
exact_plan_spans_untranslated(&g, components, "t.pred", position, min, max)
}
fn translated(source: &str) -> ExactPlan {
try_translated(source, MAX_COORD_COMPONENTS).unwrap()
}
fn untranslated(source: &str) -> ExactPlan {
try_untranslated(source, MAX_COORD_COMPONENTS).unwrap()
}
fn exponents(plan: &ExactPlan) -> (i32, i32) {
let exponent = |x: f64| {
assert!(
x.is_normal() && x > 0.0 && x.to_bits() & ((1 << 52) - 1) == 0,
"{x} is not a power of two"
);
x.log2() as i32
};
(exponent(plan.range.min), exponent(plan.range.max))
}
#[test]
fn coordinates_have_at_most_16_components() {
assert_eq!(MAX_COORD_COMPONENTS, 16);
}
#[test]
fn the_ends_of_every_range_are_powers_of_two() {
for plan in [
translated(ORIENT3D),
untranslated(ORIENT3D),
translated(INSPHERE),
untranslated(INSPHERE_RAW),
translated(DIFFERENCE),
untranslated(DIFFERENCE),
] {
let (min, max) = exponents(&plan);
assert!(min <= max, "{plan:?}");
}
}
#[test]
fn every_form_has_the_derived_range() {
assert_eq!(exponents(&translated(ORIENT3D)), (-188, 234));
assert_eq!(exponents(&untranslated(ORIENT3D)), (-188, 235));
assert_eq!(exponents(&translated(INSPHERE)), (-108, 154));
}
#[test]
fn with_one_component_the_range_is_that_of_the_stack_forms() {
let (min, max) = domain();
for source in [ORIENT3D, INSPHERE] {
let p = parse(source, "t.pred").unwrap().remove(0);
let g = difference_graph(&p.main, "t.pred", p.position).unwrap();
let two = exact_plan_differences(&g, Leaves::Two, "t.pred", p.position, min, max).unwrap();
assert_eq!(try_translated(source, 1).unwrap().range, two.range);
}
for source in [ORIENT3D, INSPHERE_RAW] {
let p = parse(source, "t.pred").unwrap().remove(0);
let position = p.exact_position.unwrap_or(p.position);
let g = p.exact.unwrap_or(p.main);
let raw = exact_plan_raw(&g, "t.pred", position, min, max).unwrap();
assert_eq!(try_untranslated(source, 1).unwrap().range, raw.range);
}
}
#[test]
fn the_range_over_spans_lies_within_the_range_over_one_component() {
let (min, max) = domain();
for source in [ORIENT3D, INSPHERE] {
let p = parse(source, "t.pred").unwrap().remove(0);
let g = difference_graph(&p.main, "t.pred", p.position).unwrap();
let two = exact_plan_differences(&g, Leaves::Two, "t.pred", p.position, min, max).unwrap();
let spans = translated(source);
assert!(two.range.min <= spans.range.min && spans.range.max <= two.range.max);
}
for source in [ORIENT3D, INSPHERE_RAW] {
let p = parse(source, "t.pred").unwrap().remove(0);
let position = p.exact_position.unwrap_or(p.position);
let g = p.exact.unwrap_or(p.main);
let raw = exact_plan_raw(&g, "t.pred", position, min, max).unwrap();
let spans = untranslated(source);
assert!(raw.range.min <= spans.range.min && spans.range.max <= raw.range.max);
}
}
#[test]
fn more_components_never_widen_the_range() {
for source in [ORIENT3D, INSPHERE] {
let mut last = try_translated(source, 1).unwrap().range;
for components in [2, 4, 5, 9, 16, 17, 64] {
let range = try_translated(source, components).unwrap().range;
assert!(
last.min <= range.min && range.max <= last.max,
"{components}"
);
last = range;
}
}
}
#[test]
fn a_degree_one_predicate_has_the_full_domain_as_range() {
let (min, max) = domain();
for plan in [translated(DIFFERENCE), untranslated(DIFFERENCE)] {
assert_eq!((plan.range.min, plan.range.max), (min, max));
}
}
fn rejected(result: Result<ExactPlan, Error>, fragment: &str) {
let e = result.expect_err("the definition must be rejected");
assert!(e.message.contains(fragment), "{e}");
assert_eq!(e.file, "t.pred");
assert_eq!((e.line, e.column), (1, 4), "{e}");
}
#[test]
fn a_degree_without_a_range_over_spans_is_an_error() {
let source = "fn p(a: Point3, b: Point3) -> Sign { let x = a.x - b.x; \
let t1 = x * x; let t2 = t1 * t1; let t3 = t2 * t2; let t4 = t3 * t3; \
let t5 = t4 * x; t5 * x }";
let p = parse(source, "t.pred").unwrap().remove(0);
let g = difference_graph(&p.main, "t.pred", p.position).unwrap();
let (min, max) = domain();
let stack = exact_plan_differences(&g, Leaves::One, "t.pred", p.position, min, max).unwrap();
assert_eq!(exponents(&stack), (24, 28));
rejected(
try_translated(source, MAX_COORD_COMPONENTS),
"no input range",
);
rejected(try_translated(source, MAX_COORD_COMPONENTS), "degree 17");
let raw_product = vec!["a.x"; 21].join(" * ");
let source = format!("fn p(a: Point3, b: Point3) -> Sign {{ {raw_product} - b.x }}");
rejected(try_untranslated(&source, 1), "no input range");
rejected(
try_untranslated(&source, MAX_COORD_COMPONENTS),
"no input range",
);
}
#[test]
fn a_definition_too_large_is_an_error_not_a_hang() {
let mut body = String::from("let t0 = a.x - b.x; ");
for i in 1..=31 {
body += &format!("let t{i} = t{} * t{}; ", i - 1, i - 1);
}
let source = format!("fn p(a: Point3, b: Point3) -> Sign {{ {body}t31 * t0 }}");
rejected(
try_translated(&source, MAX_COORD_COMPONENTS),
"no input range",
);
rejected(
try_untranslated(&source, MAX_COORD_COMPONENTS),
"no input range",
);
}
#[test]
fn the_lengths_are_those_of_the_derived_range() {
let plan = translated("fn p(a: Point3, b: Point3) -> Sign { (a.x - b.x) * (a.x - b.x) }");
assert_eq!(exponents(&plan), (-428, 474));
assert_eq!(plan.lengths, [32, 1919]);
assert_eq!(plan.total, 1951);
let plan = untranslated("fn p(a: Point3, b: Point3) -> Sign { a.x * b.y }");
assert_eq!(plan.lengths, [16, 16, 512]);
}