Skip to main content

p3_field/
subfield.rs

1//! Small subfields that a kernel can compute inside before lifting its result.
2
3use crate::{Algebra, Field};
4
5/// A field containing a copy of the small field `S`.
6///
7/// A kernel whose inputs all lie in `S` can do its arithmetic there and lift only the result.
8/// The [`Algebra`] supertrait embeds `S` and lets its elements act on this field.
9/// This trait answers whether an element lies in that copy of `S`.
10///
11/// # Contract
12///
13/// For every `x: Self`, `s: S` and `values: &[Self]`:
14///
15/// - `Self::from` is an injective ring homomorphism: it sends `S::ONE` to `Self::ONE`, it
16///   commutes with addition and multiplication, and distinct elements of `S` have distinct images.
17/// - `x + s`, `x - s` and `x * s` equal `x + Self::from(s)`, `x - Self::from(s)` and
18///   `x * Self::from(s)`, and so do the assigning forms.
19/// - `x.as_subfield() == Some(s)` holds exactly when `x == Self::from(s)`.
20///   So it returns `None` exactly when `x` is the image of no element of `S`.
21/// - `Self::all_in_subfield(values)` holds exactly when every `v.as_subfield()` is `Some`.
22///   In particular it holds on an empty slice.
23///
24/// Callers narrow values into `S` on the strength of these equalities, so they must hold exactly.
25/// A `Some` for an element outside the subfield would silently compute with a different value.
26pub trait HasSubfield<S: Field>: Field + Algebra<S> {
27    /// The element of `S` whose image this is, or `None` if it lies outside the subfield.
28    #[must_use]
29    fn as_subfield(&self) -> Option<S>;
30
31    /// Whether every element of `values` lies in the subfield.
32    ///
33    /// Equal to `values.iter().all(|v| v.as_subfield().is_some())`, which is what the default
34    /// computes. Override it where a whole slice can be tested without narrowing each element in
35    /// turn.
36    #[must_use]
37    #[inline]
38    fn all_in_subfield(values: &[Self]) -> bool {
39        values.iter().all(|v| v.as_subfield().is_some())
40    }
41}