Generic domain closures
For a generic ring $R$ (or other structure, where relevant), we can define:
- A "singularity closure" $R^{*} \supset R$ such that partial functions on $R$ extend to total functions on $R^{*}$. It is sufficient to adjoin a single
Undefinedelement, but we can also add more refined extended values like infinities. - A "computational meta-closure" $R^{**} \supset R$ or $R^{**} \supset R^{*}$ by adding an
Unknownmeta-element.
This is currently only done for ca_t (https://flintlib.org/doc/ca.html#introduction-special-values; see also https://fredrikj.net/blog/2021/01/infinity-in-calcium-and-fungrim/) and less formally for arf_t for arb_t, where NaN stands for Undefined or Unknown depending on context.
It would be better to do this with a generic construction that wraps any given ring R. By default, operations could simply intercept GR_UNABLE (turning them into Unknown) and GR_DOMAIN (turning them into Undefined). This could be refined with infinity handling for special functions like gr_exp over rings where infinities make sense.
Advantages:
- One could have well-defined semantics for infinities and special values which only need to be implemented generically once rather than for each type.
- Types representing real and complex numbers would not need builtin handling of special values. This would improve performance in the common cases where one doesn't actually care about special values.
- It would provide a facility for nonstop computation (silencing
GR_UNABLE/GR_DOMAIN) over arbitrary rings.
Disadvantages:
- There would be a performance hit working with $R^{**}$ or $R^{*}$ instead of $R$ (due to needing to wrap and inspect elements). But surely this isn't the use case to optimize for? Normally, you'd want to use $R^{**}$ or $R^{*}$ only where it is convenient, and do your actual number crunching in $R$.
Disadvantages:
- There would be a performance hit working with $R^{}$ or $R^*$ instead of $R$ (due to needing to wrap and inspect elements). But surely this isn't the use case to optimize for? Normally, you'd want to use $R^{}$ or $R^*$ only where it is convenient, and do your actual number crunching in $R$.
I agree, but it would have to be done case by case, I believe? Otherwise there may be, as you imply, unwanted overhead.