use criterion::{Criterion, Throughput, criterion_group, criterion_main};
use grid1d::{bounds::*, intervals::*};
use num_valid::{RealNative64StrictFinite, RealNative64StrictFiniteInDebug};
use std::hint::black_box;

#[cfg(feature = "rug")]
use num_valid::{RealRugStrictFinite, RealScalar};

use try_create::TryNew;

/// Benchmark interval construction for different scalar types
fn bench_interval_construction(c: &mut Criterion) {
    let mut group = c.benchmark_group("interval_construction");

    let n = 10_000;
    group.throughput(Throughput::Elements(n));

    // Raw f64 construction
    group.bench_function("closed_f64", |b| {
        b.iter(|| {
            let intervals: Vec<_> = (0..n)
                .map(|i| {
                    let start = (i as f64) / (n as f64);
                    IntervalClosed::new(black_box(start), black_box(start + 0.1))
                })
                .collect();
            black_box(intervals);
        });
    });

    // Debug-validated scalar construction
    group.bench_function("closed_debug_validated", |b| {
        b.iter(|| {
            let intervals: Vec<_> = (0..n)
                .map(|i| {
                    let start =
                        RealNative64StrictFiniteInDebug::try_new((i as f64) / (n as f64)).unwrap();
                    let end =
                        RealNative64StrictFiniteInDebug::try_new((i as f64) / (n as f64) + 0.1)
                            .unwrap();
                    IntervalClosed::new(black_box(start), black_box(end))
                })
                .collect();
            black_box(intervals);
        });
    });

    // Always-validated scalar construction
    group.bench_function("closed_always_validated", |b| {
        b.iter(|| {
            let intervals: Vec<_> = (0..n)
                .map(|i| {
                    let start = RealNative64StrictFinite::try_new((i as f64) / (n as f64)).unwrap();
                    let end =
                        RealNative64StrictFinite::try_new((i as f64) / (n as f64) + 0.1).unwrap();
                    IntervalClosed::new(black_box(start), black_box(end))
                })
                .collect();
            black_box(intervals);
        });
    });

    #[cfg(feature = "rug")]
    {
        // Arbitrary precision construction (128-bit)
        group.bench_function("closed_rug_128", |b| {
            b.iter(|| {
                let intervals: Vec<_> = (0..n)
                    .map(|i| {
                        let start =
                            RealRugStrictFinite::<128>::try_from_f64((i as f64) / (n as f64))
                                .unwrap();
                        let end =
                            RealRugStrictFinite::<128>::try_from_f64((i as f64) / (n as f64) + 0.1)
                                .unwrap();
                        IntervalClosed::new(black_box(start), black_box(end))
                    })
                    .collect();
                black_box(intervals);
            });
        });

        // High precision construction (256-bit)
        group.bench_function("closed_rug_256", |b| {
            b.iter(|| {
                let intervals: Vec<_> = (0..n)
                    .map(|i| {
                        let start =
                            RealRugStrictFinite::<256>::try_from_f64((i as f64) / (n as f64))
                                .unwrap();
                        let end =
                            RealRugStrictFinite::<256>::try_from_f64((i as f64) / (n as f64) + 0.1)
                                .unwrap();
                        IntervalClosed::new(black_box(start), black_box(end))
                    })
                    .collect();
                black_box(intervals);
            });
        });
    }

    // Different interval types with f64
    group.bench_function("open_f64", |b| {
        b.iter(|| {
            let intervals: Vec<_> = (0..n)
                .map(|i| {
                    let start = (i as f64) / (n as f64);
                    IntervalOpen::new(black_box(start), black_box(start + 0.1))
                })
                .collect();
            black_box(intervals);
        });
    });

    group.bench_function("half_open_f64", |b| {
        b.iter(|| {
            let intervals: Vec<_> = (0..n)
                .map(|i| {
                    let start = (i as f64) / (n as f64);
                    IntervalLowerClosedUpperOpen::new(black_box(start), black_box(start + 0.1))
                })
                .collect();
            black_box(intervals);
        });
    });

    group.bench_function("unbounded_f64", |b| {
        b.iter(|| {
            let intervals: Vec<_> = (0..n)
                .map(|i| {
                    let start = (i as f64) / (n as f64);
                    IntervalLowerClosedUpperUnbounded::new(black_box(start))
                })
                .collect();
            black_box(intervals);
        });
    });

    group.finish();
}

