Results of evaluate methods differ
I think the following MWE is related to issue #1008 and I wonder why it is ok that the first form of evaluation works and the second doesn't:
julia> using AbstractAlgebra
julia> Rx, x = polynomial_ring(QQ, :x)
(Univariate polynomial ring in x over rationals, x)
julia> Ry, (y,) = polynomial_ring(QQ, [:y])
(Multivariate polynomial ring in 1 variable over rationals, AbstractAlgebra.Generic.MPoly{Rational{BigInt}}[y])
julia> evaluate(y, [x])
x
julia> evaluate(y, [1], [x])
ERROR: Cannot promote to common type
Stacktrace:
[1] error(s::String)
@ Base ./error.jl:35
[2] promote(x::AbstractAlgebra.Generic.Poly{Rational{BigInt}}, y::AbstractAlgebra.Generic.MPoly{Rational{BigInt}})
@ AbstractAlgebra ~/.julia/packages/AbstractAlgebra/eNeG2/src/NCRings.jl:54
[3] *(x::AbstractAlgebra.Generic.Poly{Rational{BigInt}}, y::AbstractAlgebra.Generic.MPoly{Rational{BigInt}})
@ AbstractAlgebra ~/.julia/packages/AbstractAlgebra/eNeG2/src/NCRings.jl:80
[4] __evaluate(a::AbstractAlgebra.Generic.MPoly{…}, vars::Vector{…}, vals::Vector{…}, powers::Vector{…})
@ AbstractAlgebra ~/.julia/packages/AbstractAlgebra/eNeG2/src/MPoly.jl:991
[5] _evaluate(a::AbstractAlgebra.Generic.MPoly{…}, S::AbstractAlgebra.Generic.MPolyRing{…}, R::AbstractAlgebra.Rationals{…}, vars::Vector{…}, vals::Vector{…})
@ AbstractAlgebra ~/.julia/packages/AbstractAlgebra/eNeG2/src/MPoly.jl:969
[6] evaluate(a::AbstractAlgebra.Generic.MPoly{…}, vars::Vector{…}, vals::Vector{…})
@ AbstractAlgebra ~/.julia/packages/AbstractAlgebra/eNeG2/src/MPoly.jl:938
[7] top-level scope
@ REPL[11]:1
Some type information was truncated. Use `show(err)` to see complete types.
Or a more realistic use case where I only want to evaluate one of multiple variables:
julia> Ryz, (y, z) = polynomial_ring(QQ, [:y, :z])
(Multivariate polynomial ring in 2 variables over rationals, AbstractAlgebra.Generic.MPoly{Rational{BigInt}}[y, z])
julia> evaluate(y, [x, z])
x
julia> evaluate(y, [y, x])
y
julia> evaluate(y, [1], [x])
ERROR: Cannot promote to common type
Stacktrace:
[1] error(s::String)
@ Base ./error.jl:35
[2] promote(x::AbstractAlgebra.Generic.Poly{Rational{BigInt}}, y::AbstractAlgebra.Generic.MPoly{Rational{BigInt}})
@ AbstractAlgebra ~/.julia/packages/AbstractAlgebra/eNeG2/src/NCRings.jl:54
[3] *(x::AbstractAlgebra.Generic.Poly{Rational{BigInt}}, y::AbstractAlgebra.Generic.MPoly{Rational{BigInt}})
@ AbstractAlgebra ~/.julia/packages/AbstractAlgebra/eNeG2/src/NCRings.jl:80
[4] __evaluate(a::AbstractAlgebra.Generic.MPoly{…}, vars::Vector{…}, vals::Vector{…}, powers::Vector{…})
@ AbstractAlgebra ~/.julia/packages/AbstractAlgebra/eNeG2/src/MPoly.jl:991
[5] _evaluate(a::AbstractAlgebra.Generic.MPoly{…}, S::AbstractAlgebra.Generic.MPolyRing{…}, R::AbstractAlgebra.Rationals{…}, vars::Vector{…}, vals::Vector{…})
@ AbstractAlgebra ~/.julia/packages/AbstractAlgebra/eNeG2/src/MPoly.jl:969
[6] evaluate(a::AbstractAlgebra.Generic.MPoly{…}, vars::Vector{…}, vals::Vector{…})
@ AbstractAlgebra ~/.julia/packages/AbstractAlgebra/eNeG2/src/MPoly.jl:938
[7] top-level scope
@ REPL[16]:1
Some type information was truncated. Use `show(err)` to see complete types.
julia> evaluate(y, [2], [x])
ERROR: Cannot promote to common type
Stacktrace:
[1] error(s::String)
@ Base ./error.jl:35
[2] promote(x::AbstractAlgebra.Generic.Poly{Rational{BigInt}}, y::AbstractAlgebra.Generic.MPoly{Rational{BigInt}})
@ AbstractAlgebra ~/.julia/packages/AbstractAlgebra/eNeG2/src/NCRings.jl:54
[3] *(x::AbstractAlgebra.Generic.Poly{Rational{BigInt}}, y::AbstractAlgebra.Generic.MPoly{Rational{BigInt}})
@ AbstractAlgebra ~/.julia/packages/AbstractAlgebra/eNeG2/src/NCRings.jl:80
[4] __evaluate(a::AbstractAlgebra.Generic.MPoly{…}, vars::Vector{…}, vals::Vector{…}, powers::Vector{…})
@ AbstractAlgebra ~/.julia/packages/AbstractAlgebra/eNeG2/src/MPoly.jl:991
[5] _evaluate(a::AbstractAlgebra.Generic.MPoly{…}, S::AbstractAlgebra.Generic.MPolyRing{…}, R::AbstractAlgebra.Rationals{…}, vars::Vector{…}, vals::Vector{…})
@ AbstractAlgebra ~/.julia/packages/AbstractAlgebra/eNeG2/src/MPoly.jl:969
[6] evaluate(a::AbstractAlgebra.Generic.MPoly{…}, vars::Vector{…}, vals::Vector{…})
@ AbstractAlgebra ~/.julia/packages/AbstractAlgebra/eNeG2/src/MPoly.jl:938
[7] top-level scope
@ REPL[17]:1
Some type information was truncated. Use `show(err)` to see complete types.
Note that if you make the examples even more realistic both versions of evaluate are consistent (in failing):
julia> evaluate(y+z, [y, x])
ERROR: Cannot promote to common type
Stacktrace:
[1] error(s::String)
@ Base ./error.jl:35
[2] promote(x::AbstractAlgebra.Generic.MPoly{Rational{BigInt}}, y::AbstractAlgebra.Generic.Poly{Rational{BigInt}})
@ AbstractAlgebra ~/.julia/packages/AbstractAlgebra/lYBCD/src/NCRings.jl:54
[3] *(x::AbstractAlgebra.Generic.MPoly{Rational{BigInt}}, y::AbstractAlgebra.Generic.Poly{Rational{BigInt}})
@ AbstractAlgebra ~/.julia/packages/AbstractAlgebra/lYBCD/src/NCRings.jl:80
[4] evaluate(a::AbstractAlgebra.Generic.MPoly{Rational{BigInt}}, vals::Vector{RingElem})
@ AbstractAlgebra ~/.julia/packages/AbstractAlgebra/lYBCD/src/MPoly.jl:903
[5] top-level scope
@ REPL[18]:1
julia> evaluate(y+z, [x, z])
ERROR: Cannot promote to common type
Stacktrace:
[1] error(s::String)
@ Base ./error.jl:35
[2] promote(x::AbstractAlgebra.Generic.Poly{Rational{BigInt}}, y::AbstractAlgebra.Generic.MPoly{Rational{BigInt}})
@ AbstractAlgebra ~/.julia/packages/AbstractAlgebra/lYBCD/src/NCRings.jl:54
[3] *(x::AbstractAlgebra.Generic.Poly{Rational{BigInt}}, y::AbstractAlgebra.Generic.MPoly{Rational{BigInt}})
@ AbstractAlgebra ~/.julia/packages/AbstractAlgebra/lYBCD/src/NCRings.jl:80
[4] evaluate(a::AbstractAlgebra.Generic.MPoly{Rational{BigInt}}, vals::Vector{RingElem})
@ AbstractAlgebra ~/.julia/packages/AbstractAlgebra/lYBCD/src/MPoly.jl:903
[5] top-level scope
@ REPL[19]:1
julia> evaluate(y+z, [1], [x])
ERROR: Cannot promote to common type
Stacktrace:
[1] error(s::String)
@ Base ./error.jl:35
[2] promote(x::AbstractAlgebra.Generic.Poly{Rational{BigInt}}, y::AbstractAlgebra.Generic.MPoly{Rational{BigInt}})
@ AbstractAlgebra ~/.julia/packages/AbstractAlgebra/lYBCD/src/NCRings.jl:54
[3] *(x::AbstractAlgebra.Generic.Poly{Rational{BigInt}}, y::AbstractAlgebra.Generic.MPoly{Rational{BigInt}})
@ AbstractAlgebra ~/.julia/packages/AbstractAlgebra/lYBCD/src/NCRings.jl:80
[4] __evaluate(a::AbstractAlgebra.Generic.MPoly{…}, vars::Vector{…}, vals::Vector{…}, powers::Vector{…})
@ AbstractAlgebra ~/.julia/packages/AbstractAlgebra/lYBCD/src/MPoly.jl:997
[5] _evaluate(a::AbstractAlgebra.Generic.MPoly{…}, S::AbstractAlgebra.Generic.MPolyRing{…}, R::AbstractAlgebra.Rationals{…}, vars::Vector{…}, vals::Vector{…})
@ AbstractAlgebra ~/.julia/packages/AbstractAlgebra/lYBCD/src/MPoly.jl:975
[6] evaluate(a::AbstractAlgebra.Generic.MPoly{…}, vars::Vector{…}, vals::Vector{…})
@ AbstractAlgebra ~/.julia/packages/AbstractAlgebra/lYBCD/src/MPoly.jl:944
[7] top-level scope
@ REPL[20]:1
Some type information was truncated. Use `show(err)` to see complete types.
julia> evaluate(y+z, [2], [x])
ERROR: Cannot promote to common type
Stacktrace:
[1] error(s::String)
@ Base ./error.jl:35
[2] promote(x::AbstractAlgebra.Generic.Poly{Rational{BigInt}}, y::AbstractAlgebra.Generic.MPoly{Rational{BigInt}})
@ AbstractAlgebra ~/.julia/packages/AbstractAlgebra/lYBCD/src/NCRings.jl:54
[3] *(x::AbstractAlgebra.Generic.Poly{Rational{BigInt}}, y::AbstractAlgebra.Generic.MPoly{Rational{BigInt}})
@ AbstractAlgebra ~/.julia/packages/AbstractAlgebra/lYBCD/src/NCRings.jl:80
[4] __evaluate(a::AbstractAlgebra.Generic.MPoly{…}, vars::Vector{…}, vals::Vector{…}, powers::Vector{…})
@ AbstractAlgebra ~/.julia/packages/AbstractAlgebra/lYBCD/src/MPoly.jl:997
[5] _evaluate(a::AbstractAlgebra.Generic.MPoly{…}, S::AbstractAlgebra.Generic.MPolyRing{…}, R::AbstractAlgebra.Rationals{…}, vars::Vector{…}, vals::Vector{…})
@ AbstractAlgebra ~/.julia/packages/AbstractAlgebra/lYBCD/src/MPoly.jl:975
[6] evaluate(a::AbstractAlgebra.Generic.MPoly{…}, vars::Vector{…}, vals::Vector{…})
@ AbstractAlgebra ~/.julia/packages/AbstractAlgebra/lYBCD/src/MPoly.jl:944
[7] top-level scope
@ REPL[21]:1
Some type information was truncated. Use `show(err)` to see complete types.
Most of these failures are expected, e.g., evaluate(y+z, [2], [x]), since AbstractAlgebra will never create a new ring. (The result must be an element of R, Rx or Ryz, or any other ring that already exists.)
(Some of them might be made to work, like evaluate(y, [1], [x]).)
You are right, if I create the resulting ring beforehand they work:
julia> Rxy, (x, y) = polynomial_ring(QQ, [:x, :y])
(Multivariate polynomial ring in 2 variables over rationals, AbstractAlgebra.Generic.MPoly{Rational{BigInt}}[x, y])
julia> evaluate(y+z, [2], [x])
2*x
I find it a bit irritating that the result depends on some global state...
I tried your example, but it yields
julia> Rxy, (x, y) = polynomial_ring(QQ, [:x, :y])
(Multivariate polynomial ring in 2 variables over rationals, AbstractAlgebra.Generic.MPoly{Rational{BigInt}}[x, y])
julia> evaluate(y+z, [2], [x])
ERROR: UndefVarError: `z` not defined in `Main`
There are two rules for evaluation in AA: If you have a polynomial f in R[x,y], you can
- evaluate all variables at some elements
s, tin someR-algebraS(meaning that elements ofRandScan be multiplied, yielding elements ofS). - do a partial evaluation at an element
sfrom a ringS, but the multiplication between elements ofR[x, y]andSmust work.
Since the product of an element of any ring R and any ring S is either an element of R or of S, this is not effected by any global state I think.
P.S.: There are some cases of partial evaluation that currently don't work, due to technical reasons.
I tried your example, but it yields
Sorry, the example assumed the steps from the comments before. Here is the complete example:
julia> using AbstractAlgebra
julia> Ryz, (y, z) = polynomial_ring(QQ, [:y, :z])
julia> Rx, x = polynomial_ring(QQ, :x)
(Univariate polynomial ring in x over rationals, x)
julia> evaluate(y+z, [2], [x])
ERROR: Cannot promote to common type
Stacktrace:
[1] error(s::String)
@ Base ./error.jl:35
[2] promote(x::AbstractAlgebra.Generic.Poly{Rational{BigInt}}, y::AbstractAlgebra.Generic.MPoly{Rational{BigInt}})
@ AbstractAlgebra ~/.julia/packages/AbstractAlgebra/lYBCD/src/NCRings.jl:54
[3] *(x::AbstractAlgebra.Generic.Poly{Rational{BigInt}}, y::AbstractAlgebra.Generic.MPoly{Rational{BigInt}})
@ AbstractAlgebra ~/.julia/packages/AbstractAlgebra/lYBCD/src/NCRings.jl:80
[4] __evaluate(a::AbstractAlgebra.Generic.MPoly{…}, vars::Vector{…}, vals::Vector{…}, powers::Vector{…})
@ AbstractAlgebra ~/.julia/packages/AbstractAlgebra/lYBCD/src/MPoly.jl:997
[5] _evaluate(a::AbstractAlgebra.Generic.MPoly{…}, S::AbstractAlgebra.Generic.MPolyRing{…}, R::AbstractAlgebra.Rationals{…}, vars::Vector{…}, vals::Vector{…})
@ AbstractAlgebra ~/.julia/packages/AbstractAlgebra/lYBCD/src/MPoly.jl:975
[6] evaluate(a::AbstractAlgebra.Generic.MPoly{…}, vars::Vector{…}, vals::Vector{…})
@ AbstractAlgebra ~/.julia/packages/AbstractAlgebra/lYBCD/src/MPoly.jl:944
[7] top-level scope
@ REPL[21]:1
Some type information was truncated. Use `show(err)` to see complete types.
julia> Rxy, (x, y) = polynomial_ring(QQ, [:x, :y])
(Multivariate polynomial ring in 2 variables over rationals, AbstractAlgebra.Generic.MPoly{Rational{BigInt}}[x, y])
julia> evaluate(y+z, [2], [x])
2*x
You are right however, this isn't caused by some global state, but by me replacing the variable x with a new generator.
It is a bug that y + z does not throw an error (there is a missing parent check):
julia> parent(y) == parent(z)
false
I'll prepare a fix soon.
It is a bug that
y + zdoes not throw an error (there is a missing parent check):julia> parent(y) == parent(z) falseI'll prepare a fix soon.
Thanks, I created a separate issue for it at #2010.
So if I would like the evaluation to work I would have to transform elements from both Rings to a new Ring via homomorphism? I think I need Oscar.jl to do this for Multivariate Polynomials right?
julia> using Oscar
___ ____ ____ _ ____
/ _ \ / ___| / ___| / \ | _ \ | Combining ANTIC, GAP, Polymake, Singular
| | | |\___ \| | / _ \ | |_) | | Type "?Oscar" for more information
| |_| | ___) | |___ / ___ \| _ < | Manual: https://docs.oscar-system.org
\___/ |____/ \____/_/ \_\_| \_\ | Version 1.2.2
julia> Rxy, (x2, y2) = polynomial_ring(QQ, [:x, :y])
(Multivariate polynomial ring in 2 variables over QQ, QQMPolyRingElem[x, y])
julia> Ryz, (y1, z1) = polynomial_ring(QQ, [:y, :z])
(Multivariate polynomial ring in 2 variables over QQ, QQMPolyRingElem[y, z])
julia> Rxyz, (x3, y3, z3) = polynomial_ring(QQ, [:x, :y, :z])
(Multivariate polynomial ring in 3 variables over QQ, QQMPolyRingElem[x, y, z])
julia> h1 = hom(Ryz, Rxyz, [y3, z3])
Ring homomorphism
from multivariate polynomial ring in 2 variables over QQ
to multivariate polynomial ring in 3 variables over QQ
defined by
y -> y
z -> z
julia> h2 = hom(Rxy, Rxyz, [x3, y3])
Ring homomorphism
from multivariate polynomial ring in 2 variables over QQ
to multivariate polynomial ring in 3 variables over QQ
defined by
x -> x
y -> y
julia> evaluate(h1(y1 + z1), [2], [h2(x2)])
x + z
Here is another case where the evaluation methods return different results, this time for UnivPoly:
julia> using AbstractAlgebra
julia> R = universal_polynomial_ring(QQ)
Universal Polynomial Ring over Rationals
julia> x = gen(R, :x)
x
julia> y = gen(R, :y)
y
julia> evaluate(x + y, [1], [QQ(1)])
y + 1
julia> evaluate(x + y, [2], [QQ(1)])
x + 1
julia> evaluate(x + y, [QQ(1), QQ(1)])
2//1
julia> evaluate(x + y, Vector{RingElement}([x, QQ(1)]))
x + 1
julia> evaluate(x + y, Vector{RingElement}([QQ(1), y]))
ERROR: MethodError: Cannot `convert` an object of type AbstractAlgebra.Generic.UnivPoly{Rational{BigInt}} to an object of type Rational{BigInt}
The function `convert` exists, but no method is defined for this combination of argument types.
Closest candidates are:
convert(::Type{T}, ::T) where T<:Number
@ Base number.jl:6
convert(::Type{T}, ::T) where T
@ Base Base.jl:126
convert(::Type{T}, ::AbstractChar) where T<:Number
@ Base char.jl:185
...
Stacktrace:
[1] push!(a::Vector{Rational{BigInt}}, item::AbstractAlgebra.Generic.UnivPoly{Rational{BigInt}})
@ Base ./array.jl:1260
[2] evaluate(a::AbstractAlgebra.Generic.MPoly{Rational{BigInt}}, vals::Vector{RingElement})
@ AbstractAlgebra ~/.julia/packages/AbstractAlgebra/lYBCD/src/MPoly.jl:905
[3] evaluate(a::AbstractAlgebra.Generic.UnivPoly{Rational{BigInt}}, A::Vector{RingElement})
@ AbstractAlgebra.Generic ~/.julia/packages/AbstractAlgebra/lYBCD/src/generic/UnivPoly.jl:821
[4] top-level scope
@ REPL[12]:1
Yes, the cleanest way is with proper morphisms. But most things can be done by just evaluating at the right things:
julia> ((y1 + z1)(y3, z3))(zero(Rxyz), x2(x3, one(Rxyz)), y3)
x + y
Here is another case where the evaluation methods return different results, this time for
UnivPoly:
By "return different results", what do you mean? They all give correct results, but one of them errors, which is unfortunate (but I don't see any wrong results).
The evaluation code is very brittle when the input is inhomogeneous (as in your last example). If you stick to homogeneous evaluation points things "should work".
I don't know what your actual use case is, but just in case let me point out that there is also universal_polynomial_ring which has "as many variables as you like", dynamically.
julia> R = @universal_polynomial_ring(QQ, [:x, :y])
Universal Polynomial Ring over Rationals
julia> f = x + y
x + y
julia> g = x * gen(R, :z)
x*z
UPDATE: sorry, I did not read everything and only now realize you also referenced universal_polynomial_ring.
By "return different results", what do you mean? They all give correct results, but one of them errors, which is unfortunate (but I don't see any wrong results).
You are right, the results are correct, i just didn't expect the last line to error since the one before did and everything seems to be compatible in the mathematical sense.
To summarize my issue as I see it:
- For
xfrom RingR1andyfrom RingR2: Ifevaluate(y, [x])works I would expectevaluate(y, [1], [x])to also work. - For
xandyfrom universal ringR: Ifevaluate(x + y, Vector{RingElement}([x, QQ(1)]))works I would expectevaluate(x + y, Vector{RingElement}([QQ(1), y]))to also work.