Skip to main content

Form

Struct Form 

Source
pub struct Form {
    pub a: BigInt,
    pub b: BigInt,
    pub c: BigInt,
}
Expand description

A binary quadratic form $f = ax^2 + bxy + cy^2$ over an imaginary quadratic field.

Forms are elements of the class group $\text{Cl}(D)$ of a negative fundamental discriminant $D = b^2 - 4ac < 0$. The group law is composition, and the identity element is the principal form $(1, 1, (1-D)/4)$.

All arithmetic operations (composition, squaring, exponentiation) produce reduced forms, meaning:

  • $-a < b \le a$
  • $a \le c$
  • if $a = c$ then $b \ge 0$

Fields§

§a: BigInt

The leading coefficient $a > 0$.

§b: BigInt

The cross-term coefficient $b$ (satisfies $-a < b \le a$ when reduced).

§c: BigInt

The constant coefficient $c > 0$ (satisfies $c \ge a$ when reduced).

Implementations§

Source§

impl Form

Source

pub fn new(a: BigInt, b: BigInt, c: BigInt) -> Self

Creates a new form $(a, b, c)$ without any validation or reduction.

Prefer Form::from_abd or Form::generator when constructing from external data, as they validate the discriminant identity.

Source

pub fn identity(d: &BigInt) -> Self

Returns the principal identity element $(1, 1, (1 - D) / 4)$ for discriminant $D$.

The identity satisfies $e \circ f = f$ for any form $f$ in the same class group. Requires $D \equiv 3 \pmod 4$ (standard for imaginary quadratic fields with fundamental discriminant).

Source

pub fn from_abd(a: &BigInt, b: &BigInt, d: &BigInt) -> Option<Self>

Constructs a form $(a, b, c)$ from $a$, $b$, and discriminant $D$, computing $c = (b^2 - D) / (4a)$ and verifying exact divisibility.

Returns None if:

  • a is zero (degenerate form)
  • $(b^2 - D)$ is not exactly divisible by $4a$
Source

pub fn generator(d: &BigInt) -> Option<Self>

Returns the canonical generator form $(2, 1, (1 - D) / 8)$.

Valid for prime discriminants $D = -p$ where $p \equiv 7 \pmod 8$. In this case $2$ splits in $\mathbb{Q}(\sqrt{D})$ and the form $(2, 1, \cdot)$ generates a subgroup of the class group of order $\text{ord}(2)$ in $\text{Cl}(D)$.

Returns None if $(1 - D)$ is not divisible by 8, i.e. $D$ is not a valid prime discriminant of the required form.

Source

pub fn is_reduced(&self) -> bool

Returns true if the form is in reduced normal form.

A form $(a, b, c)$ is reduced if and only if:

  • $a > 0$ and $c > 0$
  • $-a < b \le a$ (normalization condition)
  • $a \le c$ (minimality condition)
  • if $a = c$, then $b \ge 0$ (uniqueness condition)
Source

pub fn reduce(&mut self, d: &BigInt)

Reduces this form in place using the Euclidean-style Gauss reduction algorithm.

After reduction the form satisfies the standard reduced form conditions (see Form::is_reduced). Every form class has a unique reduced representative.

§Algorithm

Iterates two steps until the form is reduced:

  1. Normalize $b$: compute $s = \lfloor (a - b) / 2a \rfloor$, then $b’ = b + 2as$, $c’ = (b’^2 - D) / 4a$.
  2. Minimize $a$: if $a > c’$, swap and negate — set $(a, b, c) = (c’, -b’, a)$ — and loop.

Terminates because the $a$-coefficient strictly decreases each swap.

Source

pub fn nudupl(&self, d: &BigInt, l: &BigInt) -> Form

Shanks’ NUDUPL algorithm — fast squaring of a binary quadratic form.

Computes $f^2 = f \circ f$ in the class group without full reduction of intermediate results, using a partial Euclidean step controlled by threshold l.

§Algorithm (Shanks, 1989 — Cohen §5.4.2)

Given form $(a_1, b_1, c_1)$ and threshold $L$:

  1. Compute $s = \gcd(b_1, a_1)$ via extended GCD and co-factor $k = -xc_1$.
  2. If $s > 1$: divide $a_1$ by $s$, multiply $c_1$ by $s$.
  3. Reduce $k \pmod{a_1}$.
  4. If $a_1 < L$: use direct multiplication (no partial reduction).
  5. Otherwise: run partial XGCD on $(a_1, k)$ stopping at $L$, then compute the new $(a, b, c)$ from the Bézout coefficients (co2, co1) and remainders (r2, r1).
