forked from SpectralSequences/sseq
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
1,440 additions
and
293 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
use crate::{constants::BITS_PER_LIMB, limb::Limb, prime::Prime}; | ||
|
||
use super::{limb::LimbMethods, Field, FieldElement}; | ||
|
||
/// A prime field. This is just a wrapper around a prime. | ||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | ||
pub struct Fp<P>(pub(crate) P); | ||
|
||
impl<P: Prime> Field for Fp<P> { | ||
type Characteristic = P; | ||
|
||
fn characteristic(self) -> Self::Characteristic { | ||
self.0 | ||
} | ||
|
||
fn degree(self) -> u32 { | ||
1 | ||
} | ||
|
||
fn zero(self) -> Self::Element { | ||
0 | ||
} | ||
|
||
fn one(self) -> Self::Element { | ||
1 | ||
} | ||
|
||
fn add(self, a: Self::Element, b: Self::Element) -> Self::Element { | ||
self.0.sum(a, b) | ||
} | ||
|
||
fn mul(self, a: Self::Element, b: Self::Element) -> Self::Element { | ||
self.0.product(a, b) | ||
} | ||
|
||
fn inv(self, a: Self::Element) -> Option<Self::Element> { | ||
if a == 0 { | ||
None | ||
} else { | ||
// By Fermat's little theorem, `a^(p-1) = 1`. Therefore, `a^(-1) = a^(p-2)`. | ||
Some(self.0.pow_mod(a, self.0.as_u32() - 2)) | ||
} | ||
} | ||
|
||
fn neg(self, a: Self::Element) -> Self::Element { | ||
if a > 0 { | ||
self.0.as_u32() - a | ||
} else { | ||
0 | ||
} | ||
} | ||
|
||
fn frobenius(self, a: Self::Element) -> Self::Element { | ||
a | ||
} | ||
} | ||
|
||
impl<P: Prime> LimbMethods for Fp<P> { | ||
type Element = u32; | ||
|
||
fn encode(self, element: Self::Element) -> Limb { | ||
element as Limb | ||
} | ||
|
||
fn decode(self, element: Limb) -> Self::Element { | ||
(element % self.0.as_u32() as Limb) as u32 | ||
} | ||
|
||
fn bit_length(self) -> usize { | ||
let p = self.characteristic().as_u32() as u64; | ||
match p { | ||
2 => 1, | ||
_ => (BITS_PER_LIMB as u32 - (p * (p - 1)).leading_zeros()) as usize, | ||
} | ||
} | ||
|
||
fn fma_limb(self, limb_a: Limb, limb_b: Limb, coeff: Self::Element) -> Limb { | ||
if self.characteristic() == 2 { | ||
limb_a ^ (coeff as Limb * limb_b) | ||
} else { | ||
limb_a + (coeff as Limb) * limb_b | ||
} | ||
} | ||
|
||
/// Contributed by Robert Burklund. | ||
fn reduce(self, limb: Limb) -> Limb { | ||
match self.characteristic().as_u32() { | ||
2 => limb, | ||
3 => { | ||
// Set top bit to 1 in every limb | ||
const TOP_BIT: Limb = (!0 / 7) << (2 - BITS_PER_LIMB % 3); | ||
let mut limb_2 = ((limb & TOP_BIT) >> 2) + (limb & (!TOP_BIT)); | ||
let mut limb_3s = limb_2 & (limb_2 >> 1); | ||
limb_3s |= limb_3s << 1; | ||
limb_2 ^= limb_3s; | ||
limb_2 | ||
} | ||
5 => { | ||
// Set bottom bit to 1 in every limb | ||
const BOTTOM_BIT: Limb = (!0 / 31) >> (BITS_PER_LIMB % 5); | ||
const BOTTOM_TWO_BITS: Limb = BOTTOM_BIT | (BOTTOM_BIT << 1); | ||
const BOTTOM_THREE_BITS: Limb = BOTTOM_BIT | (BOTTOM_TWO_BITS << 1); | ||
let a = (limb >> 2) & BOTTOM_THREE_BITS; | ||
let b = limb & BOTTOM_TWO_BITS; | ||
let m = (BOTTOM_BIT << 3) - a + b; | ||
let mut c = (m >> 3) & BOTTOM_BIT; | ||
c |= c << 1; | ||
let d = m & BOTTOM_THREE_BITS; | ||
d + c - BOTTOM_TWO_BITS | ||
} | ||
_ => self.pack(self.unpack(limb)), | ||
} | ||
} | ||
} | ||
|
||
impl<P> std::ops::Deref for Fp<P> { | ||
type Target = P; | ||
|
||
fn deref(&self) -> &Self::Target { | ||
&self.0 | ||
} | ||
} | ||
|
||
impl FieldElement for u32 { | ||
fn is_zero(&self) -> bool { | ||
*self == 0 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
use dashmap::DashMap as HashMap; | ||
use once_cell::sync::Lazy; | ||
|
||
use crate::{ | ||
limb::Limb, | ||
matrix::Matrix, | ||
prime::{Prime, ValidPrime}, | ||
vector::inner::FqVectorP, | ||
}; | ||
|
||
use super::{limb::LimbMethods, Field, FieldElement, Fp}; | ||
|
||
static MULT_MATRICES: Lazy<HashMap<(ValidPrime, u32), Matrix>> = Lazy::new(HashMap::new); | ||
static FROB_MATRICES: Lazy<HashMap<(ValidPrime, u32), Matrix>> = Lazy::new(HashMap::new); | ||
|
||
/// A field of order `q = p^d`, where `q >= 2^16` and `d > 1`. Fields of that size are too large to | ||
/// cache their Zech logarithms, so we represent their elements as polynomials over the prime field. | ||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | ||
pub struct LargeFq<P> { | ||
p: P, | ||
d: u32, | ||
} | ||
|
||
impl<P: Prime> Field for LargeFq<P> { | ||
type Characteristic = P; | ||
|
||
fn characteristic(self) -> Self::Characteristic { | ||
self.p | ||
} | ||
|
||
fn degree(self) -> u32 { | ||
self.d | ||
} | ||
|
||
fn zero(self) -> Self::Element { | ||
LargeFqElement(FqVectorP::new(Fp(self.p), self.d as usize)) | ||
} | ||
|
||
fn one(self) -> Self::Element { | ||
todo!() | ||
} | ||
|
||
fn add(self, a: Self::Element, b: Self::Element) -> Self::Element { | ||
todo!() | ||
} | ||
|
||
fn mul(self, a: Self::Element, b: Self::Element) -> Self::Element { | ||
todo!() | ||
} | ||
|
||
fn neg(self, a: Self::Element) -> Self::Element { | ||
todo!() | ||
} | ||
|
||
fn inv(self, a: Self::Element) -> Option<Self::Element> { | ||
todo!() | ||
} | ||
|
||
fn frobenius(self, a: Self::Element) -> Self::Element { | ||
todo!() | ||
} | ||
} | ||
|
||
impl<P: Prime> LimbMethods for LargeFq<P> { | ||
type Element = LargeFqElement<P>; | ||
|
||
fn encode(self, element: Self::Element) -> Limb { | ||
todo!() | ||
} | ||
|
||
fn decode(self, element: Limb) -> Self::Element { | ||
todo!() | ||
} | ||
|
||
fn bit_length(self) -> usize { | ||
todo!() | ||
} | ||
|
||
fn fma_limb(self, limb_a: Limb, limb_b: Limb, coeff: Self::Element) -> Limb { | ||
todo!() | ||
} | ||
|
||
fn reduce(self, limb: Limb) -> Limb { | ||
limb | ||
} | ||
} | ||
|
||
/// A field element as a polynomial over the prime field. This is used when the order of the | ||
/// field is large, since otherwise caching Zech logarithms uses too much memory. | ||
/// | ||
/// This is backed by an `FpVectorP` consisting of the coefficients of the polynomial. | ||
#[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
pub struct LargeFqElement<P: Prime>(pub(super) FqVectorP<Fp<P>>); | ||
|
||
impl<P: Prime> FieldElement for LargeFqElement<P> { | ||
fn is_zero(&self) -> bool { | ||
self.0.is_zero() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.