binius_field/arch/portable/
pairwise_arithmetic.rs

1// Copyright 2024-2025 Irreducible Inc.
2
3use crate::{
4	arch::PairwiseStrategy,
5	arithmetic_traits::{
6		InvertOrZero, MulAlpha, Square, TaggedInvertOrZero, TaggedMul, TaggedMulAlpha,
7		TaggedPackedTransformationFactory, TaggedSquare,
8	},
9	linear_transformation::{FieldLinearTransformation, Transformation},
10	packed::{PackedBinaryField, PackedField},
11};
12
13impl<PT: PackedField> TaggedMul<PairwiseStrategy> for PT {
14	#[inline]
15	fn mul(self, b: Self) -> Self {
16		if PT::WIDTH == 1 {
17			// fallback to be able to benchmark this strategy
18			self * b
19		} else {
20			Self::from_fn(|i| self.get(i) * b.get(i))
21		}
22	}
23}
24
25impl<PT: PackedField> TaggedSquare<PairwiseStrategy> for PT
26where
27	PT::Scalar: Square,
28{
29	#[inline]
30	fn square(self) -> Self {
31		if PT::WIDTH == 1 {
32			// fallback to be able to benchmark this strategy
33			PackedField::square(self)
34		} else {
35			Self::from_fn(|i| Square::square(self.get(i)))
36		}
37	}
38}
39
40impl<PT: PackedField> TaggedInvertOrZero<PairwiseStrategy> for PT
41where
42	PT::Scalar: InvertOrZero,
43{
44	#[inline]
45	fn invert_or_zero(self) -> Self {
46		if PT::WIDTH == 1 {
47			// fallback to be able to benchmark this strategy
48			PackedField::invert_or_zero(self)
49		} else {
50			Self::from_fn(|i| InvertOrZero::invert_or_zero(self.get(i)))
51		}
52	}
53}
54
55impl<PT: PackedField + MulAlpha> TaggedMulAlpha<PairwiseStrategy> for PT
56where
57	PT::Scalar: MulAlpha,
58{
59	#[inline]
60	fn mul_alpha(self) -> Self {
61		if PT::WIDTH == 1 {
62			// fallback to be able to benchmark this strategy
63			MulAlpha::mul_alpha(self)
64		} else {
65			Self::from_fn(|i| MulAlpha::mul_alpha(self.get(i)))
66		}
67	}
68}
69
70/// Per element transformation
71pub struct PairwiseTransformation<I> {
72	inner: I,
73}
74
75impl<I> PairwiseTransformation<I> {
76	pub const fn new(inner: I) -> Self {
77		Self { inner }
78	}
79}
80
81impl<IP, OP, IF, OF, I> Transformation<IP, OP> for PairwiseTransformation<I>
82where
83	IP: PackedField<Scalar = IF>,
84	OP: PackedField<Scalar = OF>,
85	I: Transformation<IF, OF>,
86{
87	fn transform(&self, data: &IP) -> OP {
88		OP::from_fn(|i| self.inner.transform(&data.get(i)))
89	}
90}
91
92impl<IP, OP> TaggedPackedTransformationFactory<PairwiseStrategy, OP> for IP
93where
94	IP: PackedBinaryField,
95	OP: PackedBinaryField,
96{
97	type PackedTransformation<Data: AsRef<[OP::Scalar]> + Sync> =
98		PairwiseTransformation<FieldLinearTransformation<OP::Scalar, Data>>;
99
100	fn make_packed_transformation<Data: AsRef<[OP::Scalar]> + Sync>(
101		transformation: FieldLinearTransformation<OP::Scalar, Data>,
102	) -> Self::PackedTransformation<Data> {
103		PairwiseTransformation::new(transformation)
104	}
105}