FLINT3.7.0-dev
Module · 118 functions

gr_ore_poly.h

#include <flint/gr_ore_poly.h>

This module implements Ore polynomials L=∑iaiDiL = \sum_i a_i D^i with coefficients in a ring RR given by a generic context [Ore1933; BroPet1996]. The multiplication is twisted by an endomorphism σ\sigma of RR and a σ\sigma-derivation δ\delta (an additive map with δ(ab)=σ(a)δ(b)+δ(a)b\delta(ab) = \sigma(a)\delta(b) + \delta(a) b) through the commutation rule

Da=σ(a)D+δ(a),a∈R.D a = \sigma(a) D + \delta(a), \qquad a \in R.

With R=K[x]R = K[x] and σ=id\sigma = \mathrm{id}, δ=d/dx\delta = d/dx, Ore polynomials are linear differential operators; with σ(x)=x+1\sigma(x) = x + 1, δ=0\delta = 0, linear recurrence (shift) operators; and so on for the predefined algebras listed below. The context of an Ore polynomial ring is a gr_ctx_t, so Ore polynomials can be used with the generic functions (gr_mul composes operators) and in other generic structures.

Example#

The program below multiplies differential operators over Q[x]\mathbb{Q}[x], where Dx=xD+1D x = x D + 1, and recurrence operators, where Sx=(x+1)SS x = (x + 1) S. Coefficients are written on the left of the powers of the generator.

Examplegr_ore_poly_operators.cchecked by make checkdoc
#include <flint/flint.h>
#include <flint/gr.h>
#include <flint/gr_poly.h>
#include <flint/gr_ore_poly.h>

int main(void)
{
    gr_ctx_t QQ, QQx, Dx, Sx;
    gr_ore_poly_t L, M, P;

    gr_ctx_init_fmpq(QQ);
    gr_ctx_init_gr_poly(QQx, QQ);           /* base ring Q[x] */

    /* differential operators: D x = x D + 1 */
    gr_ore_poly_ctx_init(Dx, QQx, 0, ORE_ALGEBRA_DERIVATIVE);
    gr_ore_poly_init(L, Dx);
    gr_ore_poly_init(M, Dx);
    gr_ore_poly_init(P, Dx);
    GR_MUST_SUCCEED(gr_ore_poly_set_str(L, "D", Dx));
    GR_MUST_SUCCEED(gr_ore_poly_set_str(M, "x", Dx));
    GR_MUST_SUCCEED(gr_ore_poly_mul(P, L, M, Dx));
    flint_printf("D * x         = "); gr_ore_poly_print(P, Dx); flint_printf("\n");
    GR_MUST_SUCCEED(gr_ore_poly_set_str(L, "x*D^2 + D - x", Dx));
    GR_MUST_SUCCEED(gr_ore_poly_set_str(M, "D + x^2", Dx));
    GR_MUST_SUCCEED(gr_ore_poly_mul(P, L, M, Dx));
    flint_printf("L * M         = "); gr_ore_poly_print(P, Dx); flint_printf("\n");
    gr_ore_poly_clear(L, Dx);
    gr_ore_poly_clear(M, Dx);
    gr_ore_poly_clear(P, Dx);
    gr_ore_poly_ctx_clear(Dx);

    /* recurrence operators: S x = (x + 1) S */
    gr_ore_poly_ctx_init(Sx, QQx, 0, ORE_ALGEBRA_FORWARD_SHIFT);
    GR_MUST_SUCCEED(_gr_ore_poly_ctx_set_gen_name(Sx, "S"));
    gr_ore_poly_init(L, Sx);
    gr_ore_poly_init(P, Sx);
    GR_MUST_SUCCEED(gr_ore_poly_set_str(L, "S - x - 1", Sx));
    GR_MUST_SUCCEED(gr_ore_poly_mul(P, L, L, Sx));
    flint_printf("(S - x - 1)^2 = "); gr_ore_poly_print(P, Sx); flint_printf("\n");
    gr_ore_poly_clear(L, Sx);
    gr_ore_poly_clear(P, Sx);
    gr_ore_poly_ctx_clear(Sx);

    gr_ctx_clear(QQx);
    gr_ctx_clear(QQ);
    return 0;
}
Output
D * x         = 1 + x*D
L * M         = (4*x - x^3) + (-x + 5*x^2)*D + (1 + x^3)*D^2 + x*D^3
(S - x - 1)^2 = (1 + 2*x + x^2) + (-3 - 2*x)*S + S^2

Ore algebras#

The predefined Ore algebra structures, an enumeration with the values below. Except for the commutative and Frobenius algebras, they act on a distinguished generator xx of the base ring, which must currently be a univariate polynomial ring (created with gr_ctx_init_gr_poly); otherwise σ\sigma and δ\delta return GR_UNABLE.

  • ORE_ALGEBRA_CUSTOM: σ\sigma and δ\delta given by a user function (gr_ore_poly_ctx_init_custom).
  • ORE_ALGEBRA_COMMUTATIVE: σ=id\sigma = \mathrm{id}, δ=0\delta = 0; ordinary polynomials in DD.
  • ORE_ALGEBRA_DERIVATIVE: σ=id\sigma = \mathrm{id}, δ=d/dx\delta = d/dx; linear differential operators.
  • ORE_ALGEBRA_EULER_DERIVATIVE: σ=id\sigma = \mathrm{id}, δ=x d/dx\delta = x \, d/dx (the Euler operator θ\theta).
  • ORE_ALGEBRA_FORWARD_SHIFT: σ(a)(x)=a(x+1)\sigma(a)(x) = a(x + 1), δ=0\delta = 0; linear recurrence operators.
  • ORE_ALGEBRA_FORWARD_DIFFERENCE: σ(a)(x)=a(x+1)\sigma(a)(x) = a(x + 1), δ(a)=a(x+1)−a(x)\delta(a) = a(x + 1) - a(x) (the operator Δ\Delta).
  • ORE_ALGEBRA_BACKWARD_SHIFT: σ(a)(x)=a(x−1)\sigma(a)(x) = a(x - 1), δ=0\delta = 0.
  • ORE_ALGEBRA_BACKWARD_DIFFERENCE: σ(a)(x)=a(x−1)\sigma(a)(x) = a(x - 1), δ(a)=a(x)−a(x−1)\delta(a) = a(x) - a(x - 1) (the operator ∇\nabla).
  • ORE_ALGEBRA_Q_SHIFT: σ(a)(x)=a(qx)\sigma(a)(x) = a(qx), δ=0\delta = 0; linear qq-difference operators (gr_ore_poly_ctx_init_q_shift).
  • ORE_ALGEBRA_MAHLER: σ(a)(x)=a(xb)\sigma(a)(x) = a(x^b), δ=0\delta = 0; linear Mahler operators with base bb (gr_ore_poly_ctx_init_mahler).
  • ORE_ALGEBRA_FROBENIUS: σ\sigma the Frobenius automorphism a↦apa \mapsto a^p of a finite field (δ=0\delta = 0), computed with gr_fq_frobenius.

The value ORE_POLY_NUM_ALGEBRAS is the number of algebra types.

Returns a random Ore algebra type, favouring the derivative and the forward shift, for testing.

Types and conventions#

An Ore polynomial: an array coeffs of alloc coefficients in the base ring, of which the first length are used; the coefficient of DiD^i is at index ii. The layout is that of gr_poly_t, so the functions of gr_poly that do not multiply (copying, truncation, addition, scalar operations, and the container functions) can be applied to the coefficient arrays with the base ring context.

The context of an Ore polynomial ring, a gr_ctx_t. Its data (type _gr_ore_poly_ctx_struct, compatible with the context data of gr_poly rings) holds the base ring, a degree limit, the name of the generator (D by default), the algebra type, the function computing σ\sigma and δ\delta, and algebra-specific data (type gr_ore_poly_ore_data_t: the index of the distinguished generator base_var, σ(x)\sigma(x) and qq for qq-shifts, or the Mahler base).

The context data, the base ring, and the algebra-specific data of an Ore polynomial context.

The context argument of the functions is the context of the Ore polynomial ring (not the base ring as in gr_poly). As in gr_poly, Ore polynomials are weakly normalised (a leading coefficient is removed only if it is provably zero, so the length bounds the order plus one over inexact rings), functions returning int return status codes, and the functions with a leading underscore work on coefficient arrays without memory management.

Contexts#

void gr_ore_poly_ctx_init(gr_ore_poly_ctx_t ctx, gr_ctx_t base_ring, slong base_var, const ore_algebra_t which_algebra)
void gr_ctx_init_gr_ore_poly(gr_ctx_t ctx, gr_ctx_t base_ring, slong base_var, const ore_algebra_t which_algebra)

Initialise ctx as the ring of Ore polynomials over base_ring with the predefined algebra which_algebra, acting on the generator with index base_var of the base ring. These are for the algebras without parameters; the qq-shift and Mahler algebras have their own constructors. The two functions are the same.

int gr_ore_poly_ctx_init_mahler(gr_ore_poly_ctx_t ctx, gr_ctx_t base_ring, slong base_var, slong mahler_base)

Initialise ctx for the qq-shift algebra σ(a)(x)=a(qx)\sigma(a)(x) = a(qx) with qq an element of the base ring (GR_UNABLE unless the base ring is a univariate polynomial ring), or the Mahler algebra σ(a)(x)=a(xb)\sigma(a)(x) = a(x^b) with bb = mahler_base (GR_DOMAIN for b=0b = 0).

void gr_ore_poly_ctx_init_custom(gr_ore_poly_ctx_t ctx, gr_ctx_t base_ring, const gr_ore_poly_sigma_delta_t sigma_delta, void * ore_data)

gr_ore_poly_ctx_init_custom initialises ctx with a user-defined algebra: sigma_delta computes σ\sigma and δ\delta (see gr_ore_poly_sigma_delta), and ore_data is a pointer to data for it, which sigma_delta can retrieve with gr_ore_poly_ctx_data_ptr(ctx). The data is not freed by gr_ore_poly_ctx_clear.

Initialise ctx with a random algebra over base_ring, or (the second function) over a random base ring that it initialises in base_ring, for testing.

Clears the context and the algebra data it owns.

int _gr_ore_poly_ctx_set_gen_name(gr_ctx_t ctx, const char * s)
int _gr_ore_poly_ctx_set_gen_names(gr_ctx_t ctx, const char ** s)

Set the name of the generator DD to s (respectively s[0]), and set vec to the generators of the base ring (as constant Ore polynomials) followed by DD.

Context methods. Whether the ring is a ring, the zero ring or thread-safe is inherited from the base ring; commutativity and the absence of zero divisors are currently reported as T_UNKNOWN.

Memory management#

Initialise poly as zero (with space for len coefficients), and clear it.

Return a pointer to the coefficient of DiD^i, and the length.

Swap two Ore polynomials in constant time, and make res a shallow copy of x sharing its coefficients.

Ensure space for len coefficients, set the length without normalising, and remove provably zero leading coefficients, as the gr_poly functions of the same names.

Basic manipulation#

Set res to a copy of src, or to src with the terms of order newlen and higher removed.

Set poly to a constant converted into the base ring. The function gr_ore_poly_set_other accepts an Ore polynomial with the same context (copied), an element of the base ring, an element of the coefficient ring of the base ring when the base ring is a univariate polynomial ring, or an integer or rational number (fmpz and fmpq contexts), each giving a constant; it returns GR_UNABLE for any other ring.

Comparisons, decided coefficientwise in the base ring. The underscore version requires len1≥len2\mathit{len1} \ge \mathit{len2}.

Input and output#

int gr_ore_poly_get_str(char ** res, const gr_ore_poly_t poly, gr_ore_poly_ctx_t ctx)

Write the Ore polynomial as an expression in the generator name of the context, with the coefficients on the left of the powers of DD, to a stream, to a new string (to be freed with flint_free), or to standard output.

int _gr_ore_poly_set_str(gr_ptr res, const char * s, slong len, gr_ore_poly_ctx_t ctx)

Parse an Ore polynomial from an expression in the generator name of the context and the generator names of the base ring; products are evaluated in the Ore algebra, so D*x and x*D differ. The underscore version writes exactly len coefficients (zero-padding) and returns GR_UNABLE if the result is longer; intermediate results may be longer.

Set poly to a random Ore polynomial of length at most len (respectively a random length below 5), for testing.

Action#

The type of a function int f(gr_ptr sigma, gr_ptr delta, gr_srcptr a, gr_ore_poly_ctx_struct * ctx) that sets sigma to σ(a)\sigma(a) and delta to δ(a)\delta(a) for an element aa of the base ring; either output may be NULL, in which case it is not computed.

Compute σ(a)\sigma(a) and δ(a)\delta(a), or one of them, by calling the function stored in the context.

The functions implementing σ\sigma and δ\delta for the predefined algebras, with the signature gr_ore_poly_sigma_delta_t (sigma_delta_unable always returns GR_UNABLE; sigma_delta_compose, used for qq-shifts, composes aa with the stored σ(x)\sigma(x)).

The array of the sigma_delta functions of the predefined algebras, indexed by ore_algebra_t (sigma_delta_unable for ORE_ALGEBRA_CUSTOM).

Set res to the result of applying P to the base ring element f. The first function uses the standard interpretation of P as an operator acting on the base ring (derivative operators differentiate, shift operators shift, etc.). In the second one, the generator DD acts by g↦σ(g) d1+δ(g)g \mapsto \sigma(g) \, d_1 + \delta(g) where d1 is the value D(1)D(1); any d1 defines a valid action.

Conversions#

The following functions convert between expressions of a linear differential or difference operator in different bases, represented as Ore polynomials in different Ore polynomial rings over the same base ring.

Rewrite op, of length len, from ORE_ALGEBRA_EULER_DERIVATIVE to ORE_ALGEBRA_DERIVATIVE (first function), or from ORE_ALGEBRA_DERIVATIVE to ORE_ALGEBRA_EULER_DERIVATIVE (second function). In the latter case the result is multiplied by a power of xx: res=xlen−1⋅op\mathit{res} = x^{\mathit{len}-1} \cdot \mathit{op}. Here ctx is the common base ring and var is the index of the generator xx of ctx on which the derivations act. The output vector res has the same length len as op and must not alias it.

int _gr_ore_poly_shift_convert_difference(gr_ptr res, slong * p, gr_srcptr op, slong len, int to_backward, slong var, gr_ctx_t ctx)

Rewrite op from src_alg to dst_alg, where both are among the builtin shift and difference algebras (corresponding to operators written in terms of the forward and backward shifts SS, S−1S^{-1} and the forward and backward differences S−1S - 1, 1−S−11 - S^{-1}). The result satisfies Sp⋅res=opS^p \cdot \mathit{res} = \mathit{op}. Here ctx is the common base ring and var is the index of the generator of ctx on which SS acts. Conversions that cross between the forward side (SS, S−1S - 1) and the backward side (S−1S^{-1}, 1−S−11 - S^{-1}) currently require a generic univariate polynomial base ring and otherwise return GR_UNABLE. The function returns an error status when the source or destination algebra is not of the required type. The output vector res has the same length len as op and must not alias it.

The second function is the specialisation to conversions between ORE_ALGEBRA_FORWARD_DIFFERENCE and ORE_ALGEBRA_BACKWARD_DIFFERENCE, the flag to_backward giving the direction.

Convert op from op_ctx to res_ctx. The meaning of the output parameter p depends on the algebra. For a conversion within the differential family, xp⋅res=opx^p \cdot \mathit{res} = \mathit{op} where xx is the generator of the base ring specified in the source context. For a conversion within the shift/difference family, Sp⋅res=opS^p \cdot \mathit{res} = \mathit{op} (a power of the forward shift SS). No attempt is currently made to minimise pp or its absolute value.

For f=∑nanxnf = \sum_n a_n x^n, the Euler derivative θ=x d/dx\theta = x \, d/dx acts on (an)(a_n) as multiplication by nn and xx acts as the backward shift S−1S^{-1}. The following functions convert between differential and difference operators in a way compatible with this action, mapping x d/dx↦nx \, d/dx \mapsto n and x↦S−1x \mapsto S^{-1}, and inversely.

The two inverse rewritings of the isomorphism between the Euler operator and the backward shift S−1S^{-1}. The common base ring ctx must be a univariate polynomial ring. The caller allocates res to reslen, one more than the largest coefficient degree of op.

Given a differential operator op represented as an element of op_ctx, compute a shift/difference operator res in res_ctx and an integer p such that the above correspondence maps op to Sp⋅resS^p \cdot \mathit{res} (first function); or, conversely, given a shift/difference operator op, compute a differential operator res and p such that the correspondence maps op to xp⋅resx^p \cdot \mathit{res} (second function). The generators of the base rings specified in the source and destination contexts play the role of xx and nn (first function), or nn and xx (second function). No attempt is currently made to minimise pp or its absolute value.

Arithmetic#

int _gr_ore_poly_add(gr_ptr res, gr_srcptr poly1, slong len1, gr_srcptr poly2, slong len2, gr_ore_poly_ctx_t ctx)
int _gr_ore_poly_sub(gr_ptr res, gr_srcptr poly1, slong len1, gr_srcptr poly2, slong len2, gr_ore_poly_ctx_t ctx)

Negation, sum and difference, coefficientwise.

Add or subtract a constant cc. The _other versions accept the same kinds of elements as gr_ore_poly_set_other, including an Ore polynomial with the same context.

Multiply by an integer or rational constant (which commutes with DD), or multiply on the left by xx, that is compute xLx L: an Ore polynomial with the same context is multiplied with gr_ore_poly_mul, and the other kinds of elements accepted by gr_ore_poly_set_other are constants cc with cL=∑i(cai)Dic L = \sum_i (c a_i) D^i.

Set res to the left product DL=∑i(σ(ai)Di+1+δ(ai)Di)D L = \sum_i (\sigma(a_i) D^{i+1} + \delta(a_i) D^i). The underscore version requires len≥1\mathit{len} \ge 1 and writes len+1\mathit{len} + 1 coefficients.

int _gr_ore_poly_mul(gr_ptr res, gr_srcptr poly1, slong len1, gr_srcptr poly2, slong len2, gr_ore_poly_ctx_t ctx)

Set res to the product L1L2L_1 L_2 in the Ore algebra, computed as ∑iai(DiL2)\sum_i a_i (D^i L_2) with the powers DiL2D^i L_2 obtained by repeated left multiplication by DD: O(len1⋅len2)O(\mathit{len1} \cdot \mathit{len2}) applications of σ\sigma and δ\delta and multiplications in the base ring. The underscore version requires positive lengths, writes len1+len2−1\mathit{len1} + \mathit{len2} - 1 coefficients and does not allow aliasing.

Compute the right Euclidean division U=QV+RU = QV + R with ord⁡R<ord⁡V\operatorname{ord} R < \operatorname{ord} V, which exists and is unique when the leading coefficient of VV and its images under the powers of σ\sigma are invertible (over a field with σ\sigma injective, for instance). Each step divides the leading coefficient of the current remainder by σk(lc⁡(V))\sigma^k(\operatorname{lc}(V)) and subtracts cDkVc D^k V, for kk from ord⁡U−ord⁡V\operatorname{ord} U - \operatorname{ord} V down to 0; the eliminated coefficients of RR are then set to exact zeros (in inexact rings they would otherwise only be approximately zero). The non-underscore functions return GR_DOMAIN if V=0V = 0; the underscore version requires lenU≥lenV≥1\mathit{lenU} \ge \mathit{lenV} \ge 1 and writes lenU−lenV+1\mathit{lenU} - \mathit{lenV} + 1 coefficients of QQ and lenU\mathit{lenU} of RR. (In FLINT 3.6 and earlier the last step, k=0k = 0, was skipped, so that for example D2+D+1D^2 + D + 1 divided by DD gave Q=DQ = D and R=1+DR = 1 + D.)

References#

Cite this page

The FLINT team, “gr_ore_poly.h (module overview),” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/gr_ore_poly/index.html (generated 2026-11-02).