diff --git a/src/AlgebraicGeometry/Schemes/CoveredSchemes/Morphisms/MorphismFromRationalFunctions/Methods.jl b/src/AlgebraicGeometry/Schemes/CoveredSchemes/Morphisms/MorphismFromRationalFunctions/Methods.jl index 6567b6ec396e..ac8b6ccc30b4 100644 --- a/src/AlgebraicGeometry/Schemes/CoveredSchemes/Morphisms/MorphismFromRationalFunctions/Methods.jl +++ b/src/AlgebraicGeometry/Schemes/CoveredSchemes/Morphisms/MorphismFromRationalFunctions/Methods.jl @@ -593,13 +593,15 @@ end # But they can be set by the user so that certain checks of other methods # are satisfied; i.e. the user has to take responsibility and confirm that # they know what they're doing through these channels. -@attr Any function is_proper(phi::AbsCoveredSchemeMorphism) +@attr Bool function is_proper(phi::AbsCoveredSchemeMorphism) error("no method implemented to check properness") end -@attr Any function is_isomorphism(phi::AbsCoveredSchemeMorphism) +@attr Bool function is_isomorphism(phi::AbsCoveredSchemeMorphism) error("no method implemented to check for being an isomorphism") end + +is_known(::typeof(is_isomorphism), phi::AbsCoveredSchemeMorphism) = has_attribute(phi, :is_isomorphism) ### Pullback of algebraic cycles along an isomorphism. function pullback(phi::MorphismFromRationalFunctions, C::AbsAlgebraicCycle) @@ -1073,6 +1075,7 @@ function _pushforward_prime_divisor( return PrimeIdealSheafFromChart(codomain(phi), cod_chart, JJ) end + function compose( f::MorphismFromRationalFunctions, g::MorphismFromRationalFunctions @@ -1088,7 +1091,13 @@ function compose( imgs_V = [b[V] for b in imgs] U = domain_chart(f) imgs_U = [evaluate(numerator(h), coordinate_images(f))//evaluate(denominator(h), coordinate_images(f)) for h in imgs_V] - return morphism_from_rational_functions(X, Z, U, codomain_chart(g), imgs_U; check=false) + fg = morphism_from_rational_functions(X, Z, U, codomain_chart(g), imgs_U; check=false) + if is_known(is_isomorphism, f) && is_known(is_isomorphism, g) + if is_isomorphism(f) && is_isomorphism(g) + set_attribute!(fg, :is_isomorphism=>true) + end + end + return fg end #= diff --git a/src/AlgebraicGeometry/Surfaces/EllipticSurface/Morphisms.jl b/src/AlgebraicGeometry/Surfaces/EllipticSurface/Morphisms.jl index 5e2fdc0e64b3..d77bb28bbe70 100644 --- a/src/AlgebraicGeometry/Surfaces/EllipticSurface/Morphisms.jl +++ b/src/AlgebraicGeometry/Surfaces/EllipticSurface/Morphisms.jl @@ -422,10 +422,33 @@ Return the pushforward ``f_*: V_1 \to V_2`` where ``V_i`` is the ambient quadrat This assumes that the image ``f_*(V_1)`` is contained in ``V_2``. If this is not the case, you will get ``f_*`` composed with the orthogonal projection to ``V_2``. + +# Algorithm +If the attribute `good_reduction_map` has been set via the internal method `Oscar.set_good_reduction_map!` +then the surfaces and the automorphism can be specialized and the computation carried out after specialization. +This is much faster, especially when working over number fields and for complicated maps `f`. + +# Input +The keyword argument `algorithm` can be +- `:default` -- use specialization if possible +- `:specialization` -- use specialization and error if this is not possible +- none of the above -- no specialization """ -function pushforward_on_algebraic_lattices(f::MorphismFromRationalFunctions{<:EllipticSurface, <:EllipticSurface}) - imgs_divs = _pushforward_lattice_along_isomorphism(f) - M = matrix([basis_representation(codomain(f),i) for i in imgs_divs]) +function pushforward_on_algebraic_lattices(f::MorphismFromRationalFunctions{<:EllipticSurface, <:EllipticSurface}; algorithm=:default) + X1 = domain(f) + X2 = codomain(f) + can_specialize = has_attribute(X1, :good_reduction_map) && has_attribute(X2, :good_reduction_map) + if algorithm == :specialization || (algorithm==:default && can_specialize) + match1 = good_reduction_algebraic_lattice(X1) + match2 = good_reduction_algebraic_lattice(X2) + f_red = good_reduction(f) + imgs_divs_red = _pushforward_lattice_along_isomorphism(f_red) + M_red = matrix([basis_representation(codomain(f_red), i) for i in imgs_divs_red]) + M = match1 * M_red * inv(match2) + else + imgs_divs = _pushforward_lattice_along_isomorphism(f) + M = matrix([basis_representation(codomain(f),i) for i in imgs_divs]) + end V1 = ambient_space(algebraic_lattice(domain(f))[3]) V2 = ambient_space(algebraic_lattice(codomain(f))[3]) # keep the check on since it is simple compared to all the other computations done here diff --git a/src/AlgebraicGeometry/Surfaces/EllipticSurface/NeighborStep.jl b/src/AlgebraicGeometry/Surfaces/EllipticSurface/NeighborStep.jl index f5706d9b7a1a..ae38cea473da 100644 --- a/src/AlgebraicGeometry/Surfaces/EllipticSurface/NeighborStep.jl +++ b/src/AlgebraicGeometry/Surfaces/EllipticSurface/NeighborStep.jl @@ -518,7 +518,7 @@ function transform_to_weierstrass(g::MPolyRingElem, x::MPolyRingElem, y::MPolyRi # In case of variables in the wrong order, switch and transform the result. if x == R[2] && y == R[1] switch = hom(R, R, reverse(gens(R))) - g_trans, trans = transform_to_weierstrass(switch(g), y, x, reverse(P)) + g_trans, trans, inv_trans = transform_to_weierstrass(switch(g), y, x, reverse(P)) new_trans = MapFromFunc(F, F, f->begin switch_num = switch(numerator(f)) switch_den = switch(denominator(f)) @@ -528,7 +528,16 @@ function transform_to_weierstrass(g::MPolyRingElem, x::MPolyRingElem, y::MPolyRi switch(num)//switch(den) end ) - return switch(g_trans), new_trans + new_inv_trans = MapFromFunc(F, F, f->begin + switch_num = switch(numerator(f)) + switch_den = switch(denominator(f)) + interm_res = inv_trans(F(switch_num))//inv_trans(F(switch_den)) + num = numerator(interm_res) + den = denominator(interm_res) + switch(num)//switch(den) + end + ) + return switch(g_trans), new_trans, new_inv_trans end g = inv(coeff(g,[0,2]))*g # normalise g @@ -566,15 +575,20 @@ function transform_to_weierstrass(g::MPolyRingElem, x::MPolyRingElem, y::MPolyRi E = coeff(gx, 0) #E, D, C, B, A = coeff_gx if length(P)==3 + @show "case 1" @req all(h->degree(h)<=3, coefficients(G)) "infinity (0:1:0) is not a point of this hypersurface" # y^2 = B*x^3+C*x^2+C*x+D x1 = F(inv(B)*x) y1 = F(inv(B)*y) trans = MapFromFunc(F, F, f->evaluate(numerator(f), [x1, y1])//evaluate(denominator(f), [x1, y1])) + x2 = F(B*x) + y2 = F(B*y) + inv_trans = MapFromFunc(F, F, f->evaluate(numerator(f), [x2, y2])//evaluate(denominator(f), [x2, y2])) f_trans = B^2*trans(F(g)) result = numerator(B^2*f_trans) - return result, trans + return result, trans, inv_trans elseif !iszero(E) + @show "case 2" b = py a4, a3, a2, a1, a0 = A,B,C,D,E A = b @@ -587,14 +601,15 @@ function transform_to_weierstrass(g::MPolyRingElem, x::MPolyRingElem, y::MPolyRi x1 = x1+px # TODO: The following are needed for the inverse. To be added eventually. - # x2 = (y-(A+B*x+C*x^2))//(D*x^2) - # y2 = x2//x - # x2 = evaluate(x2, [x-px, y]) - # y2 = evaluate(y2, [x-px, y]) + x2 = (y-(A+B*x+C*x^2))//(D*x^2) + y2 = x2//x + x2 = evaluate(x2, [x-px, y]) + y2 = evaluate(y2, [x-px, y]) - # @assert x == evaluate(x1, [x2, y2]) - # @assert y == evaluate(y1, [x2, y2]) + @assert x == evaluate(x1, [x2, y2]) + @assert y == evaluate(y1, [x2, y2]) else + @show "case 3" # TODO compute the inverse transformation (x2,y2) x1 = 1//x y1 = y//x^2 @@ -603,12 +618,15 @@ function transform_to_weierstrass(g::MPolyRingElem, x::MPolyRingElem, y::MPolyRi x1 = evaluate(x1, [-x//c, y//c]) y1 = evaluate(y1, [-x//c, y//c]) x1 = x1+px + x2 = x1 # A hack to allow for a coherent return format + y2 = y1 #@assert x == evaluate(x1, [x2, y2]) #@assert y == evaluate(y1, [x2, y2]) end @assert F === parent(x1) "something is wrong with caching of fraction fields" # TODO: eventually add the inverse. trans = MapFromFunc(F, F, f->evaluate(numerator(f), [x1, y1])//evaluate(denominator(f), [x1, y1])) + inv_trans = MapFromFunc(F, F, f->evaluate(numerator(f), [x2, y2])//evaluate(denominator(f), [x2, y2])) f_trans = trans(F(g)) fac = [a[1] for a in factor(numerator(f_trans)) if isone(a[2]) && _is_in_weierstrass_form(a[1])] isone(length(fac)) || error("transform to weierstrass form did not succeed") @@ -617,7 +635,7 @@ function transform_to_weierstrass(g::MPolyRingElem, x::MPolyRingElem, y::MPolyRi result = first(fac) result = inv(first(coefficients(coeff(result, gens(parent(result)), [3, 0]))))*result - return result, trans + return result, trans, inv_trans end function _is_in_weierstrass_form(f::MPolyRingElem) diff --git a/src/Rings/mpoly-ideals.jl b/src/Rings/mpoly-ideals.jl index 58120fb661f2..f829c8fbe5b6 100644 --- a/src/Rings/mpoly-ideals.jl +++ b/src/Rings/mpoly-ideals.jl @@ -525,7 +525,7 @@ Return the radical of `I`. * If the `base_ring` of `I` is a number field, then we first expand the minimal polynomials to reduce to a computation over the rationals. * For polynomial rings over the integers, the algorithm proceeds as suggested by Pfister, Sadiq, and Steidel. See [KL91](@cite), [Kem02](@cite), and [PSS11](@cite). -When `preprocessing` is set to `true`, several preprocessing heuristics are applied. See the source code for more detailed information and options. +When `eliminate_variables` is set to `true`, a preprocessing heuristic is applied in order to find variables which can be eliminated using `I`. # Examples ```jldoctest diff --git a/src/Rings/mpolyquo-localizations.jl b/src/Rings/mpolyquo-localizations.jl index b3894b363892..86003d2fabf6 100644 --- a/src/Rings/mpolyquo-localizations.jl +++ b/src/Rings/mpolyquo-localizations.jl @@ -1381,7 +1381,7 @@ end <:MPolyQuoLocRing{<:Any, <:Any, <:Any, <:Any, <:MPolyPowersOfElement}}) A = domain(f) - R = base_ring(f) + R = base_ring(A) g = hom(R, codomain(f), f.(gens(A)); check=false) K = kernel(g) return ideal(A, elem_type(A)[h for h in A.(gens(K)) if !is_zero(h)]) diff --git a/src/exports.jl b/src/exports.jl index 13aef4dfc5a2..ac3f67f48d15 100644 --- a/src/exports.jl +++ b/src/exports.jl @@ -1372,6 +1372,7 @@ export projectivization export prune_with_map export pseudo_del_pezzo_polytope export pullback +export pushforward_on_algebraic_lattices export pyramid export quadratic_form export quantum_automorphism_group @@ -1440,6 +1441,7 @@ export rem_vertex! export rem_vertices! export renest export repres +export mordell_weil_torsion export representative export representative_field export representative_patch @@ -1461,6 +1463,8 @@ export reverse_direction! export revlex_basis_encoding export reynolds_operator export right_acting_group +export translation_morphism +export isomorphism_from_generic_fibers export right_coset export right_coset_action export right_cosets