/// Benchmark point containment operations for different interval types and scalar types
fn bench_point_containment(c: &mut Criterion) {
    let mut group = c.benchmark_group("point_containment");

    let n_intervals = 1_000;
    let n_queries = 10_000;
    group.throughput(Throughput::Elements(n_queries));

    // Setup test data for f64
    let closed_intervals_f64: Vec<_> = (0..n_intervals)
        .map(|i| {
            let start = (i as f64) / (n_intervals as f64);
            IntervalClosed::new(start, start + 0.1)
        })
        .collect();

    let open_intervals_f64: Vec<_> = (0..n_intervals)
        .map(|i| {
            let start = (i as f64) / (n_intervals as f64);
            IntervalOpen::new(start, start + 0.1)
        })
        .collect();

    let half_open_intervals_f64: Vec<_> = (0..n_intervals)
        .map(|i| {
            let start = (i as f64) / (n_intervals as f64);
            IntervalLowerClosedUpperOpen::new(start, start + 0.1)
        })
        .collect();

    let unbounded_intervals_f64: Vec<_> = (0..n_intervals)
        .map(|i| {
            let start = (i as f64) / (n_intervals as f64);
            IntervalLowerClosedUpperUnbounded::new(start)
        })
        .collect();

    let test_points_f64: Vec<f64> = (0..n_queries)
        .map(|i| (i as f64) / (n_queries as f64))
        .collect();

    // Setup test data for validated scalars
    let closed_intervals_validated: Vec<_> = (0..n_intervals)
        .map(|i| {
            let start =
                RealNative64StrictFinite::try_new((i as f64) / (n_intervals as f64)).unwrap();
            let end =
                RealNative64StrictFinite::try_new((i as f64) / (n_intervals as f64) + 0.1).unwrap();
            IntervalClosed::new(start, end)
        })
        .collect();

    let test_points_validated: Vec<_> = (0..n_queries)
        .map(|i| RealNative64StrictFinite::try_new((i as f64) / (n_queries as f64)).unwrap())
        .collect();

    #[cfg(feature = "rug")]
    let (closed_intervals_rug, test_points_rug) = {
        let intervals: Vec<_> = (0..n_intervals)
            .map(|i| {
                let start =
                    RealRugStrictFinite::<128>::try_from_f64((i as f64) / (n_intervals as f64))
                        .unwrap();
                let end = RealRugStrictFinite::<128>::try_from_f64(
                    (i as f64) / (n_intervals as f64) + 0.1,
                )
                .unwrap();
                IntervalClosed::new(start, end)
            })
            .collect();

        let points: Vec<_> = (0..n_queries)
            .map(|i| {
                RealRugStrictFinite::<128>::try_from_f64((i as f64) / (n_queries as f64)).unwrap()
            })
            .collect();

        (intervals, points)
    };

    // Benchmark different interval types with f64
    group.bench_function("closed_f64", |b| {
        b.iter(|| {
            for point in &test_points_f64 {
                for interval in &closed_intervals_f64 {
                    let contains = interval.contains_point(black_box(point));
                    black_box(contains);
                }
            }
        });
    });

    group.bench_function("open_f64", |b| {
        b.iter(|| {
            for point in &test_points_f64 {
                for interval in &open_intervals_f64 {
                    let contains = interval.contains_point(black_box(point));
                    black_box(contains);
                }
            }
        });
    });

    group.bench_function("half_open_f64", |b| {
        b.iter(|| {
            for point in &test_points_f64 {
                for interval in &half_open_intervals_f64 {
                    let contains = interval.contains_point(black_box(point));
                    black_box(contains);
                }
            }
        });
    });

    group.bench_function("unbounded_f64", |b| {
        b.iter(|| {
            for point in &test_points_f64 {
                for interval in &unbounded_intervals_f64 {
                    let contains = interval.contains_point(black_box(point));
                    black_box(contains);
                }
            }
        });
    });

    // Benchmark validated scalars
    group.bench_function("closed_validated", |b| {
        b.iter(|| {
            for point in &test_points_validated {
                for interval in &closed_intervals_validated {
                    let contains = interval.contains_point(black_box(point));
                    black_box(contains);
                }
            }
        });
    });

    #[cfg(feature = "rug")]
    group.bench_function("closed_rug_128", |b| {
        b.iter(|| {
            for point in &test_points_rug {
                for interval in &closed_intervals_rug {
                    let contains = interval.contains_point(black_box(point));
                    black_box(contains);
                }
            }
        });
    });

    group.finish();
}

