Skip to main content

binius_math/
line.rs

1// Copyright 2024-2025 Irreducible Inc.
2
3use binius_field::{PackedField, field::FieldOps};
4
5/// Extrapolates a line through two points.
6///
7/// Given two points (0, x0) and (1, x1), this function evaluates the line through these
8/// points at parameter z using the formula: x0 + (x1 - x0) * z
9///
10/// # Properties
11/// - When z = 0, returns x0
12/// - When z = 1, returns x1
13/// - The function is linear in z
14#[inline]
15pub fn extrapolate_line<F: FieldOps>(x0: F, x1: F, z: F) -> F {
16	x0.clone() + (x1 - x0) * z
17}
18
19/// Extrapolates lines through a pair of packed fields at a packed vector of points.
20///
21/// Given two points (0, x0) and (1, x1), this function evaluates the line through these
22/// points at parameter z using the formula: x0 + (x1 - x0) * z
23///
24/// # Properties
25/// - When z = 0, returns x0
26/// - When z = 1, returns x1
27/// - The function is linear in z
28/// - Operates on packed field elements for SIMD efficiency
29///
30/// # Arguments
31/// * `x0` - The y-coordinate at z = 0
32/// * `x1` - The y-coordinate at z = 1
33/// * `z` - The evaluation point(s)
34///
35/// # Returns
36/// The interpolated/extrapolated value(s) at point(s) z
37#[inline]
38pub fn extrapolate_line_packed<P>(x0: P, x1: P, z: P) -> P
39where
40	P: PackedField,
41{
42	x0 + (x1 - x0) * z
43}
44
45#[cfg(test)]
46mod tests {
47	use binius_field::{Field, Random, field::FieldOps};
48	use rand::prelude::*;
49
50	use super::*;
51	use crate::test_utils::{B128, Packed128b};
52
53	type P = Packed128b;
54	type F = B128;
55
56	#[test]
57	fn test_extrapolate_line_packed_boundary_values() {
58		let mut rng = StdRng::seed_from_u64(0);
59
60		// Test with scalar field
61		let x0 = F::random(&mut rng);
62		let x1 = F::random(&mut rng);
63		let zero = F::ZERO;
64		let one = F::ONE;
65
66		// When z = 0, should return x0
67		assert_eq!(extrapolate_line_packed(x0, x1, zero), x0);
68
69		// When z = 1, should return x1
70		assert_eq!(extrapolate_line_packed(x0, x1, one), x1);
71
72		// Test with packed field
73		let x0_packed = P::random(&mut rng);
74		let x1_packed = P::random(&mut rng);
75		let zero_packed = P::zero();
76		let one_packed = P::one();
77
78		// When z = 0, should return x0
79		assert_eq!(extrapolate_line_packed(x0_packed, x1_packed, zero_packed), x0_packed);
80
81		// When z = 1, should return x1
82		assert_eq!(extrapolate_line_packed(x0_packed, x1_packed, one_packed), x1_packed);
83	}
84
85	#[test]
86	fn test_extrapolate_line_packed_linearity() {
87		let mut rng = StdRng::seed_from_u64(0);
88
89		// Generate random points and values
90		let x0 = F::random(&mut rng);
91		let x1 = F::random(&mut rng);
92		let z0 = F::random(&mut rng);
93		let z1 = F::random(&mut rng);
94		let alpha = F::random(&mut rng);
95
96		// Test linearity property: f(αz0 + (1-α)z1) = αf(z0) + (1-α)f(z1)
97		let z_combined = alpha * z0 + (F::ONE - alpha) * z1;
98
99		let f_z0 = extrapolate_line_packed(x0, x1, z0);
100		let f_z1 = extrapolate_line_packed(x0, x1, z1);
101		let f_combined = extrapolate_line_packed(x0, x1, z_combined);
102
103		let expected = alpha * f_z0 + (F::ONE - alpha) * f_z1;
104
105		assert_eq!(f_combined, expected);
106	}
107}