pub trait PolyTFracGCDRing {
// Required methods
fn power_decomposition<P>(poly_ring: P, poly: &El<P>) -> Vec<(El<P>, usize)>
where P: RingStore + Copy,
P::Type: PolyRing + DivisibilityRing,
<P::Type as RingExtension>::BaseRing: RingStore<Type = Self>;
fn gcd<P>(poly_ring: P, lhs: &El<P>, rhs: &El<P>) -> El<P>
where P: RingStore + Copy,
P::Type: PolyRing + DivisibilityRing,
<P::Type as RingExtension>::BaseRing: RingStore<Type = Self>;
// Provided methods
fn squarefree_part<P>(poly_ring: P, poly: &El<P>) -> El<P>
where P: RingStore + Copy,
P::Type: PolyRing + DivisibilityRing,
<P::Type as RingExtension>::BaseRing: RingStore<Type = Self> { ... }
fn power_decomposition_with_controller<P, Controller>(
poly_ring: P,
poly: &El<P>,
_: Controller,
) -> Vec<(El<P>, usize)>
where P: RingStore + Copy,
P::Type: PolyRing + DivisibilityRing,
<P::Type as RingExtension>::BaseRing: RingStore<Type = Self>,
Controller: ComputationController { ... }
fn gcd_with_controller<P, Controller>(
poly_ring: P,
lhs: &El<P>,
rhs: &El<P>,
_: Controller,
) -> El<P>
where P: RingStore + Copy,
P::Type: PolyRing + DivisibilityRing,
<P::Type as RingExtension>::BaseRing: RingStore<Type = Self>,
Controller: ComputationController { ... }
}
Expand description
Trait for domain R
for which there is an efficient way of computing the gcd
of univariate polynomials over TFrac(R)
, where TFrac(R)
is the total ring
of fractions.
However, computations in TFrac(R)
are avoided by most implementations due to
performance reasons, and both inputs and outputs are polynomials over R
. Despite
this, the gcd is the gcd over TFrac(R)
and not R
(the gcd over R
is often not
even defined, since R
does not have to be UFD).
§Example
let ZZX = DensePolyRing::new(StaticRing::<i64>::RING, "X");
let [f, g, expected] = ZZX.with_wrapped_indeterminate(|X| [X.pow_ref(2) - 2 * X + 1, X.pow_ref(2) - 1, X - 1]);
assert_el_eq!(&ZZX, expected, <_ as PolyTFracGCDRing>::gcd(&ZZX, &f, &g));
§Implementation notes
Efficient implementations for polynomial gcds are often quite complicated, since the standard
euclidean algorithm is only efficient over finite fields, where no coefficient explosion happens.
The general idea for other rings/fields is to reduce it to the finite case, by considering the
situation modulo a finite-index ideal. The requirements for this approach are defined by the
trait PolyGCDLocallyDomain
, and there is a blanket impl R: PolyTFracGCDRing where R: PolyGCDLocallyDomain
.
Note that this blanket impl used crate::specialization::FiniteRingSpecializable
to use the standard
algorithm whenever the corresponding ring is actually finite. In other words, despite the fact that the blanket
implementation for PolyGCDLocallyDomain
s also applies to finite fields, the local implementation is not
actually used in these cases.
Required Methods§
Sourcefn power_decomposition<P>(poly_ring: P, poly: &El<P>) -> Vec<(El<P>, usize)>where
P: RingStore + Copy,
P::Type: PolyRing + DivisibilityRing,
<P::Type as RingExtension>::BaseRing: RingStore<Type = Self>,
fn power_decomposition<P>(poly_ring: P, poly: &El<P>) -> Vec<(El<P>, usize)>where
P: RingStore + Copy,
P::Type: PolyRing + DivisibilityRing,
<P::Type as RingExtension>::BaseRing: RingStore<Type = Self>,
Compute square-free polynomials f1, f2, ...
such that a f = f1 f2^2 f3^3 ...
for some non-zero-divisor a
of this ring. They are returned as tuples (fi, i)
where deg(fi) > 0
.
These values are unique up to multiplication by units. If the base ring is a field,
we impose the additional constraint that all fi
be monic, which makes them unique.
Sourcefn gcd<P>(poly_ring: P, lhs: &El<P>, rhs: &El<P>) -> El<P>where
P: RingStore + Copy,
P::Type: PolyRing + DivisibilityRing,
<P::Type as RingExtension>::BaseRing: RingStore<Type = Self>,
fn gcd<P>(poly_ring: P, lhs: &El<P>, rhs: &El<P>) -> El<P>where
P: RingStore + Copy,
P::Type: PolyRing + DivisibilityRing,
<P::Type as RingExtension>::BaseRing: RingStore<Type = Self>,
Computes the greatest common divisor of two polynomials f, g
over the fraction field,
which is the largest-degree polynomial d
such that d | a f, a g
for some non-zero-divisor
a
of this ring.
This value is unique up to multiplication by units. If the base ring is a field, we impose the additional constraint that it be monic, which makes it unique.
§Example
let ZZX = DensePolyRing::new(StaticRing::<i64>::RING, "X");
let [f, g, expected] = ZZX.with_wrapped_indeterminate(|X| [X.pow_ref(2) - 2 * X + 1, 2 * X.pow_ref(2) - 2, X - 1]);
// note that `expected` is not the gcd over `ZZ[X]` (which would be `2 X - 2`), but `X - 1`, i.e. the (monic) gcd over `QQ[X]`
assert_el_eq!(&ZZX, expected, <_ as PolyTFracGCDRing>::gcd(&ZZX, &f, &g));
// of course, the result does not have to be monic
let [f, g, expected] = ZZX.with_wrapped_indeterminate(|X| [4 * X.pow_ref(2) - 1, 4 * X.pow_ref(2) - 4 * X + 1, - 2 * X + 1]);
assert_el_eq!(&ZZX, expected, <_ as PolyTFracGCDRing>::gcd(&ZZX, &f, &g));
Provided Methods§
Sourcefn squarefree_part<P>(poly_ring: P, poly: &El<P>) -> El<P>where
P: RingStore + Copy,
P::Type: PolyRing + DivisibilityRing,
<P::Type as RingExtension>::BaseRing: RingStore<Type = Self>,
fn squarefree_part<P>(poly_ring: P, poly: &El<P>) -> El<P>where
P: RingStore + Copy,
P::Type: PolyRing + DivisibilityRing,
<P::Type as RingExtension>::BaseRing: RingStore<Type = Self>,
Computes the square-free part of a polynomial f
, which is the largest-degree squarefree
polynomial d
such that d | a f
for some non-zero-divisor a
of this ring.
This value is unique up to multiplication by units. If the base ring is a field, we impose the additional constraint that it be monic, which makes it unique.
§Example
let ZZX = DensePolyRing::new(StaticRing::<i64>::RING, "X");
let [f] = ZZX.with_wrapped_indeterminate(|X| [1 - X.pow_ref(2)]);
assert_el_eq!(&ZZX, &f, <_ as PolyTFracGCDRing>::squarefree_part(&ZZX, &ZZX.mul_ref(&f, &f)));
Sourcefn power_decomposition_with_controller<P, Controller>(
poly_ring: P,
poly: &El<P>,
_: Controller,
) -> Vec<(El<P>, usize)>where
P: RingStore + Copy,
P::Type: PolyRing + DivisibilityRing,
<P::Type as RingExtension>::BaseRing: RingStore<Type = Self>,
Controller: ComputationController,
fn power_decomposition_with_controller<P, Controller>(
poly_ring: P,
poly: &El<P>,
_: Controller,
) -> Vec<(El<P>, usize)>where
P: RingStore + Copy,
P::Type: PolyRing + DivisibilityRing,
<P::Type as RingExtension>::BaseRing: RingStore<Type = Self>,
Controller: ComputationController,
As PolyTFracGCDRing::power_decomposition()
, this writes a polynomial as a product
of powers of square-free polynomials. However, it additionally accepts a ComputationController
to customize the performed computation.
Sourcefn gcd_with_controller<P, Controller>(
poly_ring: P,
lhs: &El<P>,
rhs: &El<P>,
_: Controller,
) -> El<P>where
P: RingStore + Copy,
P::Type: PolyRing + DivisibilityRing,
<P::Type as RingExtension>::BaseRing: RingStore<Type = Self>,
Controller: ComputationController,
fn gcd_with_controller<P, Controller>(
poly_ring: P,
lhs: &El<P>,
rhs: &El<P>,
_: Controller,
) -> El<P>where
P: RingStore + Copy,
P::Type: PolyRing + DivisibilityRing,
<P::Type as RingExtension>::BaseRing: RingStore<Type = Self>,
Controller: ComputationController,
As PolyTFracGCDRing::gcd()
, this computes the gcd of two polynomials.
However, it additionally accepts a ComputationController
to customize
the performed computation.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.