Skip to content
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

[Merged by Bors] - feat(ring_theory/*): generalise minpoly.dvd to integrally closed rings #18021

Closed
wants to merge 47 commits into from
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
04a0277
init
Paul-Lez Dec 29, 2022
e325683
tidy
Paul-Lez Dec 29, 2022
a2a320c
Moved lemmas
Paul-Lez Dec 30, 2022
1e65541
WIP
Paul-Lez Jan 3, 2023
f0cb426
Merge remote-tracking branch 'origin/master' into preliminary_ring_th…
Paul-Lez Jan 4, 2023
365d101
moved some lemmas and added import to `gauss_lemma.lean`
Paul-Lez Jan 4, 2023
52be975
Fix cyclic import issue
Paul-Lez Jan 4, 2023
19523e4
More fixing of cyclic imports
Paul-Lez Jan 4, 2023
9f200d4
More lemmas moved, deleted temporary file
Paul-Lez Jan 4, 2023
6f0b051
remove useless fraction_ring lemmas
Paul-Lez Jan 4, 2023
7eaf21c
Fix weird error
Paul-Lez Jan 4, 2023
c1d1ef2
More fixes
Paul-Lez Jan 4, 2023
3efaf33
Fix imports in `minpoly.field`
Paul-Lez Jan 4, 2023
ad86508
Init
Paul-Lez Jan 5, 2023
180bfe7
Fixed another missing import
Paul-Lez Jan 5, 2023
76c2a19
Another fix
Paul-Lez Jan 5, 2023
c316f49
Yet another fix
Paul-Lez Jan 5, 2023
4d5c9a3
Another one
Paul-Lez Jan 5, 2023
651e011
Moved lemmas again
Paul-Lez Jan 5, 2023
41f0305
Update src/field_theory/minpoly/gcd_monoid.lean
Paul-Lez Jan 6, 2023
f4bf53d
Update src/field_theory/minpoly/field.lean
Paul-Lez Jan 6, 2023
226b09c
Update src/number_theory/number_field/embeddings.lean
Paul-Lez Jan 6, 2023
5defafd
Merge remote-tracking branch 'origin/import_fix_PR' into preliminary_…
Paul-Lez Jan 6, 2023
cc79fab
A few more changes
Paul-Lez Jan 6, 2023
566efcf
Merge remote-tracking branch 'origin/master' into preliminary_ring_th…
Paul-Lez Jan 7, 2023
9c0e470
Merge remote-tracking branch 'origin/master' into preliminary_ring_th…
Paul-Lez Jan 7, 2023
3a1f017
Fix weird issue in `hasse_deriv.lean`
Paul-Lez Jan 7, 2023
88e313d
test fix
Paul-Lez Jan 7, 2023
98172e7
Other test fix
Paul-Lez Jan 7, 2023
aca52d5
Final fix!
Paul-Lez Jan 8, 2023
cc58334
Added deleted code + removed previous fix + removed unused assumptions
Paul-Lez Jan 8, 2023
d416967
Update src/ring_theory/integral_closure.lean
Paul-Lez Jan 8, 2023
3e35a30
Cleaning up `gcd_monoid`
Paul-Lez Jan 8, 2023
49c9c0b
Merge branch 'preliminary_ring_theory_PR' of https://github.com/leanp…
Paul-Lez Jan 8, 2023
8d49602
More cleanup and some golfs
Paul-Lez Jan 9, 2023
ef5bed5
Fixed typeclass issue and noisy file
Paul-Lez Jan 9, 2023
fb93b0e
Add missing lemmas
Paul-Lez Jan 9, 2023
141d463
Fixes and more cleanup
Paul-Lez Jan 9, 2023
7877382
Extra fixes and put a missing result back
Paul-Lez Jan 9, 2023
677f0c0
Fix order of parameters
Paul-Lez Jan 10, 2023
51753c6
Apply suggestions from code review
Paul-Lez Jan 10, 2023
671725b
unused variables
riccardobrasca Jan 11, 2023
49844f8
Merge remote-tracking branch 'origin/master' into preliminary_ring_th…
Paul-Lez Jan 15, 2023
c94ebe4
added key result
Paul-Lez Jan 16, 2023
f97552a
Upadte results
Paul-Lez Jan 17, 2023
1a21901
Last few modifications
Paul-Lez Jan 17, 2023
f26f977
Fixed lint error
Paul-Lez Jan 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/data/polynomial/algebra_map.lean
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,15 @@ lemma coeff_zero_eq_aeval_zero' (p : R[X]) :
algebra_map R A (p.coeff 0) = aeval (0 : A) p :=
by simp [aeval_def]

lemma aeval_commuting_diagram {S T U : Type*} [comm_ring S] [comm_ring T] [comm_ring U]
Paul-Lez marked this conversation as resolved.
Show resolved Hide resolved
[algebra R S] [algebra T U] (φ : R →+* T) (ψ : S →+* U)
(h : (algebra_map T U).comp φ = ψ.comp (algebra_map R S)) (p : R[X]) (a : S) :
ψ (aeval a p) = aeval (ψ a) (p.map φ) :=
begin
conv_rhs {rw [aeval_def, ← eval_map]},
rw [map_map, h, ← map_map, eval_map, eval₂_at_apply, aeval_def, eval_map],
end

variable (R)

theorem _root_.algebra.adjoin_singleton_eq_range_aeval (x : A) :
Expand Down
4 changes: 4 additions & 0 deletions src/data/polynomial/monic.lean
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,10 @@ begin
rw [← leading_coeff_of_injective hf, hp.leading_coeff, f.map_one]
end

theorem monic_map_iff_of_injective [nontrivial S] (f : R →+* S) (hf : function.injective f)
{p : R[X]} : p.monic ↔ (p.map f).monic :=
⟨monic.map _, polynomial.monic_of_injective hf⟩

end injective

end semiring
Expand Down
158 changes: 158 additions & 0 deletions src/number_theory/temporary_file.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import ring_theory.adjoin_root
import field_theory.minpoly
import data.polynomial.div
import ring_theory.integrally_closed
import field_theory.splitting_field

open polynomial localization alg_hom


open_locale polynomial

variables {R S : Type*} [comm_ring R] [comm_ring S]

section move_me
/- The results in this section are useful (they are direct generalisations of results in
`gauss_lemma.lean` but aren't necessary for this PR so will be shortly moved to another one) -/



variables [algebra R S] {a : S} [is_domain S] [is_domain R] {φ : R →+* S} {f : R[X]}
Paul-Lez marked this conversation as resolved.
Show resolved Hide resolved

/- theorem is_primitive.is_unit_iff_is_unit_map_of_injective' (hinj : function.injective φ)
(hf : is_primitive f) : is_unit f ↔ is_unit (map φ f) :=
begin
refine ⟨(map_ring_hom φ).is_unit_map, λ h, _⟩,
rcases is_unit_iff.1 h with ⟨_, ⟨u, rfl⟩, hu⟩,
have hdeg := degree_C u.ne_zero,
rw [hu, degree_map_eq_of_injective hinj] at hdeg,
rw [eq_C_of_degree_eq_zero hdeg] at hf,
rw [eq_C_of_degree_eq_zero hdeg, is_unit_C],
refine is_primitive_iff_is_unit_of_C_dvd.mp hf (f.coeff 0) (dvd_refl _),
end

lemma is_primitive_of_dvd' {p q : R[X]} (hp : is_primitive p) (hq : q ∣ p) : is_primitive q :=
λ a ha, is_primitive_iff_is_unit_of_C_dvd.mp hp a (dvd_trans ha hq)

lemma is_primitive.irreducible_of_irreducible_map_of_injective (hinj : function.injective φ)
(hf : is_primitive f) (h_irr : irreducible (map φ f)) :
irreducible f :=
begin
refine ⟨λ h, h_irr.not_unit (is_unit.map (map_ring_hom φ) h), _⟩,
intros a b h,
rcases h_irr.is_unit_or_is_unit (by rw [h, polynomial.map_mul]) with hu | hu,
{ left,
rwa is_primitive.is_unit_iff_is_unit_map_of_injective' hinj (is_primitive_of_dvd' hf
(dvd.intro _ h.symm)) },
right,
rwa is_primitive.is_unit_iff_is_unit_map_of_injective' hinj
(is_primitive_of_dvd' hf (dvd.intro_left _ h.symm))
end

end move_me -/
Paul-Lez marked this conversation as resolved.
Show resolved Hide resolved

local attribute [instance] frac_algebra_of_inj

open euclidean_domain

lemma polynomial.eq_zero_of_dvd_of_degree_lt {p q : R[X]} (h₁ : p ∣ q) (h₂ : degree q < degree p) :
q = 0 :=
begin
by_contradiction hc,
exact (lt_iff_not_ge _ _ ).mp h₂ (degree_le_of_dvd h₁ hc),
end

lemma aeval_eq_zero_of_dvd_aeval_eq_zero {p q : R[X]} (h₁ : p ∣ q) {a : S} (h₂ : aeval a p = 0) :
aeval a q = 0 :=
begin
rw [aeval_def, ← eval_map] at h₂ ⊢,
exact eval_eq_zero_of_dvd_of_eval_eq_zero (polynomial.map_dvd (algebra_map R S) h₁) h₂,
end

end preliminary_results

local attribute [instance] frac_algebra_of_inj

theorem algebra_map_minpoly_eq_minpoly [is_integrally_closed R]
[h : fact (function.injective (algebra_map R S))] (ha : is_integral R a) :
(map (algebra_map R (fraction_ring R)) (minpoly R a))
= minpoly (fraction_ring R) (algebra_map S (fraction_ring S) a) :=
begin
--a few "trivial" preliminary results to set up the proof
have lem0 : minpoly (fraction_ring R) (algebra_map S (fraction_ring S) a) ∣
(map (algebra_map R (fraction_ring R)) (minpoly R a)),
{ apply minpoly.dvd (fraction_ring R) (algebra_map S (fraction_ring S) a),
rw [← aeval_commuting_diagram, minpoly.aeval, map_zero],
Paul-Lez marked this conversation as resolved.
Show resolved Hide resolved
exact fraction_algebra_commuting_diagram.symm },

have lem1 : is_integral (fraction_ring R) (algebra_map S (fraction_ring S) a),
{ refine is_integral_of_commuting_diagram (algebra_map R (fraction_ring R)) _
(fraction_algebra_commuting_diagram.symm) ha },

obtain ⟨g, hg⟩ := eq_map_of_dvd (minpoly.monic ha) _ (minpoly.monic lem1) lem0,
have lem2 : aeval a g = 0,
{ have := minpoly.aeval (fraction_ring R) (algebra_map S (fraction_ring S) a),
rw [← hg, ← aeval_commuting_diagram, ← map_zero (algebra_map S (fraction_ring S))] at this,
exact is_fraction_ring.injective S (fraction_ring S) this,
refine fraction_algebra_commuting_diagram.symm },

have lem3 : g.monic,
{ suffices : monic (map (algebra_map R (fraction_ring R)) g),
{ rwa ← monic_map_iff_of_injective at this,
exact is_fraction_ring.injective R (fraction_ring R) },
rw hg,
exact minpoly.monic lem1 },

--the idea of the proof is the following: since the minpoly of `a` over `Frac(R)` divides the
--minpoly of `a` over `R`, it is itself in `R`. Hence its degree is greater or equal to that of
--the minpoly of `a` over `R`. But the minpoly of `a` over `Frac(R)` divides the minpoly of a
--over `R` in `R[X]` so we are done.
suffices: minpoly R a = g,
{ rw [← hg, this] },
refine polynomial.eq_of_monic_of_dvd_of_nat_degree_le lem3 (minpoly.monic ha) _ _,

rwa [← map_dvd_map _ (is_fraction_ring.injective R (fraction_ring R)) lem3, hg],

exact nat_degree_le_nat_degree (minpoly.min R a lem3 lem2),
end

theorem minpoly.dvd' [h : fact (function.injective (algebra_map R S))] [nontrivial R]
[is_integrally_closed R] {a : S} (ha : is_integral R a) (p : R[X]) :
aeval a p = 0 ↔ minpoly R a ∣ p :=
begin
refine ⟨λ hp, _, λ hp, _⟩,

{ have : minpoly (fraction_ring R) (algebra_map S (fraction_ring S) a) ∣
(map (algebra_map R (fraction_ring R)) (p %ₘ (minpoly R a))),
{ rw [map_mod_by_monic _ (minpoly.monic ha), mod_by_monic_eq_sub_mul_div],
refine dvd_sub (minpoly.dvd (fraction_ring R) (algebra_map S (fraction_ring S) a) _) _,
rw [← aeval_commuting_diagram, hp, map_zero],
exact fraction_algebra_commuting_diagram.symm,

apply dvd_mul_of_dvd_left,
rw algebra_map_minpoly_eq_minpoly ha,

exact monic_map_of_monic _ (minpoly.monic ha) },
rw [← algebra_map_minpoly_eq_minpoly ha, map_dvd_map (algebra_map R (fraction_ring R))
(is_fraction_ring.injective R (fraction_ring R)) (minpoly.monic ha)] at this,
rw [← dvd_iff_mod_by_monic_eq_zero (minpoly.monic ha)],
refine polynomial.eq_zero_of_dvd_of_degree_lt this
(degree_mod_by_monic_lt p $ minpoly.monic ha) },

{ simpa only [ring_hom.mem_ker, ring_hom.coe_comp, coe_eval_ring_hom,
coe_map_ring_hom, function.comp_app, eval_map, ← aeval_def] using
aeval_eq_zero_of_dvd_aeval_eq_zero hp (minpoly.aeval R a) }
end

lemma ker_eval [h : fact (function.injective (algebra_map R S))] [nontrivial R]
[is_integrally_closed R] (a : S) (ha : is_integral R a) :
((aeval a).to_ring_hom : R[X] →+* S).ker = ideal.span ({ minpoly R a} : set R[X] ):=
begin
apply le_antisymm,
{ intros p hp,
rwa [ring_hom.mem_ker, to_ring_hom_eq_coe, coe_to_ring_hom, minpoly.dvd' ha,
← ideal.mem_span_singleton] at hp },
{ intros p hp,
rwa [ring_hom.mem_ker, alg_hom.to_ring_hom_eq_coe, alg_hom.coe_to_ring_hom, minpoly.dvd' ha,
← ideal.mem_span_singleton] }
end
13 changes: 13 additions & 0 deletions src/ring_theory/integral_closure.lean
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,19 @@ begin
aeval_alg_hom_apply, aeval_map_algebra_map, aeval_def, hP.2, _root_.map_zero]
end

lemma is_integral_of_commuting_diagram {R S T U : Type*} [nontrivial S] [nontrivial T]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as above about the name. This can maybe be golfed introducing some is_scalar_tower, but I am not sure.

Copy link
Collaborator Author

@Paul-Lez Paul-Lez Jan 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess using is_scalar_tower is equivalent to this, since we have ring_hom.to_algebra. Which one would you think is most useful/practical to use?

[comm_ring R] [comm_ring S] [comm_ring T] [comm_ring U] [algebra R S] [algebra T U]
(φ : R →+* T) (ψ : S →+* U) (h : (algebra_map T U).comp φ = ψ.comp (algebra_map R S))
{a : S} (ha : is_integral R a) : is_integral T (ψ a) :=
begin
rw [is_integral, ring_hom.is_integral_elem] at ⊢ ha,
obtain ⟨p, hp⟩ := ha,
use p.map φ,
refine ⟨monic.map _ hp.left ,_⟩,
Paul-Lez marked this conversation as resolved.
Show resolved Hide resolved
rw [← eval_map, map_map, h, ← map_map, eval_map, eval₂_at_apply,
eval_map, hp.right, map_zero],
end

theorem is_integral_alg_hom_iff {A B : Type*} [ring A] [ring B] [algebra R A] [algebra R B]
(f : A →ₐ[R] B) (hf : function.injective f) {x : A} : is_integral R (f x) ↔ is_integral R x :=
begin
Expand Down
13 changes: 13 additions & 0 deletions src/ring_theory/localization/fraction_ring.lean
Original file line number Diff line number Diff line change
Expand Up @@ -303,10 +303,23 @@ noncomputable instance [is_domain R] [field K] [algebra R K] [no_zero_smul_divis
algebra (fraction_ring R) K :=
ring_hom.to_algebra (is_fraction_ring.lift (no_zero_smul_divisors.algebra_map_injective R _))

lemma fraction_algebra_commuting_diagram [h : fact (function.injective (algebra_map R S))] :
((algebra_map S (fraction_ring S)).comp (algebra_map R S)) = ((algebra_map (fraction_ring R)
(fraction_ring S)).comp (algebra_map R (fraction_ring R))) :=
begin
ext x,
rw [ring_hom.comp_apply, ring_hom.comp_apply, ring_hom.algebra_map_to_algebra,
is_fraction_ring.map, is_localization.map_eq],
end

instance [is_domain R] [field K] [algebra R K] [no_zero_smul_divisors R K] :
is_scalar_tower R (fraction_ring R) K :=
is_scalar_tower.of_algebra_map_eq (λ x, (is_fraction_ring.lift_algebra_map _ x).symm)

noncomputable def frac_algebra_of_inj [algebra R A]
[h : fact (function.injective (algebra_map R A))] : algebra (fraction_ring R) (fraction_ring A):=
Paul-Lez marked this conversation as resolved.
Show resolved Hide resolved
ring_hom.to_algebra (is_fraction_ring.map (fact_iff.mp h))

variables (A)

/-- Given an integral domain `A` and a localization map to a field of fractions
Expand Down
79 changes: 74 additions & 5 deletions src/ring_theory/polynomial/gauss_lemma.lean
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ variables {R : Type*} [comm_ring R] [is_domain R]

namespace polynomial
section normalized_gcd_monoid
variable [normalized_gcd_monoid R]

section
variables {S : Type*} [comm_ring S] [is_domain S] {φ : R →+* S} (hinj : function.injective φ)
Expand All @@ -43,12 +42,12 @@ begin
rcases is_unit_iff.1 h with ⟨_, ⟨u, rfl⟩, hu⟩,
have hdeg := degree_C u.ne_zero,
rw [hu, degree_map_eq_of_injective hinj] at hdeg,
rw [eq_C_of_degree_eq_zero hdeg, is_primitive_iff_content_eq_one,
content_C, normalize_eq_one] at hf,
rwa [eq_C_of_degree_eq_zero hdeg, is_unit_C],
rw [eq_C_of_degree_eq_zero hdeg] at hf,
rw [eq_C_of_degree_eq_zero hdeg, is_unit_C],
refine is_primitive_iff_is_unit_of_C_dvd.mp hf (f.coeff 0) (dvd_refl _),
Paul-Lez marked this conversation as resolved.
Show resolved Hide resolved
end

lemma is_primitive.irreducible_of_irreducible_map_of_injective (h_irr : irreducible (map φ f)) :
/- lemma is_primitive.irreducible_of_irreducible_map_of_injective (h_irr : irreducible (map φ f)) :
irreducible f :=
begin
refine ⟨λ h, h_irr.not_unit (is_unit.map (map_ring_hom φ) h), _⟩,
Expand All @@ -58,10 +57,80 @@ begin
rwa (hf.is_primitive_of_dvd (dvd.intro _ h.symm)).is_unit_iff_is_unit_map_of_injective hinj },
right,
rwa (hf.is_primitive_of_dvd (dvd.intro_left _ h.symm)).is_unit_iff_is_unit_map_of_injective hinj
end -/
Paul-Lez marked this conversation as resolved.
Show resolved Hide resolved

lemma is_primitive.irreducible_of_irreducible_map_of_injective (h_irr : irreducible (map φ f)) :
irreducible f :=
begin
refine ⟨λ h, h_irr.not_unit (is_unit.map (map_ring_hom φ) h), _⟩,
intros a b h,
rcases h_irr.is_unit_or_is_unit (by rw [h, polynomial.map_mul]) with hu | hu,
{ left,
rwa is_primitive.is_unit_iff_is_unit_map_of_injective hinj (is_primitive_of_dvd' hf
(dvd.intro _ h.symm)) },
right,
rwa is_primitive.is_unit_iff_is_unit_map_of_injective hinj
(is_primitive_of_dvd' hf (dvd.intro_left _ h.symm))

Paul-Lez marked this conversation as resolved.
Show resolved Hide resolved
end

variables [algebra R S] {a : S} [is_domain S] [is_domain R]

section preliminary_results

theorem roots_mem_integral_closure {R A} [comm_ring R] [comm_ring A] [is_domain A] [algebra R A]
{f : R[X]} (hf : f.monic) {a : A} (ha : a ∈ (f.map $ algebra_map R A).roots) :
a ∈ integral_closure R A :=
⟨f, hf, (eval₂_eq_eval_map _).trans $ (mem_roots $ (hf.map _).ne_zero).1 ha⟩

theorem coeff_mem_subring_of_splits {K} [field K] {f : K[X]}
(hs : f.splits (ring_hom.id K)) (hm : f.monic) (T : subring K)
(hr : ∀ a ∈ f.roots, a ∈ T) (n : ℕ) : f.coeff n ∈ T :=
begin
rw (_ : f = (f.roots.pmap (λ a h, X - C (⟨a, h⟩ : T)) hr).prod.map T.subtype),
{ rw coeff_map, apply set_like.coe_mem },
conv_lhs { rw [eq_prod_roots_of_splits_id hs, hm.leading_coeff, C_1, one_mul] },
rw [polynomial.map_multiset_prod, multiset.map_pmap],
congr, convert (f.roots.pmap_eq_map _ _ hr).symm,
ext1, ext1, rw [polynomial.map_sub, map_X, map_C], refl,
end

theorem frange_subset_integral_closure {R K} [comm_ring R] [field K] [algebra R K]
{f : R[X]} (hf : f.monic) {g : K[X]} (hg : g.monic) (hd : g ∣ f.map (algebra_map R K)) :
(g.frange : set K) ⊆ (integral_closure R K).to_subring :=
begin
haveI : is_scalar_tower R K g.splitting_field := splitting_field_aux.is_scalar_tower _ _ _,
have := coeff_mem_subring_of_splits ((splits_id_iff_splits _).2 $ splitting_field.splits g)
(hg.map _) (integral_closure R _).to_subring (λ a ha, roots_mem_integral_closure hf _),
{ intros a ha, obtain ⟨n, -, rfl⟩ := mem_frange_iff.1 ha,
obtain ⟨p, hp, he⟩ := this n, use [p, hp],
rw [is_scalar_tower.algebra_map_eq R K, coeff_map, ← eval₂_map, eval₂_at_apply] at he,
rw eval₂_eq_eval_map, apply (injective_iff_map_eq_zero _).1 _ _ he,
{ apply ring_hom.injective } },
rw [is_scalar_tower.algebra_map_eq R K _, ← map_map],
refine multiset.mem_of_le (roots.le_of_dvd ((hf.map _).map _).ne_zero _) ha,
{ apply_instance },
{ exact map_dvd (algebra_map K g.splitting_field) hd },
{ apply splitting_field_aux.is_scalar_tower },
end

theorem eq_map_of_dvd {R} [comm_ring R] [is_domain R] [is_integrally_closed R]
{f : R[X]} (hf : f.monic) (g : (fraction_ring R)[X]) (hg : g.monic)
(hd : g ∣ f.map (algebra_map R _)) : ∃ g' : R[X], g'.map (algebra_map R _) = g :=
begin
let algeq := (subalgebra.equiv_of_eq _ _ $
is_integrally_closed.integral_closure_eq_bot R _).trans
(algebra.bot_equiv_of_injective $ is_fraction_ring.injective R $ fraction_ring R),
have : (algebra_map R _).comp algeq.to_alg_hom.to_ring_hom =
(integral_closure R _).to_subring.subtype,
{ ext, conv_rhs { rw ← algeq.symm_apply_apply x }, refl },
refine ⟨map algeq.to_alg_hom.to_ring_hom _, _⟩,
use g.to_subring _ (frange_subset_integral_closure hf hg hd),
rw [map_map, this], apply g.map_to_subring,
end

end preliminary_results

section fraction_map
variables {K : Type*} [field K] [algebra R K] [is_fraction_ring R K]

Expand Down