diff --git a/CMakeLists.txt b/CMakeLists.txt index 916aea9cbd..13bb1dd6ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -261,7 +261,8 @@ set(_BUILD_DIRS acb_theta dirichlet bernoulli hypgeom gr gr_generic gr_vec gr_mat - gr_poly gr_mpoly gr_series gr_special + gr_poly gr_mpoly gr_ore_poly gr_series + gr_special calcium fmpz_mpoly_q diff --git a/Makefile.in b/Makefile.in index 5b153a1a16..5c6258a978 100644 --- a/Makefile.in +++ b/Makefile.in @@ -210,7 +210,8 @@ HEADER_DIRS := \ acb_theta dirichlet bernoulli hypgeom \ \ gr gr_generic gr_vec gr_mat \ - gr_poly gr_mpoly gr_series gr_special \ + gr_poly gr_mpoly gr_ore_poly gr_series \ + gr_special \ \ calcium \ fmpz_mpoly_q \ diff --git a/doc/source/gr_domains.rst b/doc/source/gr_domains.rst index 45b371a878..d6677506da 100644 --- a/doc/source/gr_domains.rst +++ b/doc/source/gr_domains.rst @@ -304,6 +304,10 @@ Polynomial rings over the given *base_ring*. Elements have type :type:`gr_poly_struct`. +.. function:: void gr_ctx_init_random_poly(gr_ctx_t ctx, flint_rand_t state) + + Initializes *ctx* to a random univariate polynomial ring. + .. function:: void gr_ctx_init_fmpz_mpoly(gr_ctx_t ctx, slong nvars, const ordering_t ord) Initializes *ctx* to a ring of sparsely represented multivariate @@ -318,12 +322,31 @@ Polynomial rings with monomial ordering *ord*. Elements have type :type:`gr_mpoly_struct`. +.. function:: void gr_ctx_init_random_mpoly(gr_ctx_t ctx, flint_rand_t state) + + Initializes *ctx* to a random multivariate polynomial ring. + +Ore polynomials +------------------------------------------------------------------------------- + +.. function:: 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) + + Initializes *ctx* to a ring of densely represented Ore polynomials over the + given *base_ring*, with the choice of Ore algebra structure given by + *which_algebra*. The Ore algebra structure may refer to a distinguished + generator of *base_ring*; this will be the generator of index *base_var*. + Elements have type :type:`gr_ore_poly_struct`. + Power series ------------------------------------------------------------------------------- See :func:`gr_series_ctx_init` and :func:`gr_series_mod_ctx_init` in :ref:`gr-series`. +.. function:: void gr_ctx_init_random_series(gr_ctx_t ctx, flint_rand_t state) + + Initializes *ctx* to a random power series ring. + Fraction fields ------------------------------------------------------------------------------- diff --git a/doc/source/gr_ore_poly.rst b/doc/source/gr_ore_poly.rst new file mode 100644 index 0000000000..c94cd27e55 --- /dev/null +++ b/doc/source/gr_ore_poly.rst @@ -0,0 +1,312 @@ +.. _gr-ore-poly: + +**gr_ore_poly.h** -- dense univariate Ore polynomials over generic rings +=============================================================================== + +.. note:: + + This module is under construction. Functionality is currently limited to + memory management, additive arithmetic, and multiplication from the left + by an element of the base ring. + +A :type:`gr_ore_poly_t` represents a univariate Ore polynomial `L \in R[D]` +implemented as a dense array of coefficients in a generic ring *R*. +The choice of Ore algebra structure (e.g. with `D` being the standard +derivative or Euler derivative) is stored in the context object +:type:`gr_ore_poly_ctx_t`. + +Most functions are provided in two versions: an underscore method which +operates directly on pre-allocated arrays of coefficients and generally +has some restrictions (often requiring the lengths to be nonzero +and not supporting aliasing of the input and output arrays), +and a non-underscore method which performs automatic memory +management and handles degenerate cases. + +Ore algebra types +-------------------------------------------------------------------------------- + +.. type:: ore_algebra_t + + Represents one of the following supported Ore algebra types: + + .. macro:: ORE_ALGEBRA_CUSTOM + + Custom Ore polynomials. + + .. macro:: ORE_ALGEBRA_COMMUTATIVE + + Standard polynomials. + + .. macro:: ORE_ALGEBRA_DERIVATIVE + + Linear differential operators in the standard derivative. + + The endomorphism `\sigma` is the identity, and the `\sigma`-derivation + `\delta` is the derivative `\frac{d}{dx}` with respect to a generator + `x` of the base ring. + + .. macro:: ORE_ALGEBRA_EULER_DERIVATIVE + + Linear differential operators in the Euler derivative. + + The endomorphism `\sigma` is the identity, and the `\sigma`-derivation + `\delta` is the Euler derivative `x\cdot\frac{d}{dx}` with respect to a + generator `x` of the base ring. + + .. macro:: ORE_ALGEBRA_FORWARD_SHIFT + + Linear difference operators in the standard forward shift. + + The endomorphism `\sigma` is the shift `x \mapsto x + 1` with respect + to a generator `x` of the base ring, and the `\sigma`-derivation + `\delta` is the zero map. + + .. macro:: ORE_ALGEBRA_FORWARD_DIFFERENCE + + Linear difference operator in the forward finite difference operator. + + The endomorphism `\sigma` is the shift `x \mapsto x + 1` with respect + to a generator `x` of the base ring, and the `\sigma`-derivation + `\delta` maps `x \mapsto 1`. + + .. macro:: ORE_ALGEBRA_BACKWARD_SHIFT + + Linear difference operators in the standard backward shift. + + .. macro:: ORE_ALGEBRA_BACKWARD_DIFFERENCE + + Linear difference operator in the backward finite difference operator. + + .. macro:: ORE_ALGEBRA_Q_SHIFT + + Linear q-difference operators. + + .. macro:: ORE_ALGEBRA_MAHLER + + Linear Mahler operators. + + .. macro:: ORE_ALGEBRA_FROBENIUS + + Ore polynomials over a field twisted by the Frobenius endomorphism. + +.. function:: ore_algebra_t ore_algebra_randtest(flint_rand_t state) + + Return a random Ore algebra type. + +Type compatibility +------------------------------------------------------------------------------- + +The ``gr_ore_poly`` type has the same data layout as ``gr_poly``. +Methods of ``gr_poly`` can therefore be used for linear and container +operations on a ``gr_ore_poly``, given that one is careful about providing +the right context object. + +Weak normalization +------------------------------------------------------------------------------- + +A :type:`gr_ore_poly_t` is always normalised by removing leading zeros. +For rings without decidable equality (e.g. rings with inexact +representation), only coefficients that are provably zero will be +removed, and there can thus be spurious leading zeros in the +internal representation. +Methods that depend on knowing the exact degree of a polynomial +will act appropriately, typically by returning ``GR_UNABLE`` +when it is unknown whether the leading stored coefficient is nonzero. + +Types, macros and constants +------------------------------------------------------------------------------- + +.. type:: gr_ore_poly_struct + +.. type:: gr_ore_poly_t + + Contains a pointer to an array of coefficients (``coeffs``), the used + length (``length``), and the allocated size of the array (``alloc``). + + A ``gr_ore_poly_t`` is defined as an array of length one of type + ``gr_ore_poly_struct``, permitting a ``gr_ore_poly_t`` to + be passed by reference. + +Context object methods +------------------------------------------------------------------------------- + +.. function:: 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) + + Initializes ``ctx`` to a ring of densely represented Ore polynomials over + the given ``base_ring``, with the choice of Ore algebra structure given by + ``which_algebra``. The Ore algebra structure may refer to a distinguished + generator of ``base_ring``; this will be the generator of index + ``base_var``. + + This function can be used with all Ore algebra types for which no more + specific initialization function is listed below. + +.. function:: int gr_ore_poly_ctx_init_q_shift(gr_ore_poly_ctx_t ctx, gr_ctx_t base_ring, slong base_var, gr_srcptr q) + int gr_ore_poly_ctx_init_q_difference(gr_ore_poly_ctx_t ctx, gr_ctx_t base_ring, slong base_var, gr_srcptr q) + int gr_ore_poly_ctx_init_mahler(gr_ore_poly_ctx_t ctx, gr_ctx_t base_ring, slong base_var, long mahler_base) + + Like :func:`gr_ore_poly_ctx_init` for predefined Ore polynomial types where + `\sigma` and `\delta` depend on parameters. + +.. function:: void * gr_ore_poly_ctx_data_ptr(gr_ore_poly_ctx_t ctx) + +.. function:: 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) + + Initializes ``ctx`` to a ring of densely represented Ore polynomials over + the given ``base_ring``, with a custom Ore algebra structure specified by a + pointer ``sigma_delta`` to an implementation of + :func:`gr_ore_poly_sigma_delta`. + The ``ore_data`` argument is accessible to ``sigma_delta`` as + ``gr_ore_poly_ctx_data_ptr(ctx)``. + +.. function:: void gr_ore_poly_ctx_init_randtest(gr_ore_poly_ctx_t ctx, flint_rand_t state, gr_ctx_t base_ring) + + Initializes ``ctx`` with a random Ore algebra structure. + +.. function:: void gr_ore_poly_ctx_init_randtest2(gr_ctx_t base_ring, gr_ore_poly_ctx_t ctx, flint_rand_t state) + + Initializes ``ctx`` with a random Ore algebra structure over a random base + ring. + +.. function:: void gr_ore_poly_ctx_clear(gr_ore_poly_ctx_t ctx) + + Clears the context object ``ctx``. + +The following methods implement parts of the standard interface +for ``gr`` context objects. + +.. function:: 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) + + Sets the name of the generator to the string in ``s``, respectively the + first string in ``s``. + +.. function:: int gr_ore_poly_ctx_write(gr_stream_t out, gr_ore_poly_ctx_t ctx) + truth_t gr_ore_poly_ctx_is_ring(gr_ore_poly_ctx_t ctx) + truth_t gr_ore_poly_ctx_is_zero_ring(gr_ore_poly_ctx_t ctx) + truth_t gr_ore_poly_ctx_is_commutative_ring(gr_ore_poly_ctx_t ctx) + truth_t gr_ore_poly_ctx_is_integral_domain(gr_ore_poly_ctx_t ctx) + truth_t gr_ore_poly_ctx_is_threadsafe(gr_ore_poly_ctx_t ctx) + +Memory management +------------------------------------------------------------------------------- + +.. function:: void gr_ore_poly_init(gr_ore_poly_t poly, gr_ore_poly_ctx_t ctx) + +.. function:: void gr_ore_poly_init2(gr_ore_poly_t poly, slong len, gr_ore_poly_ctx_t ctx) + +.. function:: void gr_ore_poly_clear(gr_ore_poly_t poly, gr_ore_poly_ctx_t ctx) + +.. function:: gr_ptr gr_ore_poly_coeff_ptr(gr_ore_poly_t poly, slong i, gr_ore_poly_ctx_t ctx) + gr_srcptr gr_ore_poly_coeff_srcptr(const gr_ore_poly_t poly, slong i, gr_ore_poly_ctx_t ctx) + +.. function:: slong gr_ore_poly_length(const gr_ore_poly_t poly, gr_ore_poly_ctx_t ctx) + +.. function:: void gr_ore_poly_swap(gr_ore_poly_t poly1, gr_ore_poly_t poly2, gr_ore_poly_ctx_t ctx) + +.. function:: void gr_ore_poly_fit_length(gr_ore_poly_t poly, slong len, gr_ore_poly_ctx_t ctx) + +.. function:: void _gr_ore_poly_set_length(gr_ore_poly_t poly, slong len, gr_ore_poly_ctx_t ctx) + +Basic manipulation +------------------------------------------------------------------------------- + +.. function:: void _gr_ore_poly_normalise(gr_ore_poly_t poly, gr_ore_poly_ctx_t ctx) + +.. function:: int gr_ore_poly_set(gr_ore_poly_t res, const gr_ore_poly_t src, gr_ore_poly_ctx_t ctx) + +.. function:: int gr_ore_poly_truncate(gr_ore_poly_t res, const gr_ore_poly_t poly, slong newlen, gr_ore_poly_ctx_t ctx) + +.. function:: int gr_ore_poly_zero(gr_ore_poly_t poly, gr_ore_poly_ctx_t ctx) + int gr_ore_poly_one(gr_ore_poly_t poly, gr_ore_poly_ctx_t ctx) + int gr_ore_poly_neg_one(gr_ore_poly_t poly, gr_ore_poly_ctx_t ctx) + int gr_ore_poly_gen(gr_ore_poly_t poly, gr_ore_poly_ctx_t ctx) + +.. function:: int gr_ore_poly_write(gr_stream_t out, const gr_ore_poly_t poly, gr_ore_poly_ctx_t ctx) + int _gr_ore_poly_write(gr_stream_t out, gr_srcptr poly, slong n, gr_ore_poly_ctx_t ctx) + int _gr_ore_poly_get_str(char ** res, const gr_ore_poly_t f, gr_ore_poly_ctx_t ctx) + int gr_ore_poly_get_str(char ** res, const gr_ore_poly_t f, gr_ore_poly_ctx_t ctx) + int gr_ore_poly_print(const gr_ore_poly_t poly, gr_ore_poly_ctx_t ctx) + +.. function:: int _gr_ore_poly_set_str(gr_ptr res, const char * s, slong len, gr_ore_poly_ctx_t ctx) + int gr_ore_poly_set_str(gr_ore_poly_t res, const char * s, gr_ore_poly_ctx_t ctx) + + Parse Ore polynomial from an expression string, assuming the name of the + generator is the one set in *ctx*. The underscore method zero-pads the + result if the length of the parsed polynomial is shorter than *len*, + and returns ``GR_UNABLE`` if the length of the parsed polynomial exceeds + *len*. Intermediate terms are allowed to be longer than *len*. + +.. function:: int gr_ore_poly_randtest(gr_ore_poly_t poly, flint_rand_t state, slong len, gr_ore_poly_ctx_t ctx) + +.. function:: truth_t _gr_ore_poly_equal(gr_srcptr poly1, slong len1, gr_srcptr poly2, slong len2, gr_ore_poly_ctx_t ctx) + truth_t gr_ore_poly_equal(const gr_ore_poly_t poly1, const gr_ore_poly_t poly2, gr_ore_poly_ctx_t ctx) + +.. function:: truth_t gr_ore_poly_is_zero(const gr_ore_poly_t poly, gr_ore_poly_ctx_t ctx) + truth_t gr_ore_poly_is_one(const gr_ore_poly_t poly, gr_ore_poly_ctx_t ctx) + truth_t gr_ore_poly_is_gen(const gr_ore_poly_t poly, gr_ore_poly_ctx_t ctx) + +.. function:: int gr_ore_poly_set_si(gr_ore_poly_t poly, slong c, gr_ore_poly_ctx_t ctx) + int gr_ore_poly_set_ui(gr_ore_poly_t poly, ulong c, gr_ore_poly_ctx_t ctx) + int gr_ore_poly_set_fmpz(gr_ore_poly_t poly, const fmpz_t c, gr_ore_poly_ctx_t ctx) + int gr_ore_poly_set_fmpq(gr_ore_poly_t poly, const fmpq_t c, gr_ore_poly_ctx_t ctx) + int gr_ore_poly_set_other(gr_ore_poly_t poly, gr_srcptr x, gr_ctx_t x_ctx, gr_ore_poly_ctx_t ctx) + +Action +------------------------------------------------------------------------------- + +.. function:: int gr_ore_poly_sigma(gr_ptr res, gr_srcptr a, gr_ore_poly_ctx_t ctx) + int gr_ore_poly_delta(gr_ptr res, gr_srcptr a, gr_ore_poly_ctx_t ctx) + int gr_ore_poly_sigma_delta(gr_ptr sigma, gr_ptr delta, gr_srcptr a, gr_ore_poly_ctx_t ctx) + + Compute *σ(a)*, *δ(a)*, or both, where *a* is an element of the base ring. + In the *sigma_delta* variant, the output variables *sigma* or *delta* can be + `NULL`. + +.. type:: gr_ore_poly_sigma_delta_t + + A pointer to a function with the same specification as + :func:`gr_ore_poly_sigma_delta`. + +Arithmetic +------------------------------------------------------------------------------- + +.. function:: int gr_ore_poly_neg(gr_ore_poly_t res, const gr_ore_poly_t src, gr_ore_poly_ctx_t ctx) + +.. function:: 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_add(gr_ore_poly_t res, const gr_ore_poly_t poly1, const gr_ore_poly_t poly2, gr_ore_poly_ctx_t ctx) + +.. function:: int _gr_ore_poly_sub(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_ore_poly_t res, const gr_ore_poly_t poly1, const gr_ore_poly_t poly2, gr_ore_poly_ctx_t ctx) + +.. function:: int gr_ore_poly_add_ui(gr_ore_poly_t res, const gr_ore_poly_t poly, ulong c, gr_ore_poly_ctx_t ctx) + int gr_ore_poly_add_si(gr_ore_poly_t res, const gr_ore_poly_t poly, slong c, gr_ore_poly_ctx_t ctx) + int gr_ore_poly_add_fmpz(gr_ore_poly_t res, const gr_ore_poly_t poly, const fmpz c, gr_ore_poly_ctx_t ctx) + int gr_ore_poly_add_fmpq(gr_ore_poly_t res, const gr_ore_poly_t poly, const fmpq c, gr_ore_poly_ctx_t ctx) + int gr_ore_poly_add_other(gr_ore_poly_t res, const gr_ore_poly_t poly, gr_srcptr x, gr_ctx_t x_ctx, gr_ore_poly_ctx_t ctx) + + Sets *res* to *poly* plus the scalar *c* which must be + an element of or coercible to the coefficient ring. + +.. function:: int gr_ore_poly_sub_ui(gr_ore_poly_t res, const gr_ore_poly_t poly, ulong c, gr_ore_poly_ctx_t ctx) + int gr_ore_poly_sub_si(gr_ore_poly_t res, const gr_ore_poly_t poly, slong c, gr_ore_poly_ctx_t ctx) + int gr_ore_poly_sub_fmpz(gr_ore_poly_t res, const gr_ore_poly_t poly, const fmpz c, gr_ore_poly_ctx_t ctx) + int gr_ore_poly_sub_fmpq(gr_ore_poly_t res, const gr_ore_poly_t poly, const fmpq c, gr_ore_poly_ctx_t ctx) + int gr_ore_poly_sub_other(gr_ore_poly_t res, const gr_ore_poly_t poly, gr_srcptr x, gr_ctx_t x_ctx, gr_ore_poly_ctx_t ctx) + + Sets *res* to *poly* minus *c* which must be + an element of or coercible to the coefficient ring. + +.. function:: int gr_ore_poly_mul_ui(gr_ore_poly_t res, const gr_ore_poly_t poly, ulong c, gr_ore_poly_ctx_t ctx) + int gr_ore_poly_mul_si(gr_ore_poly_t res, const gr_ore_poly_t poly, slong c, gr_ore_poly_ctx_t ctx) + int gr_ore_poly_mul_fmpz(gr_ore_poly_t res, const gr_ore_poly_t poly, const fmpz c, gr_ore_poly_ctx_t ctx) + int gr_ore_poly_mul_fmpq(gr_ore_poly_t res, const gr_ore_poly_t poly, const fmpq c, gr_ore_poly_ctx_t ctx) + int gr_ore_poly_other_mul(gr_ore_poly_t res, gr_srcptr x, gr_ctx_t x_ctx, const gr_ore_poly_t poly, gr_ore_poly_ctx_t ctx) + + Sets *res* to *poly* multiplied by *c* (or *x* multiplied by *poly*) + which must be an element of or coercible to the coefficient ring. + +.. raw:: latex + + \newpage + diff --git a/doc/source/index.rst b/doc/source/index.rst index 94f8fa66da..f9cea12d61 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -60,6 +60,7 @@ Generic rings gr_mat.rst gr_poly.rst gr_mpoly.rst + gr_ore_poly.rst gr_series.rst .. only:: not latex diff --git a/doc/source/index_generic.rst b/doc/source/index_generic.rst index 8903dc74c6..ce80504476 100644 --- a/doc/source/index_generic.rst +++ b/doc/source/index_generic.rst @@ -16,5 +16,6 @@ gr_mat.rst gr_poly.rst gr_mpoly.rst + gr_ore_poly.rst gr_series.rst diff --git a/src/generic_files/io.c b/src/generic_files/io.c index f680ddc2d6..efb71bd6ba 100644 --- a/src/generic_files/io.c +++ b/src/generic_files/io.c @@ -26,6 +26,7 @@ #include "gr.h" #include "gr_vec.h" #include "gr_poly.h" +#include "gr_ore_poly.h" #include "gr_mat.h" int _gr_mat_write(gr_stream_t out, const gr_mat_t mat, int linebreaks, gr_ctx_t ctx); @@ -728,6 +729,14 @@ int flint_vfprintf(FILE * fs, const char * ip, va_list vlist) res += out->len; ip += STRING_LENGTH("gr_poly}"); } + else if (IS_FLINT_TYPE(ip, "gr_ore_poly")) + { + const gr_ore_poly_struct * elem = va_arg(vlist, const gr_ore_poly_struct *); + gr_ctx_struct * ctx = va_arg(vlist, gr_ctx_struct *); + GR_MUST_SUCCEED(gr_ore_poly_write(out, elem, ctx)); + res += out->len; + ip += STRING_LENGTH("gr_ore_poly}"); + } else if (IS_FLINT_TYPE(ip, "gr_mat")) { const gr_mat_struct * elem = va_arg(vlist, const gr_mat_struct *); diff --git a/src/gr.h b/src/gr.h index 008dceb010..2b3d73232c 100644 --- a/src/gr.h +++ b/src/gr.h @@ -714,6 +714,7 @@ typedef enum GR_CTX_FMPZ_MPOLY, GR_CTX_GR_MPOLY, GR_CTX_FMPZ_MPOLY_Q, GR_CTX_FMPZ_MOD_MPOLY_Q, + GR_CTX_GR_ORE_POLY, GR_CTX_GR_FRACTION, GR_CTX_GR_SERIES, GR_CTX_SERIES_MOD_GR_POLY, GR_CTX_GR_MAT, @@ -1354,6 +1355,9 @@ truth_t gr_generic_ctx_predicate_false(gr_ctx_t ctx); /* Some base rings */ void gr_ctx_init_random(gr_ctx_t ctx, flint_rand_t state); +void gr_ctx_init_random_poly(gr_ctx_t ctx, flint_rand_t state); +void gr_ctx_init_random_mpoly(gr_ctx_t ctx, flint_rand_t state); +void gr_ctx_init_random_series(gr_ctx_t ctx, flint_rand_t state); void gr_ctx_init_fmpz(gr_ctx_t ctx); void gr_ctx_init_fmpq(gr_ctx_t ctx); diff --git a/src/gr/init_random.c b/src/gr/init_random.c index 73f7042e05..876158bb42 100644 --- a/src/gr/init_random.c +++ b/src/gr/init_random.c @@ -268,3 +268,52 @@ void gr_ctx_init_random(gr_ctx_t ctx, flint_rand_t state) gr_ctx_println(ctx); */ } + +void +gr_ctx_init_random_poly(gr_ctx_t ctx, flint_rand_t state) +{ + switch (n_randint(state, 8)) + { + case 0: + gr_ctx_init_fmpz_poly(ctx); + break; + case 1: + gr_ctx_init_fmpq_poly(ctx); + break; + default: + gr_ctx_init_gr_poly(ctx, _gr_random_base_ring(state)); + break; + } +} + +void +gr_ctx_init_random_mpoly(gr_ctx_t ctx, flint_rand_t state) +{ + ordering_t ordering = mpoly_ordering_randtest(state); + + switch (n_randint(state, 2)) + { + case 0: + gr_ctx_init_gr_mpoly(ctx, _gr_random_base_ring(state), n_randint(state, 3), ordering); + break; + case 1: + gr_ctx_init_fmpz_mpoly(ctx, n_randint(state, 3), mpoly_ordering_randtest(state)); + break; + } +} + +void +gr_ctx_init_random_series(gr_ctx_t ctx, flint_rand_t state) +{ + gr_ctx_struct * base_ring = _gr_random_base_ring(state); + + switch (n_randint(state, 2)) + { + case 0: + gr_series_ctx_init(ctx, base_ring, n_randint(state, 6)); + break; + case 1: + gr_series_mod_ctx_init(ctx, base_ring, n_randint(state, 6)); + break; + } +} diff --git a/src/gr/ore_poly.c b/src/gr/ore_poly.c new file mode 100644 index 0000000000..ee7a6f9ac8 --- /dev/null +++ b/src/gr/ore_poly.c @@ -0,0 +1,18 @@ +/* + Copyright (C) 2025 Ricardo Buring + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. See . +*/ + +#include "gr_ore_poly.h" + +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) +{ + gr_ore_poly_ctx_init(ctx, base_ring, base_var, which_algebra); +} diff --git a/src/gr_ore_poly.h b/src/gr_ore_poly.h new file mode 100644 index 0000000000..039aa9a939 --- /dev/null +++ b/src/gr_ore_poly.h @@ -0,0 +1,280 @@ +/* + Copyright (C) 2025 Ricardo Buring + Copyright (C) 2025 Marc Mezzarobba + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. See . +*/ + +#ifndef GR_ORE_POLY_H +#define GR_ORE_POLY_H + +#ifdef GR_ORE_POLY_INLINES_C +#define GR_ORE_POLY_INLINE +#else +#define GR_ORE_POLY_INLINE static inline +#endif + +#include "gr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Ore polynomial rings */ + +typedef enum { + ORE_ALGEBRA_CUSTOM, + ORE_ALGEBRA_COMMUTATIVE, + ORE_ALGEBRA_DERIVATIVE, + ORE_ALGEBRA_EULER_DERIVATIVE, + ORE_ALGEBRA_FORWARD_SHIFT, + ORE_ALGEBRA_FORWARD_DIFFERENCE, + ORE_ALGEBRA_BACKWARD_SHIFT, + ORE_ALGEBRA_BACKWARD_DIFFERENCE, + ORE_ALGEBRA_Q_SHIFT, + ORE_ALGEBRA_MAHLER, + /* todo: q-derivative? general substitution?... */ + ORE_ALGEBRA_FROBENIUS, + + ORE_POLY_NUM_ALGEBRAS +} +ore_algebra_t; + +ore_algebra_t ore_algebra_randtest(flint_rand_t state); + +/* Compatible with gr_poly_struct */ +typedef struct +{ + gr_ptr coeffs; + slong alloc; + slong length; +} +gr_ore_poly_struct; + +typedef gr_ore_poly_struct gr_ore_poly_t[1]; + +typedef gr_ctx_struct gr_ore_poly_ctx_struct; + +typedef gr_ore_poly_ctx_struct gr_ore_poly_ctx_t[1]; + +typedef int (* gr_ore_poly_sigma_delta_t) (gr_ptr, gr_ptr, gr_srcptr, gr_ore_poly_ctx_struct *); + +typedef struct +{ + slong base_var; + gr_ptr sigma_x; + union { + gr_ptr q; + slong mahler_base; + }; +} +gr_ore_poly_ore_data_t; + +/* Compatible with polynomial_ctx_t */ +typedef struct +{ + gr_ctx_struct * base_ring; + slong degree_limit; + char * var; + ore_algebra_t which_algebra; + gr_ore_poly_sigma_delta_t sigma_delta; + void * ore_data; +} +_gr_ore_poly_ctx_struct; + +#define GR_ORE_POLY_CTX(ring_ctx) ((_gr_ore_poly_ctx_struct *)((ring_ctx))) +#define GR_ORE_POLY_ELEM_CTX(ring_ctx) (GR_ORE_POLY_CTX(ring_ctx)->base_ring) +#define GR_ORE_POLY_ORE_DATA(ring_ctx) ((gr_ore_poly_ore_data_t *)(GR_ORE_POLY_CTX(ring_ctx)->ore_data)) + +GR_ORE_POLY_INLINE void * +gr_ore_poly_ctx_data_ptr(gr_ore_poly_ctx_t ctx) +{ + return GR_ORE_POLY_CTX(ctx)->ore_data; +} + +/* Context object */ + +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); + +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_ore_poly_ctx_clear(gr_ore_poly_ctx_t ctx); + +void gr_ore_poly_ctx_init_randtest(gr_ore_poly_ctx_t ctx, flint_rand_t state, gr_ctx_t base_ring); +void gr_ore_poly_ctx_init_randtest2(gr_ctx_t base_ring, gr_ore_poly_ctx_t ctx, flint_rand_t state); + +WARN_UNUSED_RESULT int _gr_ore_poly_ctx_set_gen_name(gr_ctx_t ctx, const char * s); +WARN_UNUSED_RESULT int _gr_ore_poly_ctx_set_gen_names(gr_ctx_t ctx, const char ** s); +WARN_UNUSED_RESULT int gr_ore_poly_gens_recursive(gr_vec_t vec, gr_ore_poly_ctx_t ctx); + +int gr_ore_poly_ctx_write(gr_stream_t out, gr_ore_poly_ctx_t ctx); + +truth_t gr_ore_poly_ctx_is_ring(gr_ore_poly_ctx_t ctx); +truth_t gr_ore_poly_ctx_is_zero_ring(gr_ore_poly_ctx_t ctx); +truth_t gr_ore_poly_ctx_is_commutative_ring(gr_ore_poly_ctx_t ctx); +truth_t gr_ore_poly_ctx_is_integral_domain(gr_ore_poly_ctx_t ctx); +truth_t gr_ore_poly_ctx_is_threadsafe(gr_ore_poly_ctx_t ctx); + +/* Memory management */ + +void gr_ore_poly_init(gr_ore_poly_t poly, gr_ore_poly_ctx_t ctx); +void gr_ore_poly_init2(gr_ore_poly_t poly, slong len, gr_ore_poly_ctx_t ctx); +void gr_ore_poly_clear(gr_ore_poly_t poly, gr_ore_poly_ctx_t ctx); + +GR_ORE_POLY_INLINE gr_ptr +gr_ore_poly_coeff_ptr(gr_ore_poly_t poly, slong i, gr_ore_poly_ctx_t ctx) +{ + return GR_ENTRY(poly->coeffs, i, GR_ORE_POLY_ELEM_CTX(ctx)->sizeof_elem); +} + +GR_ORE_POLY_INLINE gr_srcptr +gr_ore_poly_coeff_srcptr(const gr_ore_poly_t poly, slong i, gr_ore_poly_ctx_t ctx) +{ + return GR_ENTRY(poly->coeffs, i, GR_ORE_POLY_ELEM_CTX(ctx)->sizeof_elem); +} + +GR_ORE_POLY_INLINE slong gr_ore_poly_length(const gr_ore_poly_t poly, gr_ore_poly_ctx_t FLINT_UNUSED(ctx)) +{ + return poly->length; +} + +GR_ORE_POLY_INLINE void +gr_ore_poly_swap(gr_ore_poly_t poly1, gr_ore_poly_t poly2, gr_ore_poly_ctx_t FLINT_UNUSED(ctx)) +{ + FLINT_SWAP(gr_ore_poly_struct, *poly1, *poly2); +} + +GR_ORE_POLY_INLINE void +gr_ore_poly_set_shallow(gr_ore_poly_t res, const gr_ore_poly_t x, const gr_ore_poly_ctx_t ctx) +{ + *res = *x; +} + +void gr_ore_poly_fit_length(gr_ore_poly_t poly, slong len, gr_ore_poly_ctx_t ctx); +void _gr_ore_poly_set_length(gr_ore_poly_t poly, slong len, gr_ore_poly_ctx_t ctx); +void _gr_ore_poly_normalise(gr_ore_poly_t poly, gr_ore_poly_ctx_t ctx); + +/* Basic manipulation */ + +WARN_UNUSED_RESULT int gr_ore_poly_set(gr_ore_poly_t res, const gr_ore_poly_t src, gr_ore_poly_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_ore_poly_truncate(gr_ore_poly_t poly, const gr_ore_poly_t src, slong newlen, gr_ore_poly_ctx_t ctx); + +GR_ORE_POLY_INLINE WARN_UNUSED_RESULT int +gr_ore_poly_zero(gr_ore_poly_t poly, gr_ore_poly_ctx_t ctx) +{ + _gr_ore_poly_set_length(poly, 0, ctx); + return GR_SUCCESS; +} + +WARN_UNUSED_RESULT int gr_ore_poly_one(gr_ore_poly_t poly, gr_ore_poly_ctx_t ctx); +WARN_UNUSED_RESULT int gr_ore_poly_neg_one(gr_ore_poly_t poly, gr_ore_poly_ctx_t ctx); +WARN_UNUSED_RESULT int gr_ore_poly_gen(gr_ore_poly_t poly, gr_ore_poly_ctx_t ctx); + +truth_t _gr_ore_poly_equal(gr_srcptr poly1, slong len1, gr_srcptr poly2, slong len2, gr_ore_poly_ctx_t ctx); +truth_t gr_ore_poly_equal(const gr_ore_poly_t poly1, const gr_ore_poly_t poly2, gr_ore_poly_ctx_t ctx); + +truth_t gr_ore_poly_is_zero(const gr_ore_poly_t poly, gr_ore_poly_ctx_t ctx); +truth_t gr_ore_poly_is_one(const gr_ore_poly_t poly, gr_ore_poly_ctx_t ctx); +truth_t gr_ore_poly_is_gen(const gr_ore_poly_t poly, gr_ore_poly_ctx_t ctx); + +/* Input and output */ + +int _gr_ore_poly_write(gr_stream_t out, gr_srcptr poly, slong len, gr_ore_poly_ctx_t ctx); +int gr_ore_poly_write(gr_stream_t out, const gr_ore_poly_t poly, gr_ore_poly_ctx_t ctx); +int _gr_ore_poly_get_str(char ** res, gr_srcptr f, slong len, gr_ore_poly_ctx_t ctx); +int gr_ore_poly_get_str(char ** res, const gr_ore_poly_t poly, gr_ore_poly_ctx_t ctx); +int _gr_ore_poly_set_str(gr_ptr res, const char * s, slong len, gr_ore_poly_ctx_t ctx); +int gr_ore_poly_set_str(gr_ore_poly_t res, const char * s, gr_ore_poly_ctx_t ctx); +int gr_ore_poly_print(const gr_ore_poly_t poly, gr_ore_poly_ctx_t ctx); + +/* Random generation */ + +int gr_ore_poly_randtest(gr_ore_poly_t poly, flint_rand_t state, slong len, gr_ore_poly_ctx_t ctx); + +GR_ORE_POLY_INLINE WARN_UNUSED_RESULT int +_gr_ore_poly_randtest_default(gr_ore_poly_t res, flint_rand_t state, gr_ore_poly_ctx_t ctx) +{ + return gr_ore_poly_randtest(res, state, n_randint(state, 5), ctx); +} + +/* Constants */ + +WARN_UNUSED_RESULT int gr_ore_poly_set_si(gr_ore_poly_t poly, slong x, gr_ore_poly_ctx_t ctx); +WARN_UNUSED_RESULT int gr_ore_poly_set_ui(gr_ore_poly_t poly, ulong x, gr_ore_poly_ctx_t ctx); +WARN_UNUSED_RESULT int gr_ore_poly_set_fmpz(gr_ore_poly_t poly, const fmpz_t x, gr_ore_poly_ctx_t ctx); +WARN_UNUSED_RESULT int gr_ore_poly_set_fmpq(gr_ore_poly_t poly, const fmpq_t x, gr_ore_poly_ctx_t ctx); +WARN_UNUSED_RESULT int gr_ore_poly_set_other(gr_ore_poly_t poly, gr_srcptr x, gr_ctx_t x_ctx, gr_ore_poly_ctx_t ctx); + +/* Action on the base ring */ + +WARN_UNUSED_RESULT int sigma_delta_unable(gr_ptr sigma, gr_ptr delta, gr_srcptr a, gr_ore_poly_ctx_struct * ctx); +WARN_UNUSED_RESULT int sigma_delta_commutative(gr_ptr sigma, gr_ptr delta, gr_srcptr a, gr_ore_poly_ctx_struct * ctx); +WARN_UNUSED_RESULT int sigma_delta_derivative(gr_ptr sigma, gr_ptr delta, gr_srcptr a, gr_ore_poly_ctx_struct * ctx); +WARN_UNUSED_RESULT int sigma_delta_euler_derivative(gr_ptr sigma, gr_ptr delta, gr_srcptr a, gr_ore_poly_ctx_struct * ctx); +WARN_UNUSED_RESULT int sigma_delta_forward_shift(gr_ptr sigma, gr_ptr delta, gr_srcptr a, gr_ore_poly_ctx_struct * ctx); +WARN_UNUSED_RESULT int sigma_delta_backward_shift(gr_ptr sigma, gr_ptr delta, gr_srcptr a, gr_ore_poly_ctx_struct * ctx); +WARN_UNUSED_RESULT int sigma_delta_forward_difference(gr_ptr sigma, gr_ptr delta, gr_srcptr a, gr_ore_poly_ctx_struct * ctx); +WARN_UNUSED_RESULT int sigma_delta_backward_difference(gr_ptr sigma, gr_ptr delta, gr_srcptr a, gr_ore_poly_ctx_struct * ctx); +WARN_UNUSED_RESULT int sigma_delta_q_shift(gr_ptr sigma, gr_ptr delta, gr_srcptr a, gr_ore_poly_ctx_struct * ctx); +WARN_UNUSED_RESULT int sigma_delta_mahler(gr_ptr sigma, gr_ptr delta, gr_srcptr a, gr_ore_poly_ctx_struct * ctx); +WARN_UNUSED_RESULT int sigma_delta_frobenius(gr_ptr sigma, gr_ptr delta, gr_srcptr a, gr_ore_poly_ctx_struct * ctx); + +GR_ORE_POLY_INLINE WARN_UNUSED_RESULT int +gr_ore_poly_sigma_delta(gr_ptr sigma, gr_ptr delta, gr_srcptr a, gr_ore_poly_ctx_t ctx) +{ + return GR_ORE_POLY_CTX(ctx)->sigma_delta(sigma, delta, a, ctx); +} + +GR_ORE_POLY_INLINE WARN_UNUSED_RESULT int +gr_ore_poly_sigma(gr_ptr res, gr_srcptr a, gr_ore_poly_ctx_t ctx) +{ + return GR_ORE_POLY_CTX(ctx)->sigma_delta(res, NULL, a, ctx); +} + +GR_ORE_POLY_INLINE WARN_UNUSED_RESULT int +gr_ore_poly_delta(gr_ptr res, gr_srcptr a, gr_ore_poly_ctx_t ctx) +{ + return GR_ORE_POLY_CTX(ctx)->sigma_delta(NULL, res, a, ctx); +} + +extern const gr_ore_poly_sigma_delta_t _gr_ore_poly_default_sigma_delta[]; + +/* Arithmetic */ + +WARN_UNUSED_RESULT int gr_ore_poly_neg(gr_ore_poly_t res, const gr_ore_poly_t src, gr_ore_poly_ctx_t ctx); + +WARN_UNUSED_RESULT int _gr_ore_poly_add(gr_ptr res, gr_srcptr poly1, slong len1, gr_srcptr poly2, slong len2, gr_ore_poly_ctx_t ctx); +WARN_UNUSED_RESULT int gr_ore_poly_add(gr_ore_poly_t res, const gr_ore_poly_t poly1, const gr_ore_poly_t poly2, gr_ore_poly_ctx_t ctx); + +WARN_UNUSED_RESULT int _gr_ore_poly_sub(gr_ptr res, gr_srcptr poly1, slong len1, gr_srcptr poly2, slong len2, gr_ore_poly_ctx_t ctx); +WARN_UNUSED_RESULT int gr_ore_poly_sub(gr_ore_poly_t res, const gr_ore_poly_t poly1, const gr_ore_poly_t poly2, gr_ore_poly_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_ore_poly_add_ui(gr_ore_poly_t res, const gr_ore_poly_t poly, ulong c, gr_ore_poly_ctx_t ctx); +WARN_UNUSED_RESULT int gr_ore_poly_add_si(gr_ore_poly_t res, const gr_ore_poly_t poly, slong c, gr_ore_poly_ctx_t ctx); +WARN_UNUSED_RESULT int gr_ore_poly_add_fmpz(gr_ore_poly_t res, const gr_ore_poly_t poly, const fmpz_t c, gr_ore_poly_ctx_t ctx); +WARN_UNUSED_RESULT int gr_ore_poly_add_fmpq(gr_ore_poly_t res, const gr_ore_poly_t poly, const fmpq_t c, gr_ore_poly_ctx_t ctx); +WARN_UNUSED_RESULT int gr_ore_poly_add_other(gr_ore_poly_t res, const gr_ore_poly_t poly, gr_srcptr x, gr_ctx_t x_ctx, gr_ore_poly_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_ore_poly_sub_ui(gr_ore_poly_t res, const gr_ore_poly_t poly, ulong c, gr_ore_poly_ctx_t ctx); +WARN_UNUSED_RESULT int gr_ore_poly_sub_si(gr_ore_poly_t res, const gr_ore_poly_t poly, slong c, gr_ore_poly_ctx_t ctx); +WARN_UNUSED_RESULT int gr_ore_poly_sub_fmpz(gr_ore_poly_t res, const gr_ore_poly_t poly, const fmpz_t c, gr_ore_poly_ctx_t ctx); +WARN_UNUSED_RESULT int gr_ore_poly_sub_fmpq(gr_ore_poly_t res, const gr_ore_poly_t poly, const fmpq_t c, gr_ore_poly_ctx_t ctx); +WARN_UNUSED_RESULT int gr_ore_poly_sub_other(gr_ore_poly_t res, const gr_ore_poly_t poly, gr_srcptr x, gr_ctx_t x_ctx, gr_ore_poly_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_ore_poly_mul_ui(gr_ore_poly_t res, const gr_ore_poly_t poly, ulong c, gr_ore_poly_ctx_t ctx); +WARN_UNUSED_RESULT int gr_ore_poly_mul_si(gr_ore_poly_t res, const gr_ore_poly_t poly, slong c, gr_ore_poly_ctx_t ctx); +WARN_UNUSED_RESULT int gr_ore_poly_mul_fmpz(gr_ore_poly_t res, const gr_ore_poly_t poly, const fmpz_t c, gr_ore_poly_ctx_t ctx); +WARN_UNUSED_RESULT int gr_ore_poly_mul_fmpq(gr_ore_poly_t res, const gr_ore_poly_t poly, const fmpq_t c, gr_ore_poly_ctx_t ctx); +WARN_UNUSED_RESULT int gr_ore_poly_other_mul(gr_ore_poly_t res, gr_srcptr x, gr_ctx_t x_ctx, const gr_ore_poly_t poly, gr_ore_poly_ctx_t ctx); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/gr_ore_poly/ctx.c b/src/gr_ore_poly/ctx.c new file mode 100644 index 0000000000..f14c269f1c --- /dev/null +++ b/src/gr_ore_poly/ctx.c @@ -0,0 +1,471 @@ +/* + Copyright (C) 2025 Ricardo Buring + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. See . +*/ + +/* Ore polynomials over generic rings */ + +#include +#include +#include "fmpz_mpoly_q.h" +#include "fmpz_mod_mpoly_q.h" +#include "gr_vec.h" +#include "gr_ore_poly.h" +#include "gr_poly.h" +#include "gr_generic.h" +#include "long_extras.h" +#include "mpoly.h" +#include "ulong_extras.h" + +static const char * default_var = "D"; + +int gr_ore_poly_ctx_write(gr_stream_t out, gr_ore_poly_ctx_t ctx) +{ + switch (GR_ORE_POLY_CTX(ctx)->which_algebra) + { + case ORE_ALGEBRA_CUSTOM: + gr_stream_write(out, "Custom Ore polynomials"); + break; + case ORE_ALGEBRA_COMMUTATIVE: + gr_stream_write(out, "Commutative Ore polynomials"); + break; + case ORE_ALGEBRA_DERIVATIVE: + gr_stream_write(out, "Differential operators"); + break; + case ORE_ALGEBRA_EULER_DERIVATIVE: + gr_stream_write(out, "Differential operators (Euler derivative)"); + break; + case ORE_ALGEBRA_FORWARD_SHIFT: + gr_stream_write(out, "Difference operators (forward shift)"); + break; + case ORE_ALGEBRA_FORWARD_DIFFERENCE: + gr_stream_write(out, "Difference operators (forward differences)"); + break; + case ORE_ALGEBRA_BACKWARD_SHIFT: + gr_stream_write(out, "Difference operators (backward shift)"); + break; + case ORE_ALGEBRA_BACKWARD_DIFFERENCE: + gr_stream_write(out, "Difference operators (backward differences)"); + break; + case ORE_ALGEBRA_Q_SHIFT: + gr_stream_write(out, "q-difference operators (q-shift)"); + break; + case ORE_ALGEBRA_MAHLER: + gr_stream_write(out, "Mahler operators"); + break; + case ORE_ALGEBRA_FROBENIUS: + gr_stream_write(out, "Ore-Frobenius polynomials"); + break; + default: + gr_stream_write(out, "Ore polynomials"); + break; + } + gr_stream_write(out, " over "); + gr_ctx_write(out, GR_ORE_POLY_ELEM_CTX(ctx)); + return GR_SUCCESS; +} + +int _gr_ore_poly_ctx_set_gen_name(gr_ctx_t ctx, const char * s) +{ + slong len; + len = strlen(s); + + if (GR_ORE_POLY_CTX(ctx)->var == default_var) + GR_ORE_POLY_CTX(ctx)->var = NULL; + + GR_ORE_POLY_CTX(ctx)->var = flint_realloc(GR_ORE_POLY_CTX(ctx)->var, len + 1); + memcpy(GR_ORE_POLY_CTX(ctx)->var, s, len + 1); + return GR_SUCCESS; +} + +int _gr_ore_poly_ctx_set_gen_names(gr_ctx_t ctx, const char ** s) +{ + return _gr_ore_poly_ctx_set_gen_name(ctx, s[0]); +} + +void +gr_ore_poly_ctx_clear(gr_ore_poly_ctx_t ctx) +{ + switch (GR_ORE_POLY_CTX(ctx)->which_algebra) + { + case ORE_ALGEBRA_Q_SHIFT: + gr_heap_clear(GR_ORE_POLY_ORE_DATA(ctx)->q, + GR_ORE_POLY_ELEM_CTX(ctx)); + gr_heap_clear(GR_ORE_POLY_ORE_DATA(ctx)->sigma_x, + GR_ORE_POLY_ELEM_CTX(ctx)); + break; + default: + ; + } + + if (GR_ORE_POLY_CTX(ctx)->which_algebra != ORE_ALGEBRA_CUSTOM) + flint_free(GR_ORE_POLY_CTX(ctx)->ore_data); + + if (GR_ORE_POLY_CTX(ctx)->var != default_var) + flint_free(GR_ORE_POLY_CTX(ctx)->var); +} + +truth_t +gr_ore_poly_ctx_is_ring(gr_ore_poly_ctx_t ctx) +{ + return gr_ctx_is_ring(GR_ORE_POLY_ELEM_CTX(ctx)); +} + +truth_t +gr_ore_poly_ctx_is_zero_ring(gr_ore_poly_ctx_t ctx) +{ + return gr_ctx_is_zero_ring(GR_ORE_POLY_ELEM_CTX(ctx)); +} + +truth_t +gr_ore_poly_ctx_is_commutative_ring(gr_ore_poly_ctx_t ctx) +{ + return T_UNKNOWN; +} + +truth_t +gr_ore_poly_ctx_is_integral_domain(gr_ore_poly_ctx_t ctx) +{ + return T_UNKNOWN; +} + +truth_t +gr_ore_poly_ctx_is_unique_factorization_domain(gr_ore_poly_ctx_t ctx) +{ + return T_UNKNOWN; +} + +truth_t +gr_ore_poly_ctx_is_threadsafe(gr_ore_poly_ctx_t ctx) +{ + return gr_ctx_is_threadsafe(GR_ORE_POLY_ELEM_CTX(ctx)); +} + +int +ore_poly_write(gr_stream_t out, gr_ore_poly_t poly, gr_ctx_t ctx) +{ + /* todo */ + if (poly->length == 0) + { + gr_stream_write(out, "0"); + return GR_SUCCESS; + } + + return gr_ore_poly_write(out, poly, ctx); +} + +int +gr_ore_poly_i(gr_ore_poly_t res, gr_ore_poly_ctx_t ctx) +{ + int status; + gr_ore_poly_fit_length(res, 1, ctx); + _gr_ore_poly_set_length(res, 1, ctx); + status = gr_i(res->coeffs, GR_ORE_POLY_ELEM_CTX(ctx)); + _gr_ore_poly_normalise(res, ctx); + return status; +} + +int +gr_ore_poly_gens_recursive(gr_vec_t vec, gr_ore_poly_ctx_t ctx) +{ + int status; + gr_vec_t vec1; + slong i, n; + + /* Get generators of the element ring */ + gr_vec_init(vec1, 0, GR_ORE_POLY_ELEM_CTX(ctx)); + status = gr_gens_recursive(vec1, GR_ORE_POLY_ELEM_CTX(ctx)); + n = vec1->length; + + gr_vec_set_length(vec, n + 1, ctx); + + /* Promote to Ore polynomials */ + for (i = 0; i < n; i++) + status |= gr_ore_poly_set_other(gr_vec_entry_ptr(vec, i, ctx), + gr_vec_entry_srcptr(vec1, i, GR_ORE_POLY_ELEM_CTX(ctx)), + GR_ORE_POLY_ELEM_CTX(ctx), + ctx); + + status |= gr_ore_poly_gen(gr_vec_entry_ptr(vec, n, ctx), ctx); + + gr_vec_clear(vec1, GR_ORE_POLY_ELEM_CTX(ctx)); + + return status; +} + +int _gr_ore_poly_methods_initialized = 0; + +gr_static_method_table _gr_ore_poly_methods; + +gr_method_tab_input _gr_ore_poly_methods_input[] = +{ + {GR_METHOD_CTX_WRITE, (gr_funcptr) gr_ore_poly_ctx_write}, + {GR_METHOD_CTX_CLEAR, (gr_funcptr) gr_ore_poly_ctx_clear}, + + {GR_METHOD_CTX_IS_RING, (gr_funcptr) gr_ore_poly_ctx_is_ring}, + {GR_METHOD_CTX_IS_ZERO_RING, (gr_funcptr) gr_ore_poly_ctx_is_zero_ring}, + {GR_METHOD_CTX_IS_COMMUTATIVE_RING, (gr_funcptr) gr_ore_poly_ctx_is_commutative_ring}, + {GR_METHOD_CTX_IS_INTEGRAL_DOMAIN, (gr_funcptr) gr_ore_poly_ctx_is_integral_domain}, + {GR_METHOD_CTX_IS_UNIQUE_FACTORIZATION_DOMAIN, (gr_funcptr) gr_ore_poly_ctx_is_unique_factorization_domain}, + {GR_METHOD_CTX_IS_FIELD, (gr_funcptr) gr_generic_ctx_predicate_false}, + {GR_METHOD_CTX_IS_THREADSAFE, (gr_funcptr) gr_ore_poly_ctx_is_threadsafe}, + {GR_METHOD_CTX_SET_GEN_NAME, (gr_funcptr) _gr_ore_poly_ctx_set_gen_name}, + {GR_METHOD_CTX_SET_GEN_NAMES, (gr_funcptr) _gr_ore_poly_ctx_set_gen_names}, + + {GR_METHOD_INIT, (gr_funcptr) gr_ore_poly_init}, + {GR_METHOD_CLEAR, (gr_funcptr) gr_ore_poly_clear}, + {GR_METHOD_SWAP, (gr_funcptr) gr_ore_poly_swap}, + {GR_METHOD_SET_SHALLOW, (gr_funcptr) gr_ore_poly_set_shallow}, + {GR_METHOD_RANDTEST, (gr_funcptr) _gr_ore_poly_randtest_default}, + {GR_METHOD_WRITE, (gr_funcptr) ore_poly_write}, + {GR_METHOD_ZERO, (gr_funcptr) gr_ore_poly_zero}, + {GR_METHOD_ONE, (gr_funcptr) gr_ore_poly_one}, + {GR_METHOD_NEG_ONE, (gr_funcptr) gr_ore_poly_neg_one}, + {GR_METHOD_I, (gr_funcptr) gr_ore_poly_i}, + + {GR_METHOD_GEN, (gr_funcptr) gr_ore_poly_gen}, + {GR_METHOD_GENS, (gr_funcptr) gr_generic_gens_single}, + {GR_METHOD_GENS_RECURSIVE, (gr_funcptr) gr_ore_poly_gens_recursive}, + +/* + {GR_METHOD_IS_ZERO, (gr_funcptr) gr_ore_poly_is_zero}, + {GR_METHOD_IS_ONE, (gr_funcptr) gr_ore_poly_is_one}, + {GR_METHOD_IS_NEG_ONE, (gr_funcptr) gr_ore_poly_is_neg_one}, +*/ + {GR_METHOD_EQUAL, (gr_funcptr) gr_ore_poly_equal}, + {GR_METHOD_SET, (gr_funcptr) gr_ore_poly_set}, + {GR_METHOD_SET_UI, (gr_funcptr) gr_ore_poly_set_ui}, + {GR_METHOD_SET_SI, (gr_funcptr) gr_ore_poly_set_si}, + {GR_METHOD_SET_FMPZ, (gr_funcptr) gr_ore_poly_set_fmpz}, + {GR_METHOD_SET_FMPQ, (gr_funcptr) gr_ore_poly_set_fmpq}, + {GR_METHOD_SET_OTHER, (gr_funcptr) gr_ore_poly_set_other}, +/* + {GR_METHOD_SET_INTERVAL_MID_RAD, (gr_funcptr) gr_ore_poly_set_interval_mid_rad}, +*/ + {GR_METHOD_SET_STR, (gr_funcptr) gr_ore_poly_set_str}, + {GR_METHOD_NEG, (gr_funcptr) gr_ore_poly_neg}, + {GR_METHOD_ADD_UI, (gr_funcptr) gr_ore_poly_add_ui}, + {GR_METHOD_ADD_SI, (gr_funcptr) gr_ore_poly_add_si}, + {GR_METHOD_ADD_FMPZ, (gr_funcptr) gr_ore_poly_add_fmpz}, + {GR_METHOD_ADD_FMPQ, (gr_funcptr) gr_ore_poly_add_fmpq}, + {GR_METHOD_ADD, (gr_funcptr) gr_ore_poly_add}, + {GR_METHOD_ADD_OTHER, (gr_funcptr) gr_ore_poly_add_other}, + {GR_METHOD_SUB_UI, (gr_funcptr) gr_ore_poly_sub_ui}, + {GR_METHOD_SUB_SI, (gr_funcptr) gr_ore_poly_sub_si}, + {GR_METHOD_SUB_FMPZ, (gr_funcptr) gr_ore_poly_sub_fmpz}, + {GR_METHOD_SUB_FMPQ, (gr_funcptr) gr_ore_poly_sub_fmpq}, + {GR_METHOD_SUB, (gr_funcptr) gr_ore_poly_sub}, + {GR_METHOD_SUB_OTHER, (gr_funcptr) gr_ore_poly_sub_other}, +/* + {GR_METHOD_MUL, (gr_funcptr) gr_ore_poly_mul}, + {GR_METHOD_MUL_OTHER, (gr_funcptr) gr_ore_poly_mul_other}, +*/ + {GR_METHOD_OTHER_MUL, (gr_funcptr) gr_ore_poly_other_mul}, + {GR_METHOD_MUL_UI, (gr_funcptr) gr_ore_poly_mul_ui}, + {GR_METHOD_MUL_SI, (gr_funcptr) gr_ore_poly_mul_si}, + {GR_METHOD_MUL_FMPZ, (gr_funcptr) gr_ore_poly_mul_fmpz}, + {GR_METHOD_MUL_FMPQ, (gr_funcptr) gr_ore_poly_mul_fmpq}, +/* + {GR_METHOD_POW_UI, (gr_funcptr) gr_ore_poly_pow_ui}, + {GR_METHOD_POW_SI, (gr_funcptr) gr_ore_poly_pow_si}, + {GR_METHOD_POW_FMPZ, (gr_funcptr) gr_ore_poly_pow_fmpz}, + {GR_METHOD_DIV, (gr_funcptr) gr_ore_poly_div}, + {GR_METHOD_INV, (gr_funcptr) gr_ore_poly_inv}, + + {GR_METHOD_EUCLIDEAN_DIV, (gr_funcptr) gr_ore_poly_euclidean_div}, + {GR_METHOD_EUCLIDEAN_REM, (gr_funcptr) gr_ore_poly_euclidean_rem}, + {GR_METHOD_EUCLIDEAN_DIVREM, (gr_funcptr) gr_ore_poly_euclidean_divrem}, + + {GR_METHOD_GCD, (gr_funcptr) gr_ore_poly_gcd}, + + {GR_METHOD_FACTOR, (gr_funcptr) gr_ore_poly_factor}, +*/ + + {0, (gr_funcptr) NULL}, +}; + +void +_gr_ore_poly_ctx_init(gr_ore_poly_ctx_t ctx, gr_ctx_t base_ring, const ore_algebra_t which_algebra) +{ + ctx->which_ring = GR_CTX_GR_ORE_POLY; + ctx->sizeof_elem = sizeof(gr_ore_poly_struct); + ctx->size_limit = WORD_MAX; + + GR_ORE_POLY_CTX(ctx)->base_ring = (gr_ctx_struct *) base_ring; + GR_ORE_POLY_CTX(ctx)->degree_limit = WORD_MAX; + GR_ORE_POLY_CTX(ctx)->var = (char *) default_var; + GR_ORE_POLY_CTX(ctx)->which_algebra = which_algebra; + GR_ORE_POLY_CTX(ctx)->sigma_delta = _gr_ore_poly_default_sigma_delta[which_algebra]; + + ctx->methods = _gr_ore_poly_methods; + + if (!_gr_ore_poly_methods_initialized) + { + gr_method_tab_init(_gr_ore_poly_methods, _gr_ore_poly_methods_input); + _gr_ore_poly_methods_initialized = 1; + } +} + +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) +{ + _gr_ore_poly_ctx_init(ctx, base_ring, which_algebra); + + /* todo: FLINT_ASSERT(base_var < gr_ctx_ngens(base_ring)) */ + + GR_ORE_POLY_CTX(ctx)->ore_data = flint_malloc(sizeof(gr_ore_poly_ore_data_t)); + GR_ORE_POLY_ORE_DATA(ctx)->base_var = base_var; +} + +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(ctx, base_ring, ORE_ALGEBRA_CUSTOM); + GR_ORE_POLY_CTX(ctx)->sigma_delta = sigma_delta; + GR_ORE_POLY_CTX(ctx)->ore_data = ore_data; +} + +/* although we currently require base_ring to be a univariate polynomial ring + * and in this case q will typically be a constant, for multivariate polynomial + * rings one typically wants q to be an element of the polynomial ring, not its + * base ring */ +int +gr_ore_poly_ctx_init_q_shift(gr_ore_poly_ctx_t ctx, gr_ctx_t base_ring, + slong base_var, gr_srcptr q) +{ + if (base_ring->which_ring != GR_CTX_GR_POLY) + return GR_UNABLE; + + int status = GR_SUCCESS; + + gr_ore_poly_ctx_init(ctx, base_ring, base_var, ORE_ALGEBRA_Q_SHIFT); + GR_ORE_POLY_ORE_DATA(ctx)->q = gr_heap_init(base_ring); + gr_ptr sigma_x = gr_heap_init(base_ring); + GR_ORE_POLY_ORE_DATA(ctx)->sigma_x = sigma_x; + + status |= gr_set(GR_ORE_POLY_ORE_DATA(ctx)->q, q, base_ring); + status |= gr_gen(sigma_x, base_ring); + status |= gr_mul(sigma_x, q, sigma_x, base_ring); + + return status; +} + +int +gr_ore_poly_ctx_init_mahler(gr_ore_poly_ctx_t ctx, gr_ctx_t base_ring, + slong base_var, long mahler_base) +{ + if (mahler_base == 0) + return GR_DOMAIN; + + gr_ore_poly_ctx_init(ctx, base_ring, base_var, ORE_ALGEBRA_MAHLER); + GR_ORE_POLY_ORE_DATA(ctx)->mahler_base = mahler_base; + + return GR_SUCCESS; +} + +ore_algebra_t +ore_algebra_randtest(flint_rand_t state) +{ + switch (n_randint(state, 3)) + { + case 0: + return ORE_ALGEBRA_DERIVATIVE; + case 1: + return ORE_ALGEBRA_FORWARD_SHIFT; + default: + return (ore_algebra_t) n_randint(state, ORE_POLY_NUM_ALGEBRAS); + } +} + +void +gr_ore_poly_ctx_init_randtest(gr_ore_poly_ctx_t ctx, flint_rand_t state, + gr_ctx_t base_ring) +{ + ore_algebra_t alg = ore_algebra_randtest(state); + /* todo: base_var = n_randint(gr_ctx_ngens(base_ring)) */ + slong base_var = 0; + + int status = GR_SUCCESS; + + if (alg == ORE_ALGEBRA_CUSTOM) + { + /* sigma_delta_commutative does not use ore_data */ + gr_ore_poly_ctx_init_custom(ctx, base_ring, sigma_delta_commutative, NULL); + } + else if (alg == ORE_ALGEBRA_Q_SHIFT) + { + if (base_ring->which_ring == GR_CTX_GR_POLY) + { + gr_ptr q; + GR_TMP_INIT(q, base_ring); + status |= gr_randtest_not_zero(q, state, base_ring); + if (status == GR_SUCCESS) + status |= gr_ore_poly_ctx_init_q_shift(ctx, base_ring, base_var, q); + GR_TMP_CLEAR(q, base_ring); + } + else + { + status = GR_UNABLE; + } + } + else if (alg == ORE_ALGEBRA_MAHLER) + { + slong b = 2 + n_randint(state, 3); + status |= gr_ore_poly_ctx_init_mahler(ctx, base_ring, base_var, b); + } + else + { + gr_ore_poly_ctx_init(ctx, base_ring, base_var, alg); + } + + if (status != GR_SUCCESS) + gr_ore_poly_ctx_init_custom(ctx, base_ring, sigma_delta_unable, NULL); +} + +void +gr_ore_poly_ctx_init_randtest2(gr_ctx_t base_ring, gr_ore_poly_ctx_t ctx, flint_rand_t state) +{ + fmpz_t mod; + + switch (n_randint(state, 10)) + { + case 0: + gr_ctx_init_random_mpoly(base_ring, state); + break; + case 1: + gr_ctx_init_random_series(base_ring, state); + break; + case 2: + gr_ctx_init_fmpz_mpoly_q(base_ring, n_randint(state, 3), + mpoly_ordering_randtest(state)); + break; + case 3: + fmpz_init(mod); + fmpz_set_ui(mod, n_randtest_prime(state, 1)); + gr_ctx_init_fmpz_mod_mpoly_q(base_ring, n_randint(state, 3), + mpoly_ordering_randtest(state), + mod); + fmpz_clear(mod); + break; + case 4: + fmpz_init(mod); + fmpz_set_ui(mod, n_randtest_prime(state, 1)); + gr_ctx_init_fq(base_ring, mod, 1 + n_randint(state, 3), NULL); + gr_ore_poly_ctx_init(ctx, base_ring, 0, ORE_ALGEBRA_FROBENIUS); + fmpz_clear(mod); + return; + default: + gr_ctx_init_random_poly(base_ring, state); + break; + } + + gr_ore_poly_ctx_init_randtest(ctx, state, base_ring); +} diff --git a/src/gr_ore_poly/inlines.c b/src/gr_ore_poly/inlines.c new file mode 100644 index 0000000000..c336ce14bd --- /dev/null +++ b/src/gr_ore_poly/inlines.c @@ -0,0 +1,3 @@ +#define GR_ORE_POLY_INLINES_C +#include "gr_ore_poly.h" +#undef GR_ORE_POLY_INLINES_C diff --git a/src/gr_ore_poly/ring.c b/src/gr_ore_poly/ring.c new file mode 100644 index 0000000000..1af0f51611 --- /dev/null +++ b/src/gr_ore_poly/ring.c @@ -0,0 +1,384 @@ +/* + Copyright (C) 2025 Ricardo Buring + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. See . +*/ + +#include +#include "gr_poly.h" +#include "gr_ore_poly.h" + +/* Memory management */ + +void gr_ore_poly_init(gr_ore_poly_t poly, gr_ore_poly_ctx_t ctx) +{ + poly->coeffs = NULL; + poly->length = 0; + poly->alloc = 0; +} + +void +gr_ore_poly_init2(gr_ore_poly_t poly, slong len, gr_ore_poly_ctx_t ctx) +{ + gr_poly_init((gr_poly_struct *) poly, GR_ORE_POLY_ELEM_CTX(ctx)); + gr_poly_fit_length((gr_poly_struct *) poly, len, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +void gr_ore_poly_clear(gr_ore_poly_t poly, gr_ore_poly_ctx_t ctx) +{ + gr_poly_clear((gr_poly_struct *) poly, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +void +_gr_ore_poly_set_length(gr_ore_poly_t poly, slong len, gr_ore_poly_ctx_t ctx) +{ + _gr_poly_set_length((gr_poly_struct *) poly, len, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +void +gr_ore_poly_fit_length(gr_ore_poly_t poly, slong len, gr_ore_poly_ctx_t ctx) +{ + gr_poly_fit_length((gr_poly_struct *) poly, len, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +/* Basic manipulation */ + +void +_gr_ore_poly_normalise(gr_ore_poly_t poly, gr_ore_poly_ctx_t ctx) +{ + _gr_poly_normalise((gr_poly_struct *) poly, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +int +gr_ore_poly_set(gr_ore_poly_t res, const gr_ore_poly_t src, gr_ore_poly_ctx_t ctx) +{ + return gr_poly_set((gr_poly_struct *) res, (const gr_poly_struct *) src, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +int +gr_ore_poly_truncate(gr_ore_poly_t poly, const gr_ore_poly_t src, slong newlen, gr_ore_poly_ctx_t ctx) +{ + return gr_poly_truncate((gr_poly_struct *) poly, (gr_poly_struct *) src, newlen, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +int +gr_ore_poly_one(gr_ore_poly_t res, gr_ore_poly_ctx_t ctx) +{ + return gr_poly_one((gr_poly_struct *) res, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +int +gr_ore_poly_neg_one(gr_ore_poly_t res, gr_ore_poly_ctx_t ctx) +{ + return gr_poly_neg_one((gr_poly_struct *) res, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +int +gr_ore_poly_gen(gr_ore_poly_t res, gr_ore_poly_ctx_t ctx) +{ + return gr_poly_gen((gr_poly_struct *) res, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +int +_gr_ore_poly_write(gr_stream_t out, gr_srcptr poly, slong n, gr_ore_poly_ctx_t ctx) +{ + return _gr_poly_write(out, poly, n, GR_ORE_POLY_CTX(ctx)->var, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +int +gr_ore_poly_write(gr_stream_t out, const gr_ore_poly_t poly, gr_ore_poly_ctx_t ctx) +{ + return _gr_poly_write(out, poly->coeffs, poly->length, GR_ORE_POLY_CTX(ctx)->var, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +int +_gr_ore_poly_get_str(char ** res, gr_srcptr f, slong len, gr_ore_poly_ctx_t ctx) +{ + return _gr_poly_get_str(res, f, len, GR_ORE_POLY_CTX(ctx)->var, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +int +gr_ore_poly_get_str(char ** res, const gr_ore_poly_t f, gr_ore_poly_ctx_t ctx) +{ + return _gr_poly_get_str(res, f->coeffs, f->length, GR_ORE_POLY_CTX(ctx)->var, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +int +gr_ore_poly_print(const gr_ore_poly_t poly, gr_ore_poly_ctx_t ctx) +{ + gr_stream_t out; + gr_stream_init_file(out, stdout); + return gr_ore_poly_write(out, poly, ctx); +} + +int +gr_ore_poly_set_str(gr_ore_poly_t res, const char * s, gr_ore_poly_ctx_t ctx) +{ + return gr_poly_set_str((gr_poly_struct *) res, s, GR_ORE_POLY_CTX(ctx)->var, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +int +_gr_ore_poly_set_str(gr_ptr res, const char * s, slong len, gr_ore_poly_ctx_t ctx) +{ + return _gr_poly_set_str(res, s, GR_ORE_POLY_CTX(ctx)->var, len, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +int +gr_ore_poly_randtest(gr_ore_poly_t poly, flint_rand_t state, slong len, gr_ore_poly_ctx_t ctx) +{ + return gr_poly_randtest((gr_poly_struct *) poly, state, len, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +truth_t +_gr_ore_poly_equal(gr_srcptr poly1, slong len1, gr_srcptr poly2, slong len2, gr_ore_poly_ctx_t ctx) +{ + return _gr_poly_equal(poly1, len1, poly2, len2, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +truth_t +gr_ore_poly_equal(const gr_ore_poly_t poly1, const gr_ore_poly_t poly2, gr_ore_poly_ctx_t ctx) +{ + return gr_poly_equal((const gr_poly_struct *) poly1, (const gr_poly_struct *) poly2, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +truth_t +gr_ore_poly_is_zero(const gr_ore_poly_t poly, gr_ore_poly_ctx_t ctx) +{ + return gr_poly_is_zero((const gr_poly_struct *) poly, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +truth_t +gr_ore_poly_is_one(const gr_ore_poly_t poly, gr_ore_poly_ctx_t ctx) +{ + return gr_poly_is_one((const gr_poly_struct *) poly, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +truth_t +gr_ore_poly_is_gen(const gr_ore_poly_t poly, gr_ore_poly_ctx_t ctx) +{ + return gr_poly_is_gen((const gr_poly_struct *) poly, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +int +gr_ore_poly_set_si(gr_ore_poly_t poly, slong x, gr_ore_poly_ctx_t ctx) +{ + return gr_poly_set_si((gr_poly_struct *) poly, x, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +int +gr_ore_poly_set_ui(gr_ore_poly_t poly, ulong x, gr_ore_poly_ctx_t ctx) +{ + return gr_poly_set_ui((gr_poly_struct *) poly, x, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +int +gr_ore_poly_set_fmpz(gr_ore_poly_t poly, const fmpz_t x, gr_ore_poly_ctx_t ctx) +{ + return gr_poly_set_fmpz((gr_poly_struct *) poly, x, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +int +gr_ore_poly_set_fmpq(gr_ore_poly_t poly, const fmpq_t x, gr_ore_poly_ctx_t ctx) +{ + return gr_poly_set_fmpq((gr_poly_struct *) poly, x, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +int +gr_ore_poly_set_other(gr_ore_poly_t poly, gr_srcptr x, gr_ctx_t x_ctx, gr_ore_poly_ctx_t ctx) +{ + if (x_ctx == ctx) { + return gr_poly_set((gr_poly_struct *) poly, x, GR_ORE_POLY_ELEM_CTX(ctx)); + } else if (x_ctx == GR_ORE_POLY_ELEM_CTX(ctx)) { + return gr_poly_set_scalar((gr_poly_struct *) poly, x, GR_ORE_POLY_ELEM_CTX(ctx)); + } else if (GR_ORE_POLY_CTX(ctx)->base_ring->which_ring == GR_CTX_GR_POLY && \ + POLYNOMIAL_CTX(GR_ORE_POLY_CTX(ctx)->base_ring)->base_ring == x_ctx) { + gr_poly_t tmp; + tmp->coeffs = (gr_ptr) x; + tmp->length = 1; + tmp->alloc = 1; + return gr_poly_set_scalar((gr_poly_struct *) poly, tmp, GR_ORE_POLY_ELEM_CTX(ctx)); + } else if (x_ctx->which_ring == GR_CTX_FMPZ) { + return gr_poly_set_fmpz((gr_poly_struct *) poly, x, GR_ORE_POLY_ELEM_CTX(ctx)); + } else if (x_ctx->which_ring == GR_CTX_FMPQ) { + return gr_poly_set_fmpq((gr_poly_struct *) poly, x, GR_ORE_POLY_ELEM_CTX(ctx)); + } + return GR_UNABLE; +} + +/* Arithmetic */ + +int +gr_ore_poly_neg(gr_ore_poly_t res, const gr_ore_poly_t src, gr_ore_poly_ctx_t ctx) +{ + return gr_poly_neg((gr_poly_struct *) res, (const gr_poly_struct *) src, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +int +_gr_ore_poly_add(gr_ptr res, gr_srcptr poly1, slong len1, + gr_srcptr poly2, slong len2, gr_ore_poly_ctx_t ctx) +{ + return _gr_poly_add(res, poly1, len1, poly2, len2, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +int +gr_ore_poly_add(gr_ore_poly_t res, const gr_ore_poly_t poly1, const gr_ore_poly_t poly2, gr_ore_poly_ctx_t ctx) +{ + return gr_poly_add((gr_poly_struct *) res, (const gr_poly_struct *) poly1, (const gr_poly_struct *) poly2, GR_ORE_POLY_ELEM_CTX(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) +{ + return _gr_poly_sub((gr_poly_struct *) res, poly1, len1, poly2, len2, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +int +gr_ore_poly_sub(gr_ore_poly_t res, const gr_ore_poly_t poly1, const gr_ore_poly_t poly2, gr_ore_poly_ctx_t ctx) +{ + return gr_poly_sub((gr_poly_struct *) res, (const gr_poly_struct *) poly1, (const gr_poly_struct *) poly2, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +int +gr_ore_poly_add_other(gr_ore_poly_t res, const gr_ore_poly_t poly, gr_srcptr x, gr_ctx_t x_ctx, gr_ore_poly_ctx_t ctx) +{ + if (x_ctx == ctx) { + return gr_poly_add((gr_poly_struct *) res, (const gr_poly_struct *) poly, x, GR_ORE_POLY_ELEM_CTX(ctx)); + } else if (x_ctx == GR_ORE_POLY_ELEM_CTX(ctx)) { + return gr_poly_add_scalar((gr_poly_struct *) res, (const gr_poly_struct *) poly, x, GR_ORE_POLY_ELEM_CTX(ctx)); + } else if (GR_ORE_POLY_CTX(ctx)->base_ring->which_ring == GR_CTX_GR_POLY && \ + POLYNOMIAL_CTX(GR_ORE_POLY_CTX(ctx)->base_ring)->base_ring == x_ctx) { + gr_poly_t tmp; + tmp->coeffs = (gr_ptr) x; + tmp->length = 1; + tmp->alloc = 1; + return gr_poly_add_scalar((gr_poly_struct *) poly, (gr_poly_struct *) poly, tmp, GR_ORE_POLY_ELEM_CTX(ctx)); + } else if (x_ctx->which_ring == GR_CTX_FMPZ) { + return gr_poly_add_fmpz((gr_poly_struct *) res, (const gr_poly_struct *) poly, x, GR_ORE_POLY_ELEM_CTX(ctx)); + } else if (x_ctx->which_ring == GR_CTX_FMPQ) { + return gr_poly_add_fmpq((gr_poly_struct *) res, (const gr_poly_struct *) poly, x, GR_ORE_POLY_ELEM_CTX(ctx)); + } + return GR_UNABLE; +} + +int +gr_ore_poly_add_ui(gr_ore_poly_t res, const gr_ore_poly_t poly, ulong c, gr_ore_poly_ctx_t ctx) +{ + return gr_poly_add_ui((gr_poly_struct *) res, (const gr_poly_struct *) poly, c, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +int +gr_ore_poly_add_si(gr_ore_poly_t res, const gr_ore_poly_t poly, slong c, gr_ore_poly_ctx_t ctx) +{ + return gr_poly_add_si((gr_poly_struct *) res, (const gr_poly_struct *) poly, c, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +int +gr_ore_poly_add_fmpz(gr_ore_poly_t res, const gr_ore_poly_t poly, const fmpz_t c, gr_ore_poly_ctx_t ctx) +{ + return gr_poly_add_fmpz((gr_poly_struct *) res, (const gr_poly_struct *) poly, c, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +int +gr_ore_poly_add_fmpq(gr_ore_poly_t res, const gr_ore_poly_t poly, const fmpq_t c, gr_ore_poly_ctx_t ctx) +{ + return gr_poly_add_fmpq((gr_poly_struct *) res, (const gr_poly_struct *) poly, c, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +int +gr_ore_poly_sub_other(gr_ore_poly_t res, const gr_ore_poly_t poly, gr_srcptr x, gr_ctx_t x_ctx, gr_ore_poly_ctx_t ctx) +{ + if (x_ctx == ctx) { + return gr_poly_sub((gr_poly_struct *) res, (const gr_poly_struct *) poly, x, GR_ORE_POLY_ELEM_CTX(ctx)); + } else if (x_ctx == GR_ORE_POLY_ELEM_CTX(ctx)) { + return gr_poly_sub_scalar((gr_poly_struct *) res, (gr_poly_struct *) poly, x, GR_ORE_POLY_ELEM_CTX(ctx)); + } else if (GR_ORE_POLY_CTX(ctx)->base_ring->which_ring == GR_CTX_GR_POLY && \ + POLYNOMIAL_CTX(GR_ORE_POLY_CTX(ctx)->base_ring)->base_ring == x_ctx) { + gr_poly_t tmp; + tmp->coeffs = (gr_ptr) x; + tmp->length = 1; + tmp->alloc = 1; + return gr_poly_sub_scalar((gr_poly_struct *) poly, (gr_poly_struct *) poly, tmp, GR_ORE_POLY_ELEM_CTX(ctx)); + } else if (x_ctx->which_ring == GR_CTX_FMPZ) { + return gr_poly_sub_fmpz((gr_poly_struct *) res, (const gr_poly_struct *) poly, x, GR_ORE_POLY_ELEM_CTX(ctx)); + } else if (x_ctx->which_ring == GR_CTX_FMPQ) { + return gr_poly_sub_fmpq((gr_poly_struct *) res, (const gr_poly_struct *) poly, x, GR_ORE_POLY_ELEM_CTX(ctx)); + } + return GR_UNABLE; +} + +int +gr_ore_poly_sub_ui(gr_ore_poly_t res, const gr_ore_poly_t poly, ulong c, gr_ore_poly_ctx_t ctx) +{ + return gr_poly_sub_ui((gr_poly_struct *) res, (const gr_poly_struct *) poly, c, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +int +gr_ore_poly_sub_si(gr_ore_poly_t res, const gr_ore_poly_t poly, slong c, gr_ore_poly_ctx_t ctx) +{ + return gr_poly_sub_si((gr_poly_struct *) res, (const gr_poly_struct *) poly, c, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +int +gr_ore_poly_sub_fmpz(gr_ore_poly_t res, const gr_ore_poly_t poly, const fmpz_t c, gr_ore_poly_ctx_t ctx) +{ + return gr_poly_sub_fmpz((gr_poly_struct *) res, (const gr_poly_struct *) poly, c, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +int +gr_ore_poly_sub_fmpq(gr_ore_poly_t res, const gr_ore_poly_t poly, const fmpq_t c, gr_ore_poly_ctx_t ctx) +{ + return gr_poly_sub_fmpq((gr_poly_struct *) res, (const gr_poly_struct *) poly, c, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +int +gr_ore_poly_other_mul(gr_ore_poly_t res, gr_srcptr x, gr_ctx_t x_ctx, const gr_ore_poly_t poly, gr_ore_poly_ctx_t ctx) +{ + if (x_ctx == ctx) { + /* TODO: Multiplication of Ore polynomials. */ + return GR_UNABLE; + } else if (x_ctx == GR_ORE_POLY_ELEM_CTX(ctx)) { + return gr_poly_scalar_mul((gr_poly_struct *) res, x, (const gr_poly_struct *) poly, GR_ORE_POLY_ELEM_CTX(ctx)); + } else if (GR_ORE_POLY_CTX(ctx)->base_ring->which_ring == GR_CTX_GR_POLY && \ + POLYNOMIAL_CTX(GR_ORE_POLY_CTX(ctx)->base_ring)->base_ring == x_ctx) { + gr_poly_t tmp; + tmp->coeffs = (gr_ptr) x; + tmp->length = 1; + tmp->alloc = 1; + return gr_poly_scalar_mul((gr_poly_struct *) poly, tmp, (const gr_poly_struct *) poly, GR_ORE_POLY_ELEM_CTX(ctx)); + } else if (x_ctx->which_ring == GR_CTX_FMPZ) { + return gr_poly_mul_fmpz((gr_poly_struct *) res, (const gr_poly_struct *) poly, x, GR_ORE_POLY_ELEM_CTX(ctx)); + } else if (x_ctx->which_ring == GR_CTX_FMPQ) { + return gr_poly_mul_fmpq((gr_poly_struct *) res, (const gr_poly_struct *) poly, x, GR_ORE_POLY_ELEM_CTX(ctx)); + } + return GR_UNABLE; +} + +int +gr_ore_poly_mul_ui(gr_ore_poly_t res, const gr_ore_poly_t poly, ulong c, gr_ore_poly_ctx_t ctx) +{ + return gr_poly_mul_ui((gr_poly_struct *) res, (const gr_poly_struct *) poly, c, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +int +gr_ore_poly_mul_si(gr_ore_poly_t res, const gr_ore_poly_t poly, slong c, gr_ore_poly_ctx_t ctx) +{ + return gr_poly_mul_si((gr_poly_struct *) res, (const gr_poly_struct *) poly, c, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +int +gr_ore_poly_mul_fmpz(gr_ore_poly_t res, const gr_ore_poly_t poly, const fmpz_t c, gr_ore_poly_ctx_t ctx) +{ + return gr_poly_mul_fmpz((gr_poly_struct *) res, (const gr_poly_struct *) poly, c, GR_ORE_POLY_ELEM_CTX(ctx)); +} + +int +gr_ore_poly_mul_fmpq(gr_ore_poly_t res, const gr_ore_poly_t poly, const fmpq_t c, gr_ore_poly_ctx_t ctx) +{ + return gr_poly_mul_fmpq((gr_poly_struct *) res, (const gr_poly_struct *) poly, c, GR_ORE_POLY_ELEM_CTX(ctx)); +} diff --git a/src/gr_ore_poly/sigma_delta.c b/src/gr_ore_poly/sigma_delta.c new file mode 100644 index 0000000000..0a6b93a14d --- /dev/null +++ b/src/gr_ore_poly/sigma_delta.c @@ -0,0 +1,232 @@ +#include "gr_poly.h" +#include "gr_ore_poly.h" + +/* gr_poly/compose.c */ +int _gr_poly_inflate(gr_ptr poly, slong len, slong n, gr_ctx_t ctx); + +int +sigma_delta_unable(gr_ptr sigma, gr_ptr delta, + gr_srcptr a, + gr_ore_poly_ctx_struct * ctx) +{ + return GR_UNABLE; +} + +int +sigma_delta_commutative(gr_ptr sigma, gr_ptr delta, + gr_srcptr a, + gr_ore_poly_ctx_struct * ctx) +{ + gr_ctx_ptr cctx = GR_ORE_POLY_ELEM_CTX(ctx); + int status = GR_SUCCESS; + + if (sigma != NULL && sigma != a) + status |= gr_set(sigma, a, cctx); + + if (delta != NULL) + status |= gr_zero(delta, cctx); + + return status; +} + +int +sigma_delta_derivative(gr_ptr sigma, gr_ptr delta, + gr_srcptr a, + gr_ore_poly_ctx_struct * ctx) +{ + gr_ctx_struct * cctx = GR_ORE_POLY_ELEM_CTX(ctx); + /* todo: gr_derivative taking a generator index? */ + if (cctx->which_ring != GR_CTX_GR_POLY) + return GR_UNABLE; + + int status = GR_SUCCESS; + + if (sigma != NULL && sigma != a) + status |= gr_set(sigma, a, cctx); + + if (delta != NULL) + status |= gr_poly_derivative(delta, a, POLYNOMIAL_ELEM_CTX(cctx)); + + return status; +} + +int +sigma_delta_euler_derivative(gr_ptr sigma, gr_ptr delta, + gr_srcptr a, + gr_ore_poly_ctx_struct * ctx) +{ + int status = GR_SUCCESS; + gr_ctx_struct * cctx = GR_ORE_POLY_ELEM_CTX(ctx); + if (cctx->which_ring != GR_CTX_GR_POLY) + return GR_UNABLE; + + /* - for polynomial base rings, could call _gr_poly_derivative and avoid the + * post-shift + * - gr_euler_derivative for arbitrary rings??? */ + + status |= sigma_delta_derivative(sigma, delta, a, ctx); + + if (status == GR_SUCCESS && delta != NULL) + status |= gr_poly_shift_left(delta, delta, 1, POLYNOMIAL_ELEM_CTX(cctx)); + + return status; +} + +static int +sigma_delta_shift_si(gr_ptr sigma, gr_ptr delta, + gr_srcptr a, slong shift, slong difference, + gr_ore_poly_ctx_struct * ctx) +{ + gr_ctx_struct * cctx = GR_ORE_POLY_ELEM_CTX(ctx); + if (cctx->which_ring != GR_CTX_GR_POLY) + return GR_UNABLE; + gr_ctx_struct * sctx = POLYNOMIAL_ELEM_CTX(cctx); + + int status = GR_SUCCESS; + + gr_ptr _shift; + gr_poly_t shifted; + GR_TMP_INIT(_shift, sctx); + gr_poly_init(shifted, sctx); + + status |= gr_set_si(_shift, shift, sctx); + status |= gr_poly_taylor_shift(shifted, a, _shift, sctx); + + if (delta != NULL) + { + if (difference == 0) + status |= gr_zero(delta, cctx); + else if (difference == 1) + status |= gr_poly_sub(delta, shifted, a, sctx); + else if (difference == -1) + status |= gr_poly_sub(delta, a, shifted, sctx); + } + + if (sigma != NULL) + gr_swap(sigma, shifted, cctx); + + gr_poly_clear(shifted, sctx); + GR_TMP_CLEAR(_shift, sctx); + + return status; +} + +int +sigma_delta_forward_shift(gr_ptr sigma, gr_ptr delta, + gr_srcptr a, + gr_ore_poly_ctx_struct * ctx) +{ + return sigma_delta_shift_si(sigma, delta, a, +1, 0, ctx); +} + +int +sigma_delta_backward_shift(gr_ptr sigma, gr_ptr delta, + gr_srcptr a, + gr_ore_poly_ctx_struct * ctx) +{ + return sigma_delta_shift_si(sigma, delta, a, -1, 0, ctx); +} + +int +sigma_delta_forward_difference(gr_ptr sigma, gr_ptr delta, + gr_srcptr a, + gr_ore_poly_ctx_struct * ctx) +{ + return sigma_delta_shift_si(sigma, delta, a, +1, +1, ctx); +} + +int +sigma_delta_backward_difference(gr_ptr sigma, gr_ptr delta, + gr_srcptr a, + gr_ore_poly_ctx_struct * ctx) +{ + return sigma_delta_shift_si(sigma, delta, a, -1, -1, ctx); +} + +int +sigma_delta_compose(gr_ptr sigma, gr_ptr delta, + gr_srcptr a, + gr_ore_poly_ctx_struct * ctx) +{ + gr_ctx_struct * cctx = GR_ORE_POLY_ELEM_CTX(ctx); + if (cctx->which_ring != GR_CTX_GR_POLY) + return GR_UNABLE; + gr_ctx_struct * sctx = POLYNOMIAL_ELEM_CTX(cctx); + + int status = GR_SUCCESS; + + if (sigma != NULL) + status |= gr_poly_compose(sigma, a, GR_ORE_POLY_ORE_DATA(ctx)->sigma_x, sctx); + + if (delta != NULL) + status |= gr_zero(delta, cctx); + + return status; +} + +int +sigma_delta_mahler(gr_ptr sigma, gr_ptr delta, + gr_srcptr a, + gr_ore_poly_ctx_struct * ctx) +{ + gr_ctx_struct * cctx = GR_ORE_POLY_ELEM_CTX(ctx); + if (cctx->which_ring != GR_CTX_GR_POLY) + return GR_UNABLE; + gr_ctx_struct * sctx = POLYNOMIAL_ELEM_CTX(cctx); + + int status = GR_SUCCESS; + + if (sigma != NULL) + { + gr_poly_struct * _sigma = sigma; + slong b = GR_ORE_POLY_ORE_DATA(ctx)->mahler_base; + status |= gr_set(sigma, a, cctx); + if (_sigma->length > 1) + { + slong newlen = (_sigma->length - 1) * b + 1; + gr_poly_fit_length(sigma, newlen, sctx); + status |= _gr_poly_inflate(_sigma->coeffs, _sigma->length, b, sctx); + gr_poly_fit_length(sigma, newlen, sctx); + _gr_poly_set_length(sigma, newlen, sctx); + _gr_poly_normalise(sigma, sctx); + } + } + + if (delta != NULL) + status |= gr_zero(delta, cctx); + + return status; +} + +int +sigma_delta_frobenius(gr_ptr sigma, gr_ptr delta, + gr_srcptr a, + gr_ore_poly_ctx_struct * ctx) +{ + gr_ctx_ptr cctx = GR_ORE_POLY_ELEM_CTX(ctx); + int status = GR_SUCCESS; + + if (sigma != NULL) + status |= gr_fq_frobenius(sigma, a, 1, cctx); + + if (delta != NULL) + status |= gr_zero(delta, cctx); + + return status; +} + +const gr_ore_poly_sigma_delta_t _gr_ore_poly_default_sigma_delta[] = +{ + [ORE_ALGEBRA_CUSTOM] = sigma_delta_unable, + [ORE_ALGEBRA_COMMUTATIVE] = sigma_delta_commutative, + [ORE_ALGEBRA_DERIVATIVE] = sigma_delta_derivative, + [ORE_ALGEBRA_EULER_DERIVATIVE] = sigma_delta_euler_derivative, + [ORE_ALGEBRA_FORWARD_SHIFT] = sigma_delta_forward_shift, + [ORE_ALGEBRA_FORWARD_DIFFERENCE] = sigma_delta_forward_difference, + [ORE_ALGEBRA_BACKWARD_SHIFT] = sigma_delta_backward_shift, + [ORE_ALGEBRA_BACKWARD_DIFFERENCE] = sigma_delta_backward_difference, + [ORE_ALGEBRA_Q_SHIFT] = sigma_delta_compose, + [ORE_ALGEBRA_MAHLER] = sigma_delta_mahler, + [ORE_ALGEBRA_FROBENIUS] = sigma_delta_frobenius, + [ORE_POLY_NUM_ALGEBRAS] = NULL, +}; diff --git a/src/gr_ore_poly/test/main.c b/src/gr_ore_poly/test/main.c new file mode 100644 index 0000000000..bb27782d88 --- /dev/null +++ b/src/gr_ore_poly/test/main.c @@ -0,0 +1,29 @@ +/* + Copyright (C) 2025 Ricardo Buring + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. See . +*/ + +/* Include functions *********************************************************/ + +#include "t-ring.c" +#include "t-set_str.c" +#include "t-sigma_delta.c" + +/* Array of test functions ***************************************************/ + +test_struct tests[] = +{ + TEST_FUNCTION(gr_ore_poly_ring), + TEST_FUNCTION(gr_ore_poly_set_str), + TEST_FUNCTION(gr_ore_poly_sigma_delta), +}; + +/* main function *************************************************************/ + +TEST_MAIN(tests) diff --git a/src/gr_ore_poly/test/t-ring.c b/src/gr_ore_poly/test/t-ring.c new file mode 100644 index 0000000000..82768e04f9 --- /dev/null +++ b/src/gr_ore_poly/test/t-ring.c @@ -0,0 +1,67 @@ +/* + Copyright (C) 2025 Ricardo Buring + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. See . +*/ + +#include "test_helpers.h" +#include "gr_vec.h" +#include "gr_ore_poly.h" + +/* This is mostly a copy of src/gr_mpoly/test/t-ring.c */ + +FLINT_DLL extern gr_static_method_table _ca_methods; + +TEST_FUNCTION_START(gr_ore_poly_ring, state) +{ + slong iter; + + for (iter = 0; iter < 30 * flint_test_multiplier(); iter++) + { + gr_ctx_t ctx; + gr_ore_poly_ctx_t ore_ctx; + slong reps; + + gr_ore_poly_ctx_init_randtest2(ctx, ore_ctx, state); + + if (gr_ctx_is_finite(ctx) == T_TRUE || + gr_ctx_has_real_prec(ctx) == T_TRUE) + { + reps = 10; + } + else if (ctx->methods == _ca_methods) /* hack: slow */ + { + reps = 1; + } + else + { + reps = 3; + } + + /* Hack: for string conversion tests, make sure we don't have + overlapping generator names. */ + gr_vec_t vec; + gr_vec_init(vec, 0, ctx); + if (gr_gens_recursive(vec, ctx) == GR_SUCCESS) + { + const char * vars[] = { "DD" }; + + GR_MUST_SUCCEED(gr_ctx_set_gen_names(ore_ctx, vars)); + + } + gr_vec_clear(vec, ctx); + + /* gr_ctx_println(ore_ctx); */ + gr_test_ring(ore_ctx, reps, 0 * GR_TEST_VERBOSE); + + gr_ore_poly_ctx_clear(ore_ctx); + gr_ctx_clear(ctx); + } + + TEST_FUNCTION_END(state); +} diff --git a/src/gr_ore_poly/test/t-set_str.c b/src/gr_ore_poly/test/t-set_str.c new file mode 100644 index 0000000000..4a6418b550 --- /dev/null +++ b/src/gr_ore_poly/test/t-set_str.c @@ -0,0 +1,81 @@ +/* + Copyright (C) 2025 Ricardo Buring + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. See . +*/ + +#include "test_helpers.h" +#include "gr_ore_poly.h" + +/* This is mostly a copy of src/gr_poly/test/t-set_str.c */ + +TEST_FUNCTION_START(gr_ore_poly_set_str, state) +{ + slong iter; + + for (iter = 0; iter < 1000 * flint_test_multiplier(); iter++) + { + int status = GR_SUCCESS; + gr_ctx_t ctx; + gr_ore_poly_ctx_t ore_ctx; + gr_ore_poly_t f, g; + slong glen; + char * s; + + gr_ore_poly_ctx_init_randtest2(ctx, ore_ctx, state); + gr_ore_poly_init(f, ore_ctx); + gr_ore_poly_init(g, ore_ctx); + + status |= gr_ore_poly_randtest(f, state, 1 + n_randint(state, 10), ore_ctx); + status |= gr_ore_poly_randtest(g, state, 1 + n_randint(state, 10), ore_ctx); + + if (n_randint(state, 2)) + { + status |= gr_ore_poly_get_str(&s, f, ore_ctx); + status |= gr_ore_poly_set_str(g, s, ore_ctx); + glen = -1; + + if ((ctx->which_ring == GR_CTX_FMPZ || ctx->which_ring == GR_CTX_FMPQ) && + status != GR_SUCCESS) + { + flint_printf("FAIL: unable over ZZ or QQ\n\n"); + flint_printf("f = %{gr_ore_poly}\n\n", f, ctx); + flint_printf("s = %s\n\n", s); + flint_abort(); + } + } + else + { + status |= _gr_ore_poly_get_str(&s, f->coeffs, f->length, ore_ctx); + glen = n_randint(state, 10); + gr_ore_poly_fit_length(g, glen, ore_ctx); + status |= _gr_ore_poly_set_str(g->coeffs, s, glen, ore_ctx); + _gr_ore_poly_set_length(g, glen, ore_ctx); + _gr_ore_poly_normalise(g, ore_ctx); + } + + if (status == GR_SUCCESS && gr_ore_poly_equal(f, g, ore_ctx) == T_FALSE) + { + flint_printf("FAIL: get_str, set_str roundtrip\n\n"); + flint_printf("f = %{gr_ore_poly}\n\n", f, ore_ctx); + flint_printf("s = %s\n\n", s); + flint_printf("glen = %wd\n\n", glen); + flint_printf("g = %{gr_ore_poly}\n\n", g, ore_ctx); + flint_abort(); + } + + flint_free(s); + + gr_ore_poly_clear(f, ore_ctx); + gr_ore_poly_clear(g, ore_ctx); + gr_ctx_clear(ore_ctx); + gr_ctx_clear(ctx); + } + + TEST_FUNCTION_END(state); +} diff --git a/src/gr_ore_poly/test/t-sigma_delta.c b/src/gr_ore_poly/test/t-sigma_delta.c new file mode 100644 index 0000000000..7ce7d343e9 --- /dev/null +++ b/src/gr_ore_poly/test/t-sigma_delta.c @@ -0,0 +1,156 @@ +/* + Copyright (C) 2025 Marc Mezzarobba + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. See . +*/ + +#include "test_helpers.h" +#include "gr_ore_poly.h" + +FLINT_DLL extern gr_static_method_table _ca_methods; + +TEST_FUNCTION_START(gr_ore_poly_sigma_delta, state) +{ + for (slong iter = 0; iter < 1000 * flint_test_multiplier(); iter++) + { + gr_ctx_t cctx, ctx; + + gr_ore_poly_ctx_init_randtest2(cctx, ctx, state); + + gr_ptr a = gr_heap_init(cctx); + gr_ptr b = gr_heap_init(cctx); + gr_ptr c = gr_heap_init(cctx); + gr_ptr sa = gr_heap_init(cctx); + gr_ptr sb = gr_heap_init(cctx); + gr_ptr sc = gr_heap_init(cctx); + gr_ptr sc1 = gr_heap_init(cctx); + gr_ptr da = gr_heap_init(cctx); + gr_ptr db = gr_heap_init(cctx); + gr_ptr dc = gr_heap_init(cctx); + gr_ptr dc1 = gr_heap_init(cctx); + + int status = GR_SUCCESS; + + status |= gr_randtest(a, state, cctx); + status |= gr_randtest(b, state, cctx); + + int call = n_randint(state, 4); + switch (call) + { + case 0: + status |= gr_ore_poly_sigma_delta(sa, da, a, ctx); + break; + case 1: + status |= gr_ore_poly_sigma(sa, a, ctx); + status |= gr_ore_poly_delta(da, a, ctx); + break; + case 2: + status |= gr_set(sa, a, cctx); + status |= gr_ore_poly_sigma_delta(sa, da, sa, ctx); + break; + case 3: + status |= gr_set(da, a, cctx); + status |= gr_ore_poly_sigma_delta(sa, da, da, ctx); + break; + default: + FLINT_ASSERT(0); + } + + status |= gr_ore_poly_sigma_delta(sb, db, b, ctx); + + if (status != GR_SUCCESS) + { + if (cctx->which_ring == GR_CTX_GR_POLY) + { + switch (POLYNOMIAL_CTX(cctx)->base_ring->which_ring) + { + case GR_CTX_FMPZ: + case GR_CTX_FMPQ: + break; + default: + goto cleanup; + } + switch (GR_ORE_POLY_CTX(ctx)->which_algebra) + { + case ORE_ALGEBRA_COMMUTATIVE: + case ORE_ALGEBRA_DERIVATIVE: + case ORE_ALGEBRA_EULER_DERIVATIVE: + case ORE_ALGEBRA_FORWARD_SHIFT: + case ORE_ALGEBRA_FORWARD_DIFFERENCE: + case ORE_ALGEBRA_BACKWARD_SHIFT: + case ORE_ALGEBRA_BACKWARD_DIFFERENCE: + case ORE_ALGEBRA_Q_SHIFT: + case ORE_ALGEBRA_MAHLER: + flint_printf("FAIL: unexpected failure\n"); + flint_abort(); + default: + goto cleanup; + } + } + goto cleanup; + } + + status = gr_add(c, a, b, cctx); + status |= gr_ore_poly_sigma_delta(sc, dc, c, ctx); + + if (status == GR_SUCCESS) + { + status = gr_add(sc1, sa, sb, cctx); + if (status == GR_SUCCESS && gr_equal(sc, sc1, cctx) == T_FALSE) + { + flint_printf("FAIL: σ(a + b) = σ(a) + σ(b)\n"); + flint_abort(); + } + + status = gr_add(dc1, da, db, cctx); + if (status == GR_SUCCESS && gr_equal(dc, dc1, cctx) == T_FALSE) + { + flint_printf("FAIL: δ(a + b) = δ(a) + δ(b)\n"); + flint_abort(); + } + } + + status = gr_mul(c, a, b, cctx); + status |= gr_ore_poly_sigma_delta(sc, dc, c, ctx); + + if (status == GR_SUCCESS) + { + status |= gr_mul(sc1, sa, sb, cctx); + if (status == GR_SUCCESS && gr_equal(sc, sc1, cctx) == T_FALSE) + { + flint_printf("FAIL: σ(a·b) = σ(a)·σ(b)\n"); + flint_abort(); + } + + status |= gr_mul(dc1, da, b, cctx); + status |= gr_addmul(dc1, sa, db, cctx); + if (status == GR_SUCCESS && gr_equal(dc, dc1, cctx) == T_FALSE) + { + flint_printf("FAIL: δ(a·b) = δ(a)·b + σ(a)·δ(b)\n"); + flint_abort(); + } + } + +cleanup: + gr_heap_clear(dc1, cctx); + gr_heap_clear(dc, cctx); + gr_heap_clear(db, cctx); + gr_heap_clear(da, cctx); + gr_heap_clear(sc1, cctx); + gr_heap_clear(sc, cctx); + gr_heap_clear(sb, cctx); + gr_heap_clear(sa, cctx); + gr_heap_clear(c, cctx); + gr_heap_clear(b, cctx); + gr_heap_clear(a, cctx); + gr_ore_poly_ctx_clear(ctx); + gr_ctx_clear(cctx); + } + + TEST_FUNCTION_END(state); +} diff --git a/src/gr_poly/compose.c b/src/gr_poly/compose.c index 111d57f17c..60cc300942 100644 --- a/src/gr_poly/compose.c +++ b/src/gr_poly/compose.c @@ -14,16 +14,31 @@ #include "gr_vec.h" #include "gr_poly.h" +int +_gr_poly_inflate(gr_ptr poly, slong len, slong n, gr_ctx_t ctx) +{ + slong i, sz = ctx->sizeof_elem; + int status = GR_SUCCESS; + + for (i = len - 1; i >= 1 && n > 1; i--) + { + gr_swap(GR_ENTRY(poly, i * n, sz), GR_ENTRY(poly, i, sz), ctx); + status |= _gr_vec_zero(GR_ENTRY(poly, (i - 1) * n + 1, sz), n - 1, ctx); + } + + return status; +} + /* compose by poly2 = a*x^n + c, no aliasing; n >= 1 */ int _gr_poly_compose_axnc(gr_ptr res, gr_srcptr poly1, slong len1, gr_srcptr c, gr_srcptr a, slong n, gr_ctx_t ctx) { slong i, sz = ctx->sizeof_elem; - int status; + int status = GR_SUCCESS; /* shift by c (c = 0 case will be fast) */ - status = _gr_poly_taylor_shift(res, poly1, len1, c, ctx); + status |= _gr_poly_taylor_shift(res, poly1, len1, c, ctx); /* multiply by powers of a */ if (gr_is_one(a, ctx) != T_TRUE) @@ -56,11 +71,7 @@ _gr_poly_compose_axnc(gr_ptr res, gr_srcptr poly1, slong len1, } /* stretch */ - for (i = len1 - 1; i >= 1 && n > 1; i--) - { - gr_swap(GR_ENTRY(res, i * n, sz), GR_ENTRY(res, i, sz), ctx); - status |= _gr_vec_zero(GR_ENTRY(res, (i - 1) * n + 1, sz), n - 1, ctx); - } + status |= _gr_poly_inflate(res, len1, n, ctx); return status; }