§Parameters
  • d: The negative fundamental discriminant.
  • l: The Shanks threshold $L = \lfloor |D|^{1/4} \rfloor$.
§Returns

A (possibly unreduced) form. Callers must call Form::reduce to obtain the canonical representative. Use Form::square for the combined squaring+reduction.

Source

pub fn nucomp(&self, other: &Form, d: &BigInt, l: &BigInt) -> Form

Shanks’ NUCOMP algorithm — fast composition of two binary quadratic forms.

Computes $f_1 \circ f_2$ in the class group using a partial Euclidean reduction step, keeping intermediate coefficients bounded by threshold l.

§Algorithm (Shanks, 1989 — Cohen §5.4.1)

Given forms $f_1 = (a_1, b_1, c_1)$ and $f_2 = (a_2, b_2, c_2)$ with $a_1 \le a_2$:

  1. Compute $ss = (b_1 + b_2)/2$, $m = (b_1 - b_2)/2$.
  2. Compute $sp = \gcd(a_2 \bmod a_1, a_1)$ via extended GCD.
  3. If $sp = 1$: set $k = m \cdot v_1 \bmod a_1$.
  4. If $sp > 1$: reduce through a second extended GCD of $ss$ and $sp$, divide $a_1, a_2$ by $s = \gcd(ss, sp)$ and scale $c_2$.
  5. Apply partial XGCD or direct multiplication depending on $a_1$ vs $L$.
§Parameters
  • other: The second form $f_2$ to compose with.
  • d: The negative fundamental discriminant.
  • l: The Shanks threshold $L = \lfloor |D|^{1/4} \rfloor$.
§Returns

A (possibly unreduced) form. Use Form::compose for the combined compose+reduction.

Source

pub fn fast_pow(&self, exp: &BigUint, d: &BigInt, l: &BigInt) -> Form

Fast binary exponentiation using NUDUPL and NUCOMP with threshold-based reduction.

Computes $f^n$ using the standard left-to-right binary method:

  • Start with $\text{result} = f$ (from the leading bit of $n$).
  • For each remaining bit $i$ from high to low:
    • Square: $\text{result} \leftarrow \text{NUDUPL}(\text{result})$
    • If bit $i$ is set: compose $\text{result} \leftarrow \text{NUCOMP}(\text{result}, f)$
    • Opportunistically reduce when result.a.bits() > |D|.bits() / 2 to prevent coefficient blowup between full reductions.
  • Final full Gauss reduction before return.

Returns the identity form for exp = 0.

§Parameters
  • exp: Non-negative exponent as BigUint.
  • d: The negative fundamental discriminant.
  • l: The Shanks threshold $L = \lfloor |D|^{1/4} \rfloor$.
Source

pub fn pow(&self, exp: &BigUint, d: &BigInt) -> Self

Raises this form to the power of exp using Form::fast_pow.

Computes the Shanks threshold $L = \lfloor |D|^{1/4} \rfloor$ internally. Returns the identity form when exp = 0.

Source

pub fn compose(&self, other: &Form, d_disc: &BigInt) -> Form

Composes this form with other and returns the reduced result.

This is the primary group operation $f_1 \circ f_2$ of the class group $\text{Cl}(D)$. Internally calls Form::nucomp followed by Form::reduce.

Source

pub fn square(&self, d_disc: &BigInt) -> Form

Squares this form and returns the reduced result.

Equivalent to self.compose(self, d_disc) but uses the faster Form::nudupl specialization for self-composition.

Trait Implementations§

Source§

impl Clone for Form

Source§

fn clone(&self) -> Form

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Form

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Eq for Form

Source§

impl Hash for Form

Source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl PartialEq for Form

Source§

fn eq(&self, other: &Form) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for Form

Auto Trait Implementations§

§

impl Freeze for Form

§

impl RefUnwindSafe for Form

§

impl Send for Form

§

impl Sync for Form

§

impl Unpin for Form

§

impl UnsafeUnpin for Form

§

impl UnwindSafe for Form

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.