/// Benchmark interval intersection operations
fn bench_interval_intersections(c: &mut Criterion) {
    let mut group = c.benchmark_group("interval_intersections");

    let n = 1_000;
    group.throughput(Throughput::Elements(n));

    // Setup overlapping interval pairs for f64
    let interval_pairs_f64: Vec<(IntervalClosed<f64>, IntervalClosed<f64>)> = (0..n)
        .map(|i| {
            let start1 = (i as f64) / (n as f64);
            let start2 = start1 + 0.05;
            (
                IntervalClosed::new(start1, start1 + 0.1),
                IntervalClosed::new(start2, start2 + 0.1),
            )
        })
        .collect();

    let mixed_pairs_f64: Vec<(IntervalClosed<f64>, IntervalOpen<f64>)> = (0..n)
        .map(|i| {
            let start1 = (i as f64) / (n as f64);
            let start2 = start1 + 0.05;
            (
                IntervalClosed::new(start1, start1 + 0.1),
                IntervalOpen::new(start2, start2 + 0.1),
            )
        })
        .collect();

    let half_open_pairs_f64: Vec<(
        IntervalLowerClosedUpperOpen<f64>,
        IntervalLowerOpenUpperClosed<f64>,
    )> = (0..n)
        .map(|i| {
            let start1 = (i as f64) / (n as f64);
            let start2 = start1 + 0.05;
            (
                IntervalLowerClosedUpperOpen::new(start1, start1 + 0.1),
                IntervalLowerOpenUpperClosed::new(start2, start2 + 0.1),
            )
        })
        .collect();

    // Setup for validated scalars
    let interval_pairs_validated: Vec<(
        IntervalClosed<RealNative64StrictFinite>,
        IntervalClosed<RealNative64StrictFinite>,
    )> = (0..n)
        .map(|i| {
            let start1 = RealNative64StrictFinite::try_new((i as f64) / (n as f64)).unwrap();
            let end1 = RealNative64StrictFinite::try_new((i as f64) / (n as f64) + 0.1).unwrap();
            let start2 = RealNative64StrictFinite::try_new((i as f64) / (n as f64) + 0.05).unwrap();
            let end2 = RealNative64StrictFinite::try_new((i as f64) / (n as f64) + 0.15).unwrap();
            (
                IntervalClosed::new(start1, end1),
                IntervalClosed::new(start2, end2),
            )
        })
        .collect();

    #[cfg(feature = "rug")]
    let interval_pairs_rug: Vec<(
        IntervalClosed<RealRugStrictFinite<128>>,
        IntervalClosed<RealRugStrictFinite<128>>,
    )> = (0..n)
        .map(|i| {
            let start1 = RealRugStrictFinite::<128>::try_from_f64((i as f64) / (n as f64)).unwrap();
            let end1 =
                RealRugStrictFinite::<128>::try_from_f64((i as f64) / (n as f64) + 0.1).unwrap();
            let start2 =
                RealRugStrictFinite::<128>::try_from_f64((i as f64) / (n as f64) + 0.05).unwrap();
            let end2 =
                RealRugStrictFinite::<128>::try_from_f64((i as f64) / (n as f64) + 0.15).unwrap();
            (
                IntervalClosed::new(start1, end1),
                IntervalClosed::new(start2, end2),
            )
        })
        .collect();

    // Benchmark different intersection types
    group.bench_function("closed_closed_f64", |b| {
        b.iter(|| {
            for (a, b) in &interval_pairs_f64 {
                let intersection = a.intersection(black_box(b));
                black_box(intersection);
            }
        });
    });

    group.bench_function("closed_open_f64", |b| {
        b.iter(|| {
            for (a, b) in &mixed_pairs_f64 {
                let intersection = a.intersection(black_box(b));
                black_box(intersection);
            }
        });
    });

    group.bench_function("half_open_mixed_f64", |b| {
        b.iter(|| {
            for (a, b) in &half_open_pairs_f64 {
                let intersection = a.intersection(black_box(b));
                black_box(intersection);
            }
        });
    });

    group.bench_function("closed_closed_validated", |b| {
        b.iter(|| {
            for (a, b) in &interval_pairs_validated {
                let intersection = a.intersection(black_box(b));
                black_box(intersection);
            }
        });
    });

    #[cfg(feature = "rug")]
    group.bench_function("closed_closed_rug_128", |b| {
        b.iter(|| {
            for (a, b) in &interval_pairs_rug {
                let intersection = a.intersection(black_box(b));
                black_box(intersection);
            }
        });
    });

    group.finish();
}

/// Benchmark interval geometric computations (length, midpoint, etc.)
fn bench_interval_geometry(c: &mut Criterion) {
    let mut group = c.benchmark_group("interval_geometry");

    let n = 10_000;
    group.throughput(Throughput::Elements(n));

    // Setup intervals for different scalar types
    let finite_intervals_f64: Vec<IntervalClosed<f64>> = (0..n)
        .map(|i| {
            let start = (i as f64) / (n as f64);
            let length = 0.1 + (i as f64) / (n as f64);
            IntervalClosed::new(start, start + length)
        })
        .collect();

    let finite_intervals_validated: Vec<IntervalClosed<RealNative64StrictFinite>> = (0..n)
        .map(|i| {
            let start = RealNative64StrictFinite::try_new((i as f64) / (n as f64)).unwrap();
            let length = RealNative64StrictFinite::try_new(0.1 + (i as f64) / (n as f64)).unwrap();
            let end = start + length;
            IntervalClosed::new(start, end)
        })
        .collect();

    #[cfg(feature = "rug")]
    let finite_intervals_rug: Vec<IntervalClosed<RealRugStrictFinite<128>>> = (0..n)
        .map(|i| {
            let start = RealRugStrictFinite::<128>::try_from_f64((i as f64) / (n as f64)).unwrap();
            let length =
                RealRugStrictFinite::<128>::try_from_f64(0.1 + (i as f64) / (n as f64)).unwrap();
            let end = start.clone() + length;
            IntervalClosed::new(start, end)
        })
        .collect();

    // Benchmark length computation
    group.bench_function("length_f64", |b| {
        b.iter(|| {
            for interval in &finite_intervals_f64 {
                let length = interval.length();
                black_box(length);
            }
        });
    });

    group.bench_function("length_validated", |b| {
        b.iter(|| {
            for interval in &finite_intervals_validated {
                let length = interval.length();
                black_box(length);
            }
        });
    });

    #[cfg(feature = "rug")]
    group.bench_function("length_rug_128", |b| {
        b.iter(|| {
            for interval in &finite_intervals_rug {
                let length = interval.length();
                black_box(length);
            }
        });
    });

    // Benchmark midpoint computation
    group.bench_function("midpoint_f64", |b| {
        b.iter(|| {
            for interval in &finite_intervals_f64 {
                let midpoint = interval.mid_point();
                black_box(midpoint);
            }
        });
    });

    group.bench_function("midpoint_validated", |b| {
        b.iter(|| {
            for interval in &finite_intervals_validated {
                let midpoint = interval.mid_point();
                black_box(midpoint);
            }
        });
    });

    #[cfg(feature = "rug")]
    group.bench_function("midpoint_rug_128", |b| {
        b.iter(|| {
            for interval in &finite_intervals_rug {
                let midpoint = interval.mid_point();
                black_box(midpoint);
            }
        });
    });

    // Benchmark boundary checks
    group.bench_function("boundary_checks_f64", |b| {
        b.iter(|| {
            for interval in &finite_intervals_f64 {
                let is_left_closed = interval.lower_bound().is_closed();
                let is_right_closed = interval.upper_bound().is_closed();
                //let is_bounded = interval.is_bounded();
                black_box((is_left_closed, is_right_closed));
            }
        });
    });

    group.finish();
}

/// Benchmark interval containment operations
fn bench_interval_containment(c: &mut Criterion) {
    let mut group = c.benchmark_group("interval_containment");

    let n = 1_000;
    group.throughput(Throughput::Elements(n * n));

    // Setup nested intervals for f64
    let outer_intervals_f64: Vec<IntervalClosed<f64>> = (0..n)
        .map(|i| {
            let start = (i as f64) / (n as f64);
            IntervalClosed::new(start, start + 0.2)
        })
        .collect();

    let inner_intervals_f64: Vec<IntervalClosed<f64>> = (0..n)
        .map(|i| {
            let start = (i as f64) / (n as f64) + 0.05;
            IntervalClosed::new(start, start + 0.1)
        })
        .collect();

    // Setup for validated scalars
    let outer_intervals_validated: Vec<IntervalClosed<RealNative64StrictFinite>> = (0..n)
        .map(|i| {
            let start = RealNative64StrictFinite::try_new((i as f64) / (n as f64)).unwrap();
            let end = RealNative64StrictFinite::try_new((i as f64) / (n as f64) + 0.2).unwrap();
            IntervalClosed::new(start, end)
        })
        .collect();

    let inner_intervals_validated: Vec<IntervalClosed<RealNative64StrictFinite>> = (0..n)
        .map(|i| {
            let start = RealNative64StrictFinite::try_new((i as f64) / (n as f64) + 0.05).unwrap();
            let end = RealNative64StrictFinite::try_new((i as f64) / (n as f64) + 0.15).unwrap();
            IntervalClosed::new(start, end)
        })
        .collect();

    #[cfg(feature = "rug")]
    let (outer_intervals_rug, inner_intervals_rug) = {
        let outer: Vec<IntervalClosed<RealRugStrictFinite<128>>> = (0..n)
            .map(|i| {
                let start =
                    RealRugStrictFinite::<128>::try_from_f64((i as f64) / (n as f64)).unwrap();
                let end = RealRugStrictFinite::<128>::try_from_f64((i as f64) / (n as f64) + 0.2)
                    .unwrap();
                IntervalClosed::new(start, end)
            })
            .collect();

        let inner: Vec<IntervalClosed<RealRugStrictFinite<128>>> = (0..n)
            .map(|i| {
                let start =
                    RealRugStrictFinite::<128>::try_from_f64((i as f64) / (n as f64) + 0.05)
                        .unwrap();
                let end = RealRugStrictFinite::<128>::try_from_f64((i as f64) / (n as f64) + 0.15)
                    .unwrap();
                IntervalClosed::new(start, end)
            })
            .collect();

        (outer, inner)
    };

    // Benchmark containment checks
    group.bench_function("containment_f64", |b| {
        b.iter(|| {
            for outer in &outer_intervals_f64 {
                for inner in &inner_intervals_f64 {
                    let contains = outer.contains_interval(black_box(inner));
                    black_box(contains);
                }
            }
        });
    });

    group.bench_function("containment_validated", |b| {
        b.iter(|| {
            for outer in &outer_intervals_validated {
                for inner in &inner_intervals_validated {
                    let contains = outer.contains_interval(black_box(inner));
                    black_box(contains);
                }
            }
        });
    });

    #[cfg(feature = "rug")]
    group.bench_function("containment_rug_128", |b| {
        b.iter(|| {
            for outer in &outer_intervals_rug {
                for inner in &inner_intervals_rug {
                    let contains = outer.contains_interval(black_box(inner));
                    black_box(contains);
                }
            }
        });
    });

    group.finish();
}

/// Benchmark boundary operations and predicates
fn bench_boundary_operations(c: &mut Criterion) {
    let mut group = c.benchmark_group("boundary_operations");

    let n = 10_000;
    group.throughput(Throughput::Elements(n));

    // Setup different interval types
    let closed_intervals: Vec<IntervalClosed<f64>> = (0..n)
        .map(|i| {
            let start = (i as f64) / (n as f64);
            IntervalClosed::new(start, start + 0.1)
        })
        .collect();

    let open_intervals: Vec<IntervalOpen<f64>> = (0..n)
        .map(|i| {
            let start = (i as f64) / (n as f64);
            IntervalOpen::new(start, start + 0.1)
        })
        .collect();

    let half_open_intervals: Vec<IntervalLowerClosedUpperOpen<f64>> = (0..n)
        .map(|i| {
            let start = (i as f64) / (n as f64);
            IntervalLowerClosedUpperOpen::new(start, start + 0.1)
        })
        .collect();

    let unbounded_intervals: Vec<IntervalLowerClosedUpperUnbounded<f64>> = (0..n)
        .map(|i| {
            let start = (i as f64) / (n as f64);
            IntervalLowerClosedUpperUnbounded::new(start)
        })
        .collect();

    // Benchmark boundary predicates
    group.bench_function("boundary_predicates_closed", |b| {
        b.iter(|| {
            for interval in &closed_intervals {
                let left_closed = interval.lower_bound().is_closed();
                let right_closed = interval.upper_bound().is_closed();
                black_box((left_closed, right_closed));
            }
        });
    });

    group.bench_function("boundary_predicates_open", |b| {
        b.iter(|| {
            for interval in &open_intervals {
                let left_closed = interval.lower_bound().is_closed();
                let right_closed = interval.upper_bound().is_closed();
                black_box((left_closed, right_closed));
            }
        });
    });

    group.bench_function("boundary_predicates_half_open", |b| {
        b.iter(|| {
            for interval in &half_open_intervals {
                let left_closed = interval.lower_bound().is_closed();
                let right_closed = interval.upper_bound().is_closed();
                black_box((left_closed, right_closed));
            }
        });
    });

    group.bench_function("boundary_predicates_unbounded", |b| {
        b.iter(|| {
            for interval in &unbounded_intervals {
                let left_closed = interval.lower_bound().is_closed();
                black_box(left_closed);
            }
        });
    });

    group.finish();
}

/// Benchmark universal Interval enum operations
fn bench_universal_interval(c: &mut Criterion) {
    let mut group = c.benchmark_group("universal_interval");

    let n = 1_000;
    group.throughput(Throughput::Elements(n));

    // Create mixed interval types using the universal Interval enum
    let mixed_intervals: Vec<Interval<f64>> = (0..n)
        .map(|i| {
            let start = (i as f64) / (n as f64);
            match i % 4 {
                0 => IntervalClosed::new(start, start + 0.1).into(),
                1 => IntervalOpen::new(start, start + 0.1).into(),
                2 => IntervalLowerClosedUpperOpen::new(start, start + 0.1).into(),
                _ => IntervalLowerClosedUpperUnbounded::new(start).into(),
            }
        })
        .collect();

    let test_point = 0.5_f64;

    // Benchmark dynamic dispatch through universal enum
    group.bench_function("universal_point_containment", |b| {
        b.iter(|| {
            for interval in &mixed_intervals {
                let contains = interval.contains_point(black_box(&test_point));
                black_box(contains);
            }
        });
    });

    // Benchmark interval intersection with mixed types
    group.bench_function("universal_intersections", |b| {
        b.iter(|| {
            for i in 0..mixed_intervals.len() - 1 {
                let intersection =
                    mixed_intervals[i].intersection(black_box(&mixed_intervals[i + 1]));
                black_box(intersection);
            }
        });
    });

    group.finish();
}

/// Benchmark realistic interval workflows
fn bench_realistic_workflows(c: &mut Criterion) {
    let mut group = c.benchmark_group("realistic_workflows");

    // Simulate mesh refinement with interval splitting
    group.bench_function("mesh_refinement_simulation", |b| {
        let domain = IntervalClosed::new(0.0_f64, 1.0_f64);

        b.iter(|| {
            let mut intervals = vec![black_box(domain.clone())];

            // Simulate 5 levels of refinement
            for _level in 0..5 {
                let mut new_intervals = Vec::new();
                for interval in &intervals {
                    let mid = interval.mid_point();
                    let left = IntervalClosed::new(*interval.lower_bound_value(), mid);
                    let right = IntervalClosed::new(mid, *interval.upper_bound_value());
                    new_intervals.push(left);
                    new_intervals.push(right);
                }
                intervals = new_intervals;
            }

            black_box(intervals);
        });
    });

    // Simulate interval arithmetic for uncertainty propagation
    group.bench_function("uncertainty_propagation", |b| {
        let base_intervals: Vec<IntervalClosed<f64>> = (1..=100)
            .map(|i| {
                let center = (i as f64) / 100.0;
                let uncertainty = 0.01;
                IntervalClosed::new(center - uncertainty, center + uncertainty)
            })
            .collect();

        b.iter(|| {
            let mut result_intervals = Vec::new();

            for interval in &base_intervals {
                // Simulate arithmetic operations with uncertainty
                let a_pow_lower = interval.lower_bound_value().powf(1.1);
                let a_pow_upper = interval.upper_bound_value().powf(1.1);
                let a_pow = IntervalClosed::new(a_pow_lower, a_pow_upper);

                let b_pow_lower = interval.lower_bound_value().powf(1.05);
                let b_pow_upper = interval.upper_bound_value().powf(1.05);
                let b_pow = IntervalClosed::new(b_pow_lower, b_pow_upper);

                result_intervals.push(a_pow);
                result_intervals.push(b_pow);
            }

            black_box(result_intervals);
        });
    });

    group.finish();
}

// Group all benchmarks
criterion_group!(
    interval_benches,
    bench_interval_construction,
    bench_point_containment,
    bench_interval_intersections,
    bench_interval_geometry,
    bench_interval_containment,
    bench_boundary_operations,
    bench_universal_interval,
    bench_realistic_workflows
);
criterion_main!(interval_benches);
