AbstractAlgebra.jl icon indicating copy to clipboard operation
AbstractAlgebra.jl copied to clipboard

Inconsistent canonical_unit

Open wbhart opened this issue 4 years ago • 7 comments

The following seems inconsistent (it was reported in the comments of #575).

julia> using AbstractAlgebra

julia> S, x = PolynomialRing(ZZ, "x")
(Univariate Polynomial Ring in x over Integers, x)

julia> F = FractionField(S)
Fraction field of Univariate Polynomial Ring in x over Integers

julia> canonical_unit(F())
0

julia> canonical_unit(S())
1

It used to be the case that canonical_unit(0) == 0. In fact the documentation indicates that this is still the case for all fields.

However the docs are inconsistent as they say that the function can just return 1 when it is impractical to implement the function. Perhaps it should return 0 at 0. Or perhaps there is a justification for making it return 1 at 0. Personally I think that just hides bugs (like the one I just fixed on #575).

Either way, we should be more consistent about this. See also point 1 of #552

wbhart avatar Jun 10 '21 12:06 wbhart

I'd be in favour of canonical_unit always returning a unit... and call teh default for fields (x ->x) an error

On Thu, Jun 10, 2021 at 05:11:43AM -0700, wbhart wrote:

The following seems inconsistent (it was reported in the comments of #575).

It used to be the case that canonical_unit(0) == 0. In fact the documentation indicates that this is still the case for all fields.

However the docs are inconsistent as they say that the function can just return 1 when it is impractical to implement the function. Perhaps it should return 0 at 0. Or perhaps there is a justification for making it return 1 at 0. Personally I think that just hides bugs (like the one I just fixed on #575).

Either way, we should be more consistent about this. See also point 1 of #552

-- You are receiving this because you are subscribed to this thread. Reply to this email directly or view it on GitHub: https://github.com/Nemocas/AbstractAlgebra.jl/issues/894

fieker avatar Jun 10 '21 12:06 fieker

Yeah but that is problematic for inexact rings where checking for zero may not be possible, e.g. Calcium and Arb objects need to have it defined.

Is there any really good reason to change the definition other than that it says "unit" in the name of the function?

wbhart avatar Jun 10 '21 12:06 wbhart

On Thu, Jun 10, 2021 at 05:49:53AM -0700, wbhart wrote:

Yeah but that is problematic for inexact rings where checking for zero may not be possible, e.g. Calcium and Arb objects need to have it defined.

Is there any really good reason to change the definition other than that it says "unit" in the name of the function?

Almost every useage will either invert the result or divide by it to normalise the input. For inexact fields, 1 might be correct...

Think HNF for example, canonical_unit make it unique (in Z) (granted: here I will never call it on zero)

I guess the 0 will have to be dealt with: either in all uses of canonical_unit or in canonical_unit.

Pest vs Cholera?

-- You are receiving this because you commented. Reply to this email directly or view it on GitHub: https://github.com/Nemocas/AbstractAlgebra.jl/issues/894#issuecomment-858593454

fieker avatar Jun 10 '21 12:06 fieker

I don't think the function should ever be called on zero. That's why the cost of checking if the value is zero (even if it is not) is too high for inexact rings.

It's designed for canonicalisation, which means dividing by the return value. Therefore it doesn't make sense that it ever be called on zero. If it is, the right thing will happen (a divide by zero error, indicating the code is faulty).

wbhart avatar Jun 10 '21 12:06 wbhart

What I'm saying is that the cases where we test for zero should be minimised, which means calling code should do it if necessary. In most use cases it isn't necessary because you are dividing by the canonical unit of a denominator of a fraction (its original intended use), which is by definition not zero, so no need to check.

wbhart avatar Jun 10 '21 13:06 wbhart

Related Question (I think). The Documentation indicates that canonical_unit of a Generic.FieldElem should just return the element itself (perhaps this also means for zero too).

Nevertheless, it looks like a fallback method like

canonical_unit(x::Generic.FieldElem) = x

Is not implemented. Is there an issue with this?

julia> using AbstractAlgebra

julia> K, t = LaurentSeriesField(GF(5), 5, "t")
(Laurent series field in t over Finite field F_5, t + O(t^6))

julia> canonical_unit(K(1))
ERROR: MethodError: no method matching canonical_unit(::AbstractAlgebra.Generic.LaurentSeriesFieldElem{AbstractAlgebra.GFElem{Int64}})
Closest candidates are:
  canonical_unit(::PolynomialElem) at ~/.julia/dev/AbstractAlgebra/src/Poly.jl:469
  canonical_unit(::MatrixElem) at ~/.julia/dev/AbstractAlgebra/src/Matrix.jl:358
  canonical_unit(::FracElem) at ~/.julia/dev/AbstractAlgebra/src/Fraction.jl:105
  ...
Stacktrace:
 [1] top-level scope
   @ REPL[2]:1

julia> methods(canonical_unit)
# 15 methods for generic function "canonical_unit":
[1] canonical_unit(x::PolynomialElem) in AbstractAlgebra at /Users/f004584/.julia/dev/AbstractAlgebra/src/Poly.jl:469
[2] canonical_unit(a::MatrixElem) in AbstractAlgebra at /Users/f004584/.julia/dev/AbstractAlgebra/src/Matrix.jl:358
[3] canonical_unit(a::FracElem) in AbstractAlgebra at /Users/f004584/.julia/dev/AbstractAlgebra/src/Fraction.jl:105
[4] canonical_unit(p::AbstractAlgebra.Generic.UnivPoly) in AbstractAlgebra.Generic at /Users/f004584/.julia/dev/AbstractAlgebra/src/generic/UnivPoly.jl:280
[5] canonical_unit(a::LocElem{T}) where T<:RingElem in AbstractAlgebra.Generic at /Users/f004584/.julia/dev/AbstractAlgebra/src/generic/Misc/Localization.jl:412
[6] canonical_unit(x::ResElem{<:Union{RingElem, Integer}}) in AbstractAlgebra at /Users/f004584/.julia/dev/AbstractAlgebra/src/Residue.jl:104
[7] canonical_unit(a::AbstractFloat) in AbstractAlgebra at /Users/f004584/.julia/dev/AbstractAlgebra/src/julia/Float.jl:41
[8] canonical_unit(p::AbstractAlgebra.Generic.LaurentPolyWrap) in AbstractAlgebra.Generic at /Users/f004584/.julia/dev/AbstractAlgebra/src/generic/LaurentPoly.jl:214
[9] canonical_unit(x::AbstractAlgebra.LaurentPolyElem) in AbstractAlgebra at /Users/f004584/.julia/dev/AbstractAlgebra/src/algorithms/LaurentPoly.jl:200
[10] canonical_unit(x::AbstractAlgebra.GFElem) in AbstractAlgebra at /Users/f004584/.julia/dev/AbstractAlgebra/src/julia/GF.jl:122
[11] canonical_unit(a::Rational) in AbstractAlgebra at /Users/f004584/.julia/dev/AbstractAlgebra/src/julia/Rational.jl:51
[12] canonical_unit(a::T) where T<:Integer in AbstractAlgebra at /Users/f004584/.julia/dev/AbstractAlgebra/src/julia/Integer.jl:44
[13] canonical_unit(x::AbstractAlgebra.ResFieldElem{<:Union{RingElem, Integer}}) in AbstractAlgebra at /Users/f004584/.julia/dev/AbstractAlgebra/src/ResidueField.jl:113
[14] canonical_unit(x::MPolyElem) in AbstractAlgebra at /Users/f004584/.julia/dev/AbstractAlgebra/src/MPoly.jl:508
[15] canonical_unit(a::AbstractAlgebra.Generic.Rat) in AbstractAlgebra.Generic at /Users/f004584/.julia/dev/AbstractAlgebra/src/generic/RationalFunctionField.jl:125

a-kulkarn avatar Feb 19 '22 21:02 a-kulkarn

I guess a fallback method for fields is a good idea.

wbhart avatar Feb 19 '22 22:02 wbhart