Add generic Ore polynomial module
This contains only the basic structure so far, such as memory management, additive arithmetic, and multiplication from the left by an element of the base ring.
- Part of https://github.com/flintlib/flint/issues/1881
Feedback welcome!
We would like to use this data type as input to differential equation solvers, so we don't need the multiplicative structure initially, though it would be nice to have it in the future.
Multiplicative operations (to be defined later) depend on the Ore context object, so I figured that all operations should take the Ore context as input, to make the interface uniform. So now the interface looks like gr_mpoly, and the basic operations implemented so far call gr_poly methods.
~~Since the base ring will typically be polynomial, should gr_ore_poly_scalar_mul and GR_ORE_POLY_ELEM_CTX be named differently? Maybe using base / BASE?~~
~~I also tried to make the module "optional" in the sense that gr_mpoly is, let me know if I missed something in this regard.~~
cc @mezzarobba
On Saturday, 12 April 2025 Ricardo Buring wrote:
+typedef enum {
- ORE_OPERATOR_DERIVATIVE,
- ORE_OPERATOR_EULER_DERIVATIVE,
- /* TODO: Shift operator, etc. */ +} +ore_operator_t;
I named this enum (and the value prefix) improperly. What should the name be?
Maybe gr_ore_poly_which_operator, for consistency with gr_which_structure?
-- Marc
Some/most of the arithmetic/setter methods (gr_ore_poly_add for example) are not getting called in the ring tests.
I'm not sure what I did wrong since I did put them in the method table.
Edit: Never mind, I put some NULL pointers in there which is not allowed except to indicate the end of the table.
So, working with Ore polynomials over say R[x], one might indeed want to do mixed operations with operands from either R or R[x]. The term "scalar" being ambiguous, instead of adding many extra methods, perhaps just define gr_ore_poly_add_other etc. that handles all cases?
I don't see the need for ore_poly.h and ore_poly_types.h.
Most of the one-line trivial methods could go in a single file.
Multiplicative operations (to be defined later) depend on the Ore context object, so I figured that all operations should take the Ore context as input, to make the interface uniform.
Yes, this is the right way to do it. The way gr_poly and gr_mat work directly with the element context is an exception rather than the rule, and at some point we should add a public interface for those types using a poly/mat context as well.
I reorganized the code to collect the wrapper functions in one file, and applied all the other suggestions above. I removed all the methods with scalar in the name and added some other methods, indeed this looks much better.
Let me know if this needs any further changes.
Looks good. The only thing missing is documentation.
Something that doesn't seem to be well specified in the documentation is the generator name (set_gen_name / string conversion methods). If I'm in R[x][D], say, shouldn't x already be named the base ring while the Ore ring generator is D?
In fact, shouldn't the generator x (given as an element of the base ring) be a parameter to the Ore polynomial ring constructor? In general, the base ring could be something multivariate.
I updated the context and constructor to include an index of a generator of the base ring, and (hopefully) clarified the documentation. I think the restriction to generators of the base ring (rather than elements of the base ring) is reasonable, and e.g. in the univariate case it saves the user from having to define a variable that will probably never be used (e.g. multiplication by the variable will be replaced by a shift). Let me know if this is alright.
On Tuesday, 29 April 2025 Ricardo Buring wrote:
@rburing requested your review on: flintlib/flint#2299 Add generic Ore polynomial module.
Sure, I can take a look, but maybe not before next week. Thanks for your work on this!
Another question: How should the q parameter for q-shifts or q-derivations be handled? The current gr_ctx_init_gr_ore_poly and the struct _gr_ore_poly_ctx_struct do not refer to it. Can this be left for later? I guess the main question is: do we want to put an extra parameter (again an index into the list of generators or a gr_srcptr?) already in gr_ctx_init_gr_ore_poly, or add a separate second constructor later (or break source compatibility by adding an extra parameter to gr_ctx_init_gr_ore_poly later)?
Either add a q-parameter which is allowed to be NULL, or add a separate constructor gr_ctx_init_gr_ore_poly_q_twist or whatever later for this case. I don't think it matters much which solution you choose.
I think the restriction to generators of the base ring (rather than elements of the base ring) is reasonable
There are definitely cases where one wants to work with derivations like x²·d/dx or operators relative to a generator of the base ring of the base ring, but they can probably be handled by a future “Ore twist as function pointer” mechanism.
Btw, what do you think about calling (σ,δ) the “(Ore) twist” instead of the “(Ore) operator”? I suppose “twist” would more properly refer to σ alone, but that would avoid some overloading of the word “operator”.
I'm also wondering if just gr_ore would be a better prefix than gr_ore_poly. OTOH gr_more for a potential future multivariate version may be confusing.
Thanks for the extensive feedback @mezzarobba, I think it looks better now.
What do you think about using the name ore_algebra_t for the enum? With values ORE_ALGEBRA_STANDARD_DERIVATIVE and ORE_ALGEBRA_EULER_DERIVATIVE for now.
@fredrik-johansson Should I keep entry in the name of gr_ore_poly_entry_ptr for consistency with gr_poly, or use coeff instead?
I think the gr_poly method is misnamed and should use coeff as well.
What do you think about using the name
ore_algebra_tfor the enum? With valuesORE_ALGEBRA_STANDARD_DERIVATIVEandORE_ALGEBRA_EULER_DERIVATIVEfor now.
Sounds good too. I think I would call d/dx DERIVATIVE instead of STANDARD_DERIVATIVE, and you could add SHIFT (or maybe FORWARD_SHIFT) and FORWARD_DIFFERENCE right away.
I added support for general (σ,δ) and implemented a number of standard (σ,δ) pairs, see https://github.com/mezzarobba/flint/tree/gr_ore_poly. Any feedback welcome. (Ricardo, feel free to merge my branch into this PR if you like.)
I should add that most predefined operator types are currently limited to base rings of type gr_poly but this restriction should be easy to lift if a few methods like gr_derivative or gr_subs are added to the general interface of generic rings. (I didn't want to embark in that now.)