Skip to content

access to generator names #2314

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open

Conversation

mezzarobba
Copy link
Contributor

An API for accessing generator names.

This includes some debatable choices. Most importantly, I am treating contexts as containers as regards generator names (not using status flags, providing pointers to names owned by the context rather than writing to a separate buffer), which basically makes it impossible to write a context that generates the names on the fly and does not want to store them forever. Also, the method for accessing the names returns an array of generator names rather than individual names.

@fredrik-johansson
Copy link
Collaborator

I'd rather have an API that preserves the ability for contexts to generate names on the fly.

@mezzarobba
Copy link
Contributor Author

Ok, thanks. Would this version be acceptable with gr_ctx_gen_names_srcptr renamed to _gr_ctx_gen_names_srcptr (or _ptr, dropping the consts) and an explicit warning that it may not be implemented by all contexts? The other options I can think of make it a bit cumbersome to do simple thinks like copying the generator names of a ring to another one.

@fredrik-johansson
Copy link
Collaborator

What is the exact use case here? What is the problem with returning newly allocated strings?

@mezzarobba
Copy link
Contributor Author

In general, I would like to have a way of accessing the names of the generators. In practice, in the cases I am really interested in, I could probably just call gr_gens() and print each generator to a string, but there is no reason in general that a generator prints to just its name.

A concrete use case is for changing the base ring of a polynomial ring.

There is no real problem with returning newly allocated strings, it just feels a bit complicated when in 99% of cases a pointer to the existing names array would do the job. Take the previous example: either you return the generators one by one and the user must arrange them in an array to call gr_ctx_set_gen_names. Or you return them all at once but then you need the infrastructure for the user to free an array of strings: either have them allocate the array and loop over it to free the individual strings, or provide dedicated objects with associated init/free functions, or write everything in a single malloc'd buffer. All doable but all a bit impractical IMO. But maybe I am missing something obvious!

@fredrik-johansson
Copy link
Collaborator

I could probably just call gr_gens() and print each generator to a string, but there is no reason in general that a generator prints to just its name.

Indeed, and this is already an issue:

>>> R = PowerSeriesModRing(ZZ, 3)
>>> R.gen()
x (mod x^3)
>>> R("x")
Traceback (most recent call last):
...
FlintUnableError: unable to create element of Power series over Integer ring (fmpz) mod x^3 from x of type <class 'str'>

For that reason, a method to return the generator names would indeed be useful.

However, I'm still not sure about returning names by reference.

Something to consider: gr_ctx_init_gr_poly and gr_ctx_init_gr_mpoly choose a default variable name so that creating the context object doesn't require a string allocation. But obviously as soon as you start printing you don't want to your nested ring to be $R[x][x][x]$. Perhaps a better solution would be to look at the recursive generators of the coefficient ring and choosing something not in that list so that you automatically get $R[x][y][z]$ or whatever. However, this should arguably be done on demand when printing or parsing rather than when constructing the ring. This means one can't guarantee that there is a persistent default variable string to point to.

All doable but all a bit impractical IMO. But maybe I am missing something obvious!

Not really, I think allocating temporary arrays and allocating new strings is the least hacky way to do it.

For internal use, life would be easier if we had a memory-managed flint_string_t. But then everyone downstream would just end up needing their own conversions between FLINT strings and C strings...

@mezzarobba
Copy link
Contributor Author

Do you prefer

  • slong gr_ctx_ngens(gr_ctx_t) or int gr_ctx_ngens(slong * gr_ctx_t)?
  • int gr_ctx_gen_name(char * name, slong i, gr_ctx_t ctx) or
    int gr_ctx_gen_names(char ** names, gr_ctx_t ctx)?
  • or a single function
    int gr_ctx_gen_names(char ** names, slong * ngens, gr_ctx_t ctx)
    (where names is to be cleared with a single call to flint_free)
  • or some other variant?

@fredrik-johansson
Copy link
Collaborator

I think I'd go with

int gr_ctx_ngens(slong *, gr_ctx_t)

int gr_ctx_gen_name(char ** name, slong i, gr_ctx_t ctx)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants