\import Algebra.Field \import Algebra.Group \import Algebra.Meta \import Algebra.Monoid \import Algebra.Monoid.Category \import Algebra.Monoid.GCD \import Algebra.Monoid.Sub \import Algebra.Ring \import Algebra.Ring.Localization \import Algebra.Ring.Reduced \import Algebra.Semiring \import Arith.Nat \import Function \import Function.Meta ($) \import Logic \import Logic.Meta \import Meta \import Order.StrictOrder \import Paths \import Paths.Meta \import Relation.Equivalence \import Set \import Set.Fin \open Monoid {- | Domain is a ring with a tight apartness relation such that elements apart from {zro} are closed under finite products. - Classically, this is equivalent to the usual definition since there is a unique apartness relation on a set assuming LEM. -} \class Domain \extends Ring.With#, ImpotentRing, NonZeroRing { | zro#ide : ide `#0 | #0-* {x y : E} : x `#0 -> y `#0 -> (x * y) `#0 | isReduced p => #0-tight \lam a#0 => #0-zro $ transport #0 p (#0-* a#0 a#0) | isImpotent {a} p => \have q : a * (1 - a) = 0 => ldistr_- *> toZero (ide-right *> inv p) \in \case #0-+ (transportInv #0 (+-comm *> +-assoc *> pmap (1 +) negative-left *> zro-right) zro#ide) \with { | byLeft a#0 => byRight $ inv $ fromZero $ #0-tight \lam zro-a#0 => apartNonZero (#0-* a#0 zro-a#0) q | byRight zro-a#0 => byLeft $ #0-tight \lam a#0 => apartNonZero (#0-* a#0 zro-a#0) q } \default zro/=ide zro=ide => #0-zro (transportInv #0 zro=ide zro#ide) \lemma nonZero_* {x y : E} (x/=0 : x /= zro) (y/=0 : y /= zro) : x * y /= zro => \lam x*y=0 => x/=0 (#0-tight (\lam x#0 => y/=0 (#0-tight (\lam y#0 => #0-zro (transport #0 x*y=0 (#0-* x#0 y#0)))))) \lemma nonZero-left {x y : E} (x/=0 : x /= zro) (x*y=0 : x * y = zro) : y = zro => separatedEq (nonZero_* x/=0 __ x*y=0) \lemma nonZero-right {x y : E} (y/=0 : y /= zro) (x*y=0 : x * y = zro) : x = zro => separatedEq (nonZero_* __ y/=0 x*y=0) \lemma nonZero-cancel-left {x y z : E} (x/=0 : x /= zro) (x*y=x*z : x * y = x * z) : y = z => fromZero (nonZero-left x/=0 (ldistr_- *> toZero x*y=x*z)) \lemma nonZero-cancel-right {x y z : E} (z/=0 : z /= zro) (x*z=y*z : x * z = y * z) : x = y => fromZero (nonZero-right z/=0 (rdistr_- *> toZero x*z=y*z)) \func nonZeroMonoid : CancelMonoid \cowith | E => \Sigma (x : E) (x `#0) | ide => (ide, zro#ide) | * x y => (x.1 * y.1, #0-* x.2 y.2) | ide-left => ext ide-left | ide-right => ext ide-right | *-assoc => ext *-assoc | cancel_*-left x {y} {z} x*y=x*z => ext (nonZero-cancel-left (apartNonZero x.2) (pmap __.1 x*y=x*z)) | cancel_*-right z {x} {y} x*z=y*z => ext (nonZero-cancel-right (apartNonZero z.2) (pmap __.1 x*z=y*z)) \func subMonoid : SubMonoid \this \cowith | contains => #0 | contains_ide => zro#ide | contains_* => #0-* \lemma ldiv_nonZero {a b : nonZeroMonoid} (a|b : Monoid.LDiv a.1 b.1) : Monoid.LDiv {nonZeroMonoid} a b \cowith | inv => (a|b.inv, #0-*-right (transportInv #0 a|b.inv-right b.2)) | inv-right => ext a|b.inv-right \func nonZero_ldiv {a b : nonZeroMonoid} (a|b : Monoid.LDiv {nonZeroMonoid} a b) : Monoid.LDiv a.1 b.1 \cowith | inv => a|b.inv.1 | inv-right => pmap __.1 a|b.inv-right \lemma inv_nonZero {a : nonZeroMonoid} (i : Monoid.Inv a.1) : Monoid.Inv {nonZeroMonoid} a \cowith | inv => (i.inv, #0-*-right (transportInv #0 i.inv-right zro#ide)) | inv-left => ext i.inv-left | inv-right => ext i.inv-right \lemma nonZero_inv {a : nonZeroMonoid} (i : Monoid.Inv {nonZeroMonoid} a) : Monoid.Inv a.1 \cowith | inv => i.inv.1 | inv-left => pmap __.1 i.inv-left | inv-right => pmap __.1 i.inv-right \lemma pow_#0 {a : E} {n : Nat} (a#0 : a `#0) : pow a n `#0 \elim n | 0 => zro#ide | suc n => #0-* (pow_#0 a#0) a#0 } \where { \class Dec \extends Domain, Ring.Dec, StrictDomain { \default zeroProduct {x} {y} xy=0 => \case decideEq x zro, decideEq y zro \with { | yes x=0, _ => byLeft x=0 | _, yes y=0 => byRight y=0 | no x/=0, no y/=0 => absurd $ #0-zro $ transport #0 xy=0 $ #0-* (nonZeroApart x/=0) (nonZeroApart y/=0) } \default zro#ide => nonZeroApart (\lam x => zro/=ide (inv x)) \default #0-* x#0 y#0 => nonZeroApart (\lam xy=0 => ||.rec' (apartNonZero x#0) (apartNonZero y#0) (zeroProduct xy=0)) \func LDiv_TruncP {a b : E} (p : TruncP (LDiv a b)) : LDiv a b => \case decideEq a 0 \with { | yes a=0 => LDiv.make 1 \case p \with { | inP (_,q) => later (rewrite a=0 simplify) *> q } | no a/=0 => TruncP.remove (\lam d d' => ext $ nonZero-cancel-left a/=0 $ LDiv.inv-right {d} *> inv (LDiv.inv-right {d'})) p } } } -- | An integral domain is a commutative domain. \class IntegralDomain \extends Domain, CRing.With#, ImpotentCRing, NonZeroCRing { \func nonZeroMonoid : CancelCMonoid \cowith | CancelMonoid => Domain.nonZeroMonoid | *-comm => ext *-comm \lemma div-inv (x y : E) (x/=0 : x /= zro) (x|y : LDiv x y) (y|x : LDiv y x) : Inv x|y.inv => Inv.rmake y|x.inv (Domain.nonZero-cancel-left x/=0 (equation {Monoid})) \func gcd_nonZero {a b : nonZeroMonoid} (gcd : GCD a.1 b.1) : GCD {nonZeroMonoid} a b \cowith | gcd => (gcd.gcd, #0-*-left (transportInv #0 gcd.gcd|val1.inv-right a.2)) | gcd|val1 => ldiv_nonZero gcd.gcd|val1 | gcd|val2 => ldiv_nonZero gcd.gcd|val2 | gcd-univ g g|a g|b => ldiv_nonZero $ gcd.gcd-univ g.1 (nonZero_ldiv g|a) (nonZero_ldiv g|b) \func nonZero_gcd {a b : nonZeroMonoid} (gcd : GCD {nonZeroMonoid} a b) : GCD a.1 b.1 \cowith | gcd => gcd.gcd.1 | gcd|val1 => nonZero_ldiv gcd.gcd|val1 | gcd|val2 => nonZero_ldiv gcd.gcd|val2 | gcd-univ g (g|a : LDiv g a.1) g|b => nonZero_ldiv {_} {g, #0-*-left $ transportInv #0 g|a.inv-right a.2} $ gcd.gcd-univ _ (ldiv_nonZero g|a) (ldiv_nonZero g|b) \lemma divQuotient_LDiv {x y : DivQuotient nonZeroMonoid} : TruncP (LDiv {DivQuotientMonoid \this} (map subMonoid.embed x) (map subMonoid.embed y)) <-> TruncP (LDiv {DivQuotientMonoid nonZeroMonoid} x y) \elim x, y | in~ x, in~ y => (\case __ \with { | inP (in~ z, p) => TruncP.map (make~ p).2 \lam s => div-to~ $ ldiv_nonZero $ LDiv.trans (LDiv.factor-left LDiv.id-div) s }, \case __ \with { | inP (in~ z, p) => TruncP.map (make~ p).2 \lam (xz|y : LDiv (x nonZeroMonoid.* z) y) => \new LDiv (map subMonoid.embed (inD {nonZeroMonoid} x)) (map subMonoid.embed (inD {nonZeroMonoid} y)) (inD (z.1 * xz|y.inv.1)) $ pmap inD $ inv *-assoc *> pmap __.1 xz|y.inv-right }) \lemma toNonZeroDivChain (cc : CMonoid.DivChain {DivQuotientMonoid \this}) : CMonoid.DivChain {DivQuotientMonoid nonZeroMonoid} => \lam a d => \have | (inP s) => cc (\lam i => map subMonoid.embed (a i)) \lam i => divQuotient_LDiv.2 (d i) | (inP d) => divQuotient_LDiv.1 (inP s.2) \in inP (s.1, d) \lemma IsRegular_/=0 {a : E} : IsRegular a <-> a /= 0 => (\lam ar a=0 => zro/=ide $ ar (rewrite a=0 simplify), \lam a/=0 p => nonZero-cancel-left a/=0 p) } \where { \open DivQuotient \class Dec \extends IntegralDomain, Domain.Dec, CRing.Dec, StrictIntegralDomain, PPRing { | isPPRing a => inP \case decideEq a 0 \with { | yes a=0 => (0, rewrite a=0 (inv zro_*-left), \lam _ => zro_*-left) | no a/=0 => (1, inv ide-left, \lam p => ide-left *> nonZero-left a/=0 p) } \lemma fromNonZeroDivChain (cc : CMonoid.DivChain {DivQuotientMonoid nonZeroMonoid}) : CMonoid.DivChain {DivQuotientMonoid \this} => \lam a ac => \have | f => map {SubMonoid.cStruct subMonoid} subMonoid.embed | f-inj : isInj f => \lam {x} {y} => \case \elim x, \elim y \with { | in~ x, in~ y => \lam p => \have t => make~ p \in ~-pequiv (TruncP.map t.1 ldiv_nonZero, TruncP.map t.2 ldiv_nonZero) } | r n (q : Not (∃ (j : Fin (suc (suc n))) (a (suc j) = in~ 0))) => TruncP.rec {_} {\Sigma (x : DivQuotient nonZeroMonoid) (f x = a (suc n))} (\lam s s' => ext $ f-inj $ s.2 *> inv s'.2) (Quotient.in-surj (a (suc n))) \lam s => (in~ (s.1, nonZeroApart \lam s=0 => q $ inP (n, pmap (\lam x => a (suc x)) (toFin'=id $ id<suc <∘ id<suc) *> inv s.2 *> pmap in~ s=0)), s.2) | t => cc (\lam n => \case FinSet.search {FinFin (suc (suc n))} _ (\lam j => divQuotient_dec0 (a (suc j))) \with { | yes e => in~ (1,zro#ide) | no q => (r n q).1 }) (\lam n => mcases {1} \with { | yes e => inP LDiv.ide-div | no q => rewrite (FinSet.search_no_reduce (\lam (j : Fin (suc (suc n))) => divQuotient_dec0 (a (suc j))) (\lam p => q p)) \case ac (suc n) \with { | inP d => divQuotient_LDiv.1 $ inP $ transport2 LDiv (inv (r (suc n) q).2) (inv (r n (\lam p => q p)).2) d } }) \in \case t \with { | inP s => mcases {2} s.2 _ \with { | yes e', s2 => TruncP.map e' \lam e => (e.1, \new LDiv { | inv => in~ 0 | inv-right => cases (a e.1) \with { | in~ b => pmap in~ zro_*-right *> inv e.2 } }) | no q, s2 => rewrite (FinSet.search_no_reduce (\lam (j : Fin (suc (suc s.1))) => divQuotient_dec0 (a (suc j))) (\lam p => q p)) at s2 $ inP (suc s.1, transport2 LDiv (r s.1 (\lam p => q p)).2 (r (suc s.1) q).2 $ MonoidHom.func-LDiv {f} s2) } } \lemma oneDimensional-char : Dim<= 1 <-> (\Pi (a u : E) -> a /= 0 -> ∃ (v : E) (n : Nat) (LDiv a (pow u n * (1 - u * v)))) => (\lam d a u a/=0 => \case d (a,u) \with { | inP (b,m,p) => \have q => nonZero-cancel-left (apartNonZero $ pow_#0 $ nonZeroApart a/=0) (p *> inv zro_*-right) \in inP (b 1, m 1, LDiv.make (b 0) equation) }, \lam f x => \case decideEq (x 0) 0 \with { | yes x0=0 => inP ((1,1), (1,1), rewrite x0=0 simplify) | no x0/=0 => \case f (x 0) (x 1) x0/=0 \with { | inP (v,n,(y,p)) => inP ((y, v), (1, n), equation) } }) } } \instance FieldOfQuotients (D : IntegralDomain.Dec) : DiscreteField \cowith | CRing => LocRing D.subMonoid | zro/=ide p => \case LocRing.unequals p \with { | inP (c,c#0,q) => D.#0-zro (transport D.#0 equation c#0) } | eitherZeroOrInv => \case \elim __ \with { | in~ x => \case decideEq x.1 0 \with { | yes e => byLeft $ LocRing.equals1 $ ide-right *> e *> inv zro_*-left | no q => byRight $ Monoid.Inv.lmake (inl~ (x.2, x.1, AddGroup.nonZeroApart q)) $ LocRing.equals1 (simplify *-comm) } } \class StrictDomain \extends Ring, NonZeroSemiring, ImpotentRing { | zeroProduct {x y : E} : x * y = zro -> (x = zro) || (y = zro) | isReduced => \case zeroProduct __ \with { | byLeft r => r | byRight r => r } | isImpotent {a} p => \have q : a * (a - 1) = 0 => ldistr_- *> toZero (p *> inv ide-right) \in \case zeroProduct q \with { | byLeft r => byLeft r | byRight r => byRight (fromZero r) } \lemma zeroBigProd {l : Array E} (p : BigProd l = zro) : ∃ (j : Fin l.len) (l j = 0) \elim l | nil => absurd $ zro/=ide (inv p) | a :: l => \case zeroProduct p \with { | byLeft r => inP (0,r) | byRight r => TruncP.map (zeroBigProd r) \lam s => (suc s.1, s.2) } \lemma zeroOrCancel-left {x y z : E} (p : x * y = x * z) : (x = 0) || (y = z) => \case zeroProduct $ ldistr_- *> toZero p \with { | byLeft x=0 => byLeft x=0 | byRight y-z=0 => byRight (fromZero y-z=0) } \lemma zeroOrCancel-right {x y z : E} (p : x * z = y * z) : (x = y) || (z = 0) => \case zeroProduct $ rdistr_- *> toZero p \with { | byLeft x-y=0 => byLeft (fromZero x-y=0) | byRight z=0 => byRight z=0 } \lemma nonZero-cancel-left {x y z : E} (x/=0 : x /= 0) (p : x * y = x * z) : y = z => \case zeroOrCancel-left p \with { | byLeft x=0 => absurd (x/=0 x=0) | byRight r => r } \lemma nonZero-cancel-right {x y z : E} (z/=0 : z /= 0) (p : x * z = y * z) : x = y => \case zeroOrCancel-right p \with { | byLeft r => r | byRight z=0 => absurd (z/=0 z=0) } } \class StrictIntegralDomain \extends StrictDomain, ImpotentCRing { \lemma div-associates {a b : E} (a|b : LDiv a b) (b|a : LDiv b a) : TruncP (associates a b) => \case zeroOrCancel-left $ inv *-assoc *> pmap (`* _) a|b.inv-right *> b|a.inv-right *> inv ide-right \with { | byLeft a=0 => inP (Inv.ide-isInv, a=0 *> inv (ldiv=0 a|b a=0) *> inv ide-left) | byRight r => inP (Inv.lmake _ r, inv b|a.inv-right *> *-comm) } }