import tactic.basic

-- A ballot is a pair consisting a round number and a process
-- identifier. Process identifiers must be linearly ordered. Under this
-- constraint, ballots are totally ordered.
--
-- example: "fin 3" is a valid pid_t, but bool is not.
structure ballot (pid_t : Type) [linear_order pid_t] :=
  (round : ℕ) (address : pid_t)

namespace ballot

variables {pid_t : Type}  [linear_order pid_t]

-- Ballots are ordered lexicographically, and this is a total order.
def le : ballot pid_t → ballot pid_t → Prop :=
  λ b₁ b₂, b₁.round < b₂.round ∨ (b₁.round = b₂.round ∧ b₁.address ≤ b₂.address)

instance has_le : has_le (ballot pid_t) := ⟨le⟩

def lt  : ballot pid_t → ballot pid_t → Prop :=
  λ b₁ b₂, b₁.round < b₂.round ∨ (b₁.round = b₂.round ∧ b₁.address < b₂.address)

instance has_lt : has_lt (ballot pid_t) := ⟨lt⟩

lemma le_refl (b : ballot pid_t) : b ≤ b :=
begin
cases b,
right,
split; refl
end

lemma le_trans (n m k : ballot pid_t) : n ≤ m → m ≤ k → n ≤ k :=
begin
intros h1 h2,
cases n,
cases m,
cases k,
cases h1 with round1_lt address1_lt;
cases h2 with round2_lt address2_lt,
{ left, exact lt_trans round1_lt round2_lt },
{ left, rw ← address2_lt.left, exact round1_lt },
{ left, rw address1_lt.left, exact round2_lt },
right,
split,
{ exact eq.trans address1_lt.left address2_lt.left },
exact le_trans address1_lt.right address2_lt.right
end

lemma lt_iff_le_not_le (m n : ballot pid_t) : m < n ↔ (m ≤ n ∧ ¬ n ≤ m) :=
begin
cases m, cases n,
split,
{ intro hyp_less,
  split,
  { cases hyp_less with rounds addresses,
    { exact or.inl rounds },
    { exact or.inr ⟨addresses.left, le_of_lt addresses.right⟩ }},
  intro hyp_ge,
  cases hyp_less with rounds_less pids_less;
  cases hyp_ge with rounds_ge pids_ge,
  { exact lt_asymm rounds_less rounds_ge },
  { rw pids_ge.left at rounds_less,
    exact lt_irrefl m_round rounds_less },
  { rw pids_less.left at rounds_ge,
    exact lt_irrefl n_round rounds_ge },
  exact lt_irrefl m_address (lt_of_lt_of_le pids_less.right pids_ge.right)
  },
rintros ⟨hyp_le, hyp_not_le⟩,
cases hyp_le with rounds pids,
{ exact or.inl rounds },
suffices key : m_address ≠ n_address,
by { exact or.inr ⟨pids.left, lt_of_le_of_ne pids.right key⟩ },
intro pids_equal,
apply hyp_not_le,
right,
split,
{ exact eq.symm pids.left },
exact le_of_eq (eq.symm pids_equal)
end

lemma le_antisymm (n m : ballot pid_t) : n ≤ m → m ≤ n → n = m :=
begin
intros h1 h2,
cases n,
cases m,
suffices key : n_round = m_round ∧ n_address = m_address,
by { rwa [key.left, key.right] },
have rounds_eq : n_round = m_round,
by {
  apply le_antisymm,
  { cases h1,
    { exact le_of_lt h1 },
    exact le_of_eq h1.left },
  cases h2,
  { exact le_of_lt h2 },
  exact le_of_eq h2.left
},
split,
{ exact rounds_eq },
apply le_antisymm,
{ cases h1,
  { exact (ne_of_lt h1 rounds_eq).elim },
  exact h1.right },
cases h2,
{ exact (ne_of_lt h2 (eq.symm rounds_eq)).elim },
exact h2.right
end

lemma le_total (n m : ballot pid_t) : n ≤ m ∨ m ≤ n :=
begin
cases n,
cases m,
cases lt_trichotomy n_round m_round with lt ge,
{ exact or.inl (or.inl lt) },
cases ge with equal gt,
{ cases le_total n_address m_address with le ge,
  { exact or.inl (or.inr ⟨equal, le⟩) },
  exact or.inr (or.inr ⟨eq.symm equal, ge⟩) },
exact or.inr (or.inl gt),
end

instance decidable_le : ∀ b₁ b₂ : ballot pid_t, decidable (b₁ ≤ b₂) :=
begin
intros b₁ b₂,
exact or.decidable
end

instance decidable_eq : decidable_eq (ballot pid_t) :=
begin
intros b₁ b₂,
suffices key : decidable (b₁.round = b₂.round ∧ b₁.address = b₂.address),
by {
  apply decidable_of_decidable_of_iff key,
  split,
  { rintros ⟨rounds_eq, addresses_eq⟩,
    cases b₁,
    cases b₂,
    unfold ballot.round at rounds_eq,
    unfold ballot.address at addresses_eq,
    rwa [rounds_eq, addresses_eq] },
  intro hyp,
  rw hyp,
  exact ⟨eq.refl b₂.round, eq.refl b₂.address⟩
},
apply_instance
end

instance decidable_lt : ∀ b₁ b₂ : ballot pid_t, decidable (b₁ < b₂) :=
begin
intros b₁ b₂,
exact or.decidable
end

instance linear_order : linear_order (ballot pid_t) :=
{ le := ballot.le,
  le_refl := ballot.le_refl,
  le_trans := ballot.le_trans,
  le_antisymm := ballot.le_antisymm,
  le_total := ballot.le_total,
  lt := ballot.lt,
  lt_iff_le_not_le := ballot.lt_iff_le_not_le,
  decidable_lt := ballot.decidable_lt,
  decidable_eq := ballot.decidable_eq,
  decidable_le := ballot.decidable_le }

-- For any process id p and ballot b, there is a ballot belonging to p which is
-- strictly greater than b. Specifically, `next p b` is such a ballot.
--
-- NOTE(gnanabit): we could keep the round number the same if the other pid is
-- less than ours, but this is a bit easier to work with.
def next (p : pid_t) : ballot pid_t → ballot pid_t :=
  λ b, { round := b.round.succ, address := b.address }

theorem next_larger :
  ∀ (p : pid_t) (b : ballot pid_t), b < next p b :=
begin
intros p b,
left,
exact nat.lt_succ_self b.round
end

end ballot


/-
Copyright (c) 2021 Paula Neeley. All rights reserved.
Authors : Paula Neeley
-/

import syntax.syntaxCL
import syntax.axiomsCL
import semantics.semanticsCL
-- import basicmodal.semantics.definability basicmodal.syntax.syntaxlemmas
local attribute [instance] classical.prop_decidable

open set

variable {agents : Type}

---------------------- Soundness ----------------------

theorem soundnessCL (φ : formCL agents) : '⊢ φ → '⊨ φ :=
begin
  intro h,
  induction h,
  -- case Prop1
  { intros m s h1 h2,
    exact h1, },
  -- case Prop2
  { intros m s h1 h2 h3,
    apply h1,
      { exact h3,},
      { apply h2,
        exact h3 }, },
  -- case Prop3
  { intros m s h1 h2,
    by_contradiction hf,
    exact (h1 hf) (h2 hf), },
  -- case Prop4
  { intros m s h1 h2,
    exact and.intro h1 h2, },
  -- case Prop5
  { intros m s h1,
    exact h1.left, },
  -- case Prop6
  { intros m s h1,
    exact h1.right, },
  -- case Prop7
  { intros m s h1 h2,
    by_contradiction hf,
    exact h1 hf h2, },
  -- case ⊥
  { intros m s h1,
    exact m.f.E.liveness s h h1, },
  -- case ⊤
  { intros m s,
    simp [s_entails_CL],
    exact m.f.E.safety s h, },
  -- case N
  { intros m s h1,
    apply m.f.E.N_max,
    by_contradiction,
    exact h1 h, },
  -- case M
  { intros m s,
    apply m.f.E.mono s h_G _ {t | ⟨m, t⟩ '⊨ h_φ},
    intros t h1,
    exact h1.left, },
  -- case S
  { intros m s h1,
    exact m.f.E.superadd s h_G h_F _ _ h1.left h1.right h_hInt, },
  -- case MP
  { intros m s,
    apply h_ih_hImp,
    exact h_ih_hL m s, },
  -- case Eq
  { intros m s,
    have heq : {t | ⟨m, t⟩ '⊨ h_φ} = {t | ⟨m, t⟩ '⊨ h_ψ}, from
      begin
        apply set.ext,
        intro u,
        apply iff.intro,
        { intro hu,
          exact (h_ih m u).left hu, },
        { intro hu,
          exact (h_ih m u).right hu, },
      end,
    apply and.intro,
    { intro h1,
      simp[s_entails_CL] at *,
      rw ←heq,
      exact h1, },
    { intro h1,
      simp[s_entails_CL] at *,
      rw heq,
      exact h1, }, },
end

-- create an example Model
inductive single : Type
  | one : single

lemma univ_single : (set.univ : set single) = {single.one} :=
begin
  rw eq_comm,
  rw set.eq_univ_iff_forall,
  intro x,
  cases x,
  simp,
end

lemma single_nonempty : nonempty single :=
begin
  apply exists_true_iff_nonempty.mp,
  apply exists.intro single.one,
  exact trivial,
end

def m_ex : modelCL agents :=
{ f :=
  { states := single,
    hs := single_nonempty,
    E  :=
    { E := λ s G, {{single.one}},
      liveness :=
      begin
        intros _ _ hf,
        simp at hf,
        rw set.ext_iff at hf,
        simp at hf,
        apply hf single.one,
        refl,
      end,
      safety :=
        begin
          intros _ _, simp at *,
          exact univ_single,
        end,
      N_max :=
        begin
          intros _ _ hxc, simp at *,
          rw ←univ_single at *,
          have hcond : {single.one} ≠ (∅ : set single),

            { intro hf,
              rw set.ext_iff at hf,
              simp at *,
              apply hf single.one,
              refl, },
          simp [hcond] at *, by_contradiction,
          have hex : ∃ x, x ∈ X, from nonempty_def.mp (ne_empty_iff_nonempty.mp hxc),
          cases hex with s hs,
          cases s,
          rw ←singleton_subset_iff at hs,
          rw ←univ_single at hs,
          exact h (univ_subset_iff.mp hs),
        end,
      mono :=
        begin
          intros _ _ _ _ hxy hx,
          simp [←univ_single] at *,
          rw hx at hxy,
          exact univ_subset_iff.mp hxy,
        end,
      superadd :=
      begin
        intros _ _ _ _ _ hX hY hGF,
        simp at *,
        simp[hX, hY],
      end } },
  v := λ _, {}, }

lemma nprfalseCL {agents : Type} : ¬ ('⊢ ('⊥ : formCL agents)) :=
begin
  -- prove with the contrapositive of soundness : ¬ ⊨ ⊥
  apply (mt (soundnessCL (@formCL.bot agents))),
  -- assume by contradiction : ⊨ ⊥
  intro hf,
  -- ⊨ ⊥ only holds if no model with states exists
  simp[global_valid, valid_m, s_entails_CL] at hf,
  -- we create an example model with a single state to prove a contradiction
  exact hf (m_ex) single.one,
end


import algebraic_topology.simplicial_object
import ring_theory.int.basic

import polyhedral_lattice.finsupp
import polyhedral_lattice.category
import polyhedral_lattice.quotient

/-!
# The Čech conerve attached to `Λ → Λ'`

Let `f : Λ → Λ'` be a morphism of polyhedral lattices.
(We probably need to assume that the cokernel is torsion-free...)

In this file we construct the Čech conerve attached to `f`.

Concretely, but in pseudo-code:
it consists of the objects `Λ'^(m)` defined as `(Λ')^m/L`,
where `L` is the sublattice `Λ ⊗ {x : ℤ^m | ∑ x = 0}`.
-/

noncomputable theory

open_locale big_operators

namespace polyhedral_lattice

variables {Λ Λ' : Type*} [polyhedral_lattice Λ] [polyhedral_lattice Λ']
variables (f : polyhedral_lattice_hom Λ Λ')

namespace conerve

section objects

/-!
## The objects
-/

variables (m : ℕ)

def L : add_subgroup (fin m →₀ Λ') :=
{ carrier := { l' | ∑ i, l' i = 0 ∧ ∀ i, ∃ l, f l = l' i},
  zero_mem' := ⟨finset.sum_const_zero, λ i, ⟨0, f.map_zero⟩⟩,
  add_mem' :=
  begin
    rintro l'₁ l'₂ ⟨hl'₁, Hl'₁⟩ ⟨hl'₂, Hl'₂⟩,
    refine ⟨_, _⟩,
    { simp only [finsupp.add_apply, finset.sum_add_distrib, hl'₁, hl'₂, add_zero] },
    { intro i,
      obtain ⟨l₁, hl₁⟩ := Hl'₁ i,
      obtain ⟨l₂, hl₂⟩ := Hl'₂ i,
      refine ⟨l₁ + l₂, _⟩,
      rw [f.map_add, hl₁, hl₂, finsupp.add_apply] }
  end,
  neg_mem' :=
  begin
    rintro l' ⟨hl', Hl'⟩,
    refine ⟨_, _⟩,
    { simp only [finsupp.neg_apply, finset.sum_neg_distrib, hl', neg_zero] },
    { intro i,
      obtain ⟨l, hl⟩ := Hl' i,
      refine ⟨-l, _⟩,
      rw [f.map_neg, hl, finsupp.neg_apply] }
  end }

instance L_saturated [hf : fact f.to_add_monoid_hom.range.saturated] :
  fact (L f m).saturated :=
begin
  constructor,
  rw add_subgroup.saturated_iff_nsmul,
  rintro n l' ⟨hl', Hl'⟩,
  simp only [zsmul_eq_smul, finsupp.smul_apply, ← finset.smul_sum, smul_eq_zero] at hl' Hl',
  rw or_iff_not_imp_left,
  intro hn,
  refine ⟨hl'.resolve_left hn, λ i, _⟩,
  obtain ⟨li, hli⟩ := Hl' i,
  have hl'i : n • l' i ∈ f.to_add_monoid_hom.range,
  { rw [← hli, add_monoid_hom.mem_range], refine ⟨li, rfl⟩ },
  have Hf := hf.1,
  exact (Hf hl'i).resolve_left hn,
end

section open finsupp

lemma L_le_comap {n} (g : fin (n+1) → fin (m+1)) :
  (L f (n+1)) ≤ (L f (m+1)).comap (map_domain.add_monoid_hom g) :=
begin
  rintro l' ⟨hl', Hl'⟩,
  rw add_subgroup.mem_comap,
  refine ⟨_, _⟩,
  { have aux1 : l'.sum (λ _, add_monoid_hom.id _) = ∑ i, l' i,
    { exact finsupp.sum_fintype _ _ (λ _, rfl) },
    have aux2 := @sum_map_domain_index_add_monoid_hom _ _ _ _ _ _ g l' (λ _, add_monoid_hom.id _),
    dsimp only at aux2,
    rw [aux1, finsupp.sum_fintype, hl'] at aux2,
    { simpa only [add_monoid_hom.id_apply] using aux2 },
    { intro, refl } },
  { intro i,
    choose l hl using Hl',
    simp only [map_domain.add_monoid_hom_apply, map_domain],
    refine ⟨∑ j, if g j = i then (l j) else 0, _⟩,
    rw [finsupp.sum_apply, finsupp.sum_fintype],
    swap, { intro, simp only [coe_zero, pi.zero_apply, single_zero] },
    simp only [f.map_sum, single_apply, ← hl],
    apply fintype.sum_congr,
    intro j, split_ifs,
    { refl },
    { exact f.map_zero } }
end

@[simp] lemma L_one : L f 1 = ⊥ :=
begin
  rw eq_bot_iff,
  rintro l' ⟨hl', Hl'⟩,
  simp only [fin.default_eq_zero, finset.univ_unique, finset.sum_singleton] at hl',
  simp only [add_subgroup.mem_bot, finsupp.ext_iff, coe_zero, pi.zero_apply],
  intro i, fin_cases i, exact hl'
end

end

def obj := (fin m →₀ Λ') ⧸ (L f m)

instance : normed_add_comm_group (obj f m) :=
add_subgroup.normed_add_comm_group_quotient _

def π : normed_add_group_hom (fin m →₀ Λ') (obj f m) :=
(L f m).normed_mk

lemma π_apply_eq_zero_iff (x : fin m →₀ Λ') : π f m x = 0 ↔ x ∈ L f m :=
quotient_add_group.eq_zero_iff _

lemma π_surjective : function.surjective (π f m) :=
quotient.surjective_quotient_mk'

lemma norm_π_one_eq (l : fin 1 →₀ Λ') : ∥(π f 1) l∥ = ∥l∥ :=
begin
  delta π, dsimp,
  show ∥(quotient_add_group.mk' (L f 1)) l∥ = ∥l∥,
  rw quotient_norm_mk_eq (L f 1) l,
  simp only [L_one, set.image_singleton, add_zero, cInf_singleton, add_subgroup.coe_bot],
end

lemma π_is_quotient : (π f m).is_quotient :=
normed_add_group_hom.is_quotient_quotient _

instance [fact f.to_add_monoid_hom.range.saturated] : polyhedral_lattice (obj f m) :=
by { delta obj, apply_instance }

end objects

section maps

/-!
## The simplicial maps
-/

open finsupp

variables {n m k : ℕ} (g : fin (n+1) → fin (m+1)) (g' : fin (m+1) → fin (k+1))

-- the underlying morphism of additive groups
def map_add_hom : obj f (n+1) →+ obj f (m+1) :=
quotient_add_group.map _ _ (map_domain.add_monoid_hom g) (L_le_comap f _ g)

lemma map_domain_add_monoid_hom_strict (x : fin (n+1) →₀ Λ) : ∥map_domain.add_monoid_hom g x∥ ≤ ∥x∥ :=
begin
  simp only [norm_def, map_domain.add_monoid_hom_apply],
  dsimp [map_domain],
  rw [sum_fintype], swap, { intro, exact norm_zero },
  simp only [sum_apply],
  rw [sum_fintype], swap, { intro, exact norm_zero },
  calc ∑ i, ∥x.sum (λ j l, single (g j) l i)∥
      ≤ ∑ i, ∑ j, ∥single (g j) (x j) i∥ : _
  ... ≤ ∑ j, ∥x j∥ : _,
  { apply finset.sum_le_sum,
    rintro i -,
    rw sum_fintype, swap, { intro, rw [single_zero, zero_apply] },
    exact norm_sum_le _ _ },
  { rw finset.sum_comm,
    apply finset.sum_le_sum,
    rintro j -,
    simp only [single_apply, norm_zero, apply_ite norm],
    apply le_of_eq,
    simp only [finset.sum_ite_eq, finset.mem_univ, if_true], }
end

lemma map_add_hom_strict (x : obj f (n+1)) : ∥map_add_hom f g x∥ ≤ ∥x∥ :=
begin
  apply le_of_forall_pos_le_add,
  intros ε hε,
  obtain ⟨x, rfl, h⟩ := norm_mk_lt x hε,
  calc _ ≤ ∥map_domain.add_monoid_hom g x∥ : quotient_norm_mk_le _ _
  ... ≤ ∥x∥ : map_domain_add_monoid_hom_strict _ _
  ... ≤ _ : h.le,
end

lemma map_add_hom_mk (x : fin (n+1) →₀ Λ') :
  (map_add_hom f g) (quotient_add_group.mk x) =
    quotient_add_group.mk (map_domain.add_monoid_hom g x) :=
rfl

@[simp] lemma map_add_hom_π (x : fin (n+1) →₀ Λ') :
  (map_add_hom f g) (π _ _ x) = π _ _ (map_domain.add_monoid_hom g x) :=
rfl

variables [fact f.to_add_monoid_hom.range.saturated]

@[simps]
def map : polyhedral_lattice_hom (obj f (n+1)) (obj f (m+1)) :=
{ strict' := map_add_hom_strict f g,
  .. map_add_hom f g }

lemma map_id : map f (id : fin (m+1) → fin (m+1)) = polyhedral_lattice_hom.id :=
begin
  ext x,
  apply quotient_add_group.induction_on x; clear x,
  intro x,
  simp only [add_monoid_hom.to_fun_eq_coe, map_apply, polyhedral_lattice_hom.id_apply,
    map_add_hom_mk, map_domain.add_monoid_hom_apply, map_domain_id],
end

lemma map_comp : map f (g' ∘ g) = (map f g').comp (map f g) :=
begin
  ext x,
  apply quotient_add_group.induction_on x; clear x,
  intro x,
  simp only [add_monoid_hom.to_fun_eq_coe, map_apply, polyhedral_lattice_hom.comp_apply,
    map_add_hom_mk, map_domain.add_monoid_hom_apply, ← map_domain_comp],
end

end maps

lemma lift'_w {M : Type*} [add_comm_group M] (m : ℕ) (g₀ : Λ →+ M)
  (g : fin (m + 1) → (Λ' →+ M)) (hg : ∀ i l, (g i) (f l) = g₀ l)
  (hf : function.injective f) :
  ∀ (l : fin (m + 1) →₀ Λ') (hl : l ∈ L f (m + 1)), finsupp.lift_add_hom g l = 0 :=
begin
  rintro l ⟨h1, h2⟩,
  choose l₀ hl₀ using h2,
  dsimp only [finsupp.lift_add_hom_apply],
  rw [finsupp.sum_fintype],
  swap, { intro j, exact (g j).map_zero },
  simp only [← hl₀, hg, ← g₀.map_sum, ← f.map_sum] at h1 ⊢,
  rw [← polyhedral_lattice_hom.coe_to_add_monoid_hom] at h1 hf,
  rw [injective_iff_map_eq_zero] at hf,
  rw [hf _ h1, g₀.map_zero],
end

def lift' {M : Type*} [add_comm_group M] (m : ℕ) (g₀ : Λ →+ M)
  (g : fin (m + 1) → (Λ' →+ M)) (hg : ∀ i l, (g i) (f l) = g₀ l)
  (hf : function.injective f) :
  obj f (m + 1) →+ M :=
begin
  let Ψ := quotient_add_group.lift
    (polyhedral_lattice.conerve.L f (m + 1))
    (finsupp.lift_add_hom g) (lift'_w f m g₀ g hg hf),
  exact Ψ,
end

end conerve

end polyhedral_lattice

namespace PolyhedralLattice

universe variables u

open polyhedral_lattice simplex_category _root_.category_theory

variables {Λ Λ' : PolyhedralLattice.{u}} (f : Λ ⟶ Λ') [fact f.to_add_monoid_hom.range.saturated]

namespace Cech_conerve

def obj (m : ℕ) : PolyhedralLattice := of (conerve.obj f (m+1))

section open finsupp

def map_succ_zero_aux (m : ℕ) (g : fin (m+2) →o fin 1) : obj f (m+1) →+ Λ' :=
(apply_add_hom (0 : fin 1)).comp $
begin
  -- TODO: this is very ugly
  let foo := quotient_add_group.lift (conerve.L f (m + 1 + 1)) (map_domain.add_monoid_hom g),
  refine foo _,
  rintro l' ⟨hl', Hl'⟩,
  ext i,
  simp only [map_domain.add_monoid_hom_apply, map_domain, sum_apply, single_apply, zero_apply],
  rw [finsupp.sum_fintype],
  swap, { simp only [forall_const, if_true, eq_iff_true_of_subsingleton] },
  convert hl',
  ext, rw if_pos, exact subsingleton.elim _ _
end

end

def map_succ_zero (m : ℕ) (g : fin (m+2) →o fin 1) : obj f (m+1) ⟶ Λ' :=
{ strict' :=
  begin
    intro x,
    apply le_of_forall_pos_le_add,
    intros ε hε,
    obtain ⟨x, rfl, h⟩ := norm_mk_lt x hε,
    calc ∥finsupp.map_domain.add_monoid_hom g x 0∥
        ≤ ∥finsupp.map_domain.add_monoid_hom g x∥ : _
    ... ≤ ∥x∥ : conerve.map_domain_add_monoid_hom_strict g x
    ... ≤ _ : h.le,
    rw [finsupp.norm_def, finsupp.sum_fintype, fin.sum_univ_succ, fin.sum_univ_zero, add_zero],
    intro, exact norm_zero
  end,
  .. map_succ_zero_aux f m g }

def finsupp_fin_one_iso : of (fin 1 →₀ Λ') ≅ Λ' :=
iso.symm $ PolyhedralLattice.iso_mk
  (finsupp.single_add_hom 0) (finsupp.apply_add_hom 0)
  (λ l, by { dsimp [finsupp.norm_def], simp only [norm_zero, finsupp.sum_single_index] })
  (by { ext l, dsimp, simp only [finsupp.single_eq_same] })
  (by { ext f, dsimp, simp only [finsupp.single_eq_same] })
.

@[simp] lemma finsupp_fin_one_iso_hom (l') :
  (@finsupp_fin_one_iso Λ').hom l' = finsupp.apply_add_hom (0 : fin 1) l':= rfl

@[simp] lemma finsupp_fin_one_iso_inv (l') :
  (@finsupp_fin_one_iso Λ').inv l' = finsupp.single_add_hom (0 : fin 1) l':= rfl

/-- the left hand side is by definition the quotient of the right hand side
by a subgroup that is provably trivial -/
def obj_zero_iso' : obj f 0 ≅ of (fin 1 →₀ Λ') :=
iso.symm $ PolyhedralLattice.iso_mk
  (polyhedral_lattice.conerve.π _ _).to_add_monoid_hom
  (quotient_add_group.lift _ (add_monoid_hom.id _)
    (by { intros x hx, rwa [polyhedral_lattice.conerve.L_one, add_subgroup.mem_bot] at hx }))
  (polyhedral_lattice.conerve.norm_π_one_eq _)
  (by ext; refl) (by ext ⟨x⟩; refl)

-- @[simp] lemma obj_zero_iso'_hom (l') :
--   (obj_zero_iso' f).hom l' = _ := rfl

@[simp] lemma obj_zero_iso'_inv (l') :
  (obj_zero_iso' f).inv l' = polyhedral_lattice.conerve.π _ _ l':= rfl

def obj_zero_iso : obj f 0 ≅ Λ' := obj_zero_iso' _ ≪≫ finsupp_fin_one_iso

def π_hom (m : ℕ) : of (fin (m+1) →₀ Λ') ⟶ obj f m :=
{ to_fun := conerve.π f (m+1),
  strict' := (conerve.π_is_quotient f (m+1)).norm_le,
  .. conerve.π f (m+1) }

instance (m : ℕ) : epi (π_hom f m) :=
concrete_category.epi_of_surjective _ $ conerve.π_surjective f (m+1)

lemma map_const_obj_zero_iso (m : ℕ) (i : fin (m+1)) (l : Λ') :
  conerve.map f (λ _, i) ((obj_zero_iso f).inv l) =
    conerve.π f (m+1) (finsupp.single i l) :=
begin
  dsimp only [conerve.map_apply, add_monoid_hom.to_fun_eq_coe,
    conerve.map_add_hom, obj_zero_iso, iso.trans_inv,
    finsupp.single_add_hom_apply],
  simp only [comp_apply, finsupp_fin_one_iso_inv, obj_zero_iso'_inv, conerve.π],
  delta quotient_add_group.map,
  erw quotient_add_group.lift_mk',
  simp only [add_monoid_hom.comp_apply],
  simp only [finsupp.map_domain.add_monoid_hom_apply, finsupp.single_add_hom_apply,
    finsupp.map_domain_single, add_subgroup.normed_mk.apply],
end

end Cech_conerve

open Cech_conerve

@[simps] def Cech_conerve : cosimplicial_object PolyhedralLattice :=
{ obj := λ n, obj f n.len,
  map := λ n m g, conerve.map f g.to_order_hom,
  map_id' := λ _, conerve.map_id f,
  map_comp' := λ _ _ _ _ _, conerve.map_comp f _ _ }

@[simps] def Cech_augmentation_map : Λ ⟶ (Cech_conerve f).obj (mk 0) :=
f ≫ (obj_zero_iso f).inv

def augmented_Cech_conerve : cosimplicial_object.augmented PolyhedralLattice :=
(Cech_conerve f).augment Λ (Cech_augmentation_map f)
begin
  intros n g₁ g₂,
  ext l : 2,
  simp only [comp_apply, Cech_augmentation_map_apply, Cech_conerve_map, conerve.map_apply,
    add_monoid_hom.to_fun_eq_coe, obj_zero_iso, iso.trans_inv, finsupp.single_add_hom_apply,
    finsupp_fin_one_iso_inv, obj_zero_iso'_inv],
  have H1 := conerve.map_add_hom_π f (g₁.to_order_hom) (finsupp.single 0 (f l)),
  have H2 := conerve.map_add_hom_π f (g₂.to_order_hom) (finsupp.single 0 (f l)),
  refine H1.trans (eq.trans _ H2.symm), clear H1 H2,
  simp only [finsupp.map_domain_single, finsupp.map_domain.add_monoid_hom_apply],
  rw [← sub_eq_zero, ← _root_.map_sub, conerve.π_apply_eq_zero_iff],
  refine ⟨_, λ i, _⟩,
  { simp only [finsupp.sub_apply, finset.sum_sub_distrib, sub_eq_zero, finsupp.single_apply,
      finset.sum_ite_eq, finset.mem_univ, if_true], },
  { by_cases H : g₁.to_order_hom 0 = g₂.to_order_hom 0,
    { refine ⟨0, _⟩, simp only [H, sub_self, f.map_zero, finsupp.zero_apply], },
    simp only [finsupp.sub_apply, finsupp.single_apply],
    by_cases h₁ : i = g₁.to_order_hom 0,
    { refine ⟨l, _⟩, subst i,
      simp only [if_neg (ne.symm H), if_true, eq_self_iff_true, sub_zero], },
    by_cases h₂ : i = g₂.to_order_hom 0,
    { refine ⟨-l, _⟩, subst i,
      simp only [if_neg H, if_true, eq_self_iff_true, zero_sub, f.map_neg], },
    { refine ⟨0, _⟩, simp only [if_false, ne.symm h₁, ne.symm h₂, f.map_zero, sub_zero], } }
end

lemma augmentation_map_equalizes :
  Cech_augmentation_map f ≫ (Cech_conerve f).map (δ 0) =
  Cech_augmentation_map f ≫ (Cech_conerve f).map (δ 1) :=
begin
  ext l,
  simp only [conerve.map_apply, add_monoid_hom.to_fun_eq_coe, Cech_augmentation_map_apply,
    Cech_conerve_map, comp_apply, finsupp.single_add_hom_apply, obj_zero_iso, iso.trans_inv,
    finsupp_fin_one_iso_inv, obj_zero_iso'_inv],
  have H1 := conerve.map_add_hom_π f (@hom.to_order_hom (mk 0) _ (δ 0)) (finsupp.single 0 (f l)),
  have H2 := conerve.map_add_hom_π f (@hom.to_order_hom (mk 0) _ (δ 1)) (finsupp.single 0 (f l)),
  refine H1.trans (eq.trans _ H2.symm), clear H1 H2,
  show (conerve.π f 2) _ = (conerve.π f 2) _,
  simp only [finsupp.map_domain_single, finsupp.map_domain.add_monoid_hom_apply],
  rw [← sub_eq_zero, ← _root_.map_sub, conerve.π_apply_eq_zero_iff],
  have hδ0 : hom.to_order_hom (δ (0 : fin 2)) 0 = 1 := rfl,
  have hδ1 : hom.to_order_hom (δ (1 : fin 2)) 0 = 0 := rfl,
  erw [hδ0, hδ1],
  refine ⟨_, λ i, _⟩,
  { simp only [fin.sum_univ_succ, fin.sum_univ_zero, add_zero, finsupp.sub_apply,
      len_mk, finsupp.single_apply, fin.one_eq_zero_iff, if_true, zero_sub, fin.zero_eq_one_iff,
      eq_self_iff_true, sub_zero, fin.succ_zero_eq_one, add_left_neg, if_false, one_ne_zero] },
  fin_cases i;
  simp only [finsupp.sub_apply, len_mk, finsupp.single_apply, eq_self_iff_true, if_true, if_false,
    fin.one_eq_zero_iff, fin.zero_eq_one_iff, fin.succ_zero_eq_one, one_ne_zero,
    sub_zero, zero_sub, ← f.map_neg, exists_apply_eq_apply],
end

end PolyhedralLattice


/-
Copyright (c) 2016 Jeremy Avigad. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Jeremy Avigad, Leonardo de Moura, Mario Carneiro, Johannes Hölzl

! This file was ported from Lean 3 source module algebra.order.monoid.to_mul_bot
! leanprover-community/mathlib commit 448144f7ae193a8990cb7473c9e9a01990f64ac7
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.Algebra.Order.WithZero
import Mathbin.Algebra.Order.Monoid.WithTop
import Mathbin.Algebra.Order.Monoid.TypeTags

/-!
> THIS FILE IS SYNCHRONIZED WITH MATHLIB4.
> Any changes to this file require a corresponding PR to mathlib4.

Making an additive monoid multiplicative then adding a zero is the same as adding a bottom
element then making it multiplicative.
-/

universe u

variable {α : Type u}

namespace WithZero

attribute [local semireducible] WithZero

variable [Add α]

/- warning: with_zero.to_mul_bot -> WithZero.toMulBot is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} [_inst_1 : Add.{u1} α], MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toHasMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.hasMul.{u1} α _inst_1))) (Multiplicative.hasMul.{u1} (WithBot.{u1} α) (WithBot.hasAdd.{u1} α _inst_1))
but is expected to have type
  forall {α : Type.{u1}} [_inst_1 : Add.{u1} α], MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1))
Case conversion may be inaccurate. Consider using '#align with_zero.to_mul_bot WithZero.toMulBotₓ'. -/
/-- Making an additive monoid multiplicative then adding a zero is the same as adding a bottom
element then making it multiplicative. -/
def toMulBot : WithZero (Multiplicative α) ≃* Multiplicative (WithBot α) :=
  MulEquiv.refl _
#align with_zero.to_mul_bot WithZero.toMulBot

/- warning: with_zero.to_mul_bot_zero -> WithZero.toMulBot_zero is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} [_inst_1 : Add.{u1} α], Eq.{succ u1} (Multiplicative.{u1} (WithBot.{u1} α)) (coeFn.{succ u1, succ u1} (MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toHasMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.hasMul.{u1} α _inst_1))) (Multiplicative.hasMul.{u1} (WithBot.{u1} α) (WithBot.hasAdd.{u1} α _inst_1))) (fun (_x : MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toHasMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.hasMul.{u1} α _inst_1))) (Multiplicative.hasMul.{u1} (WithBot.{u1} α) (WithBot.hasAdd.{u1} α _inst_1))) => (WithZero.{u1} (Multiplicative.{u1} α)) -> (Multiplicative.{u1} (WithBot.{u1} α))) (MulEquiv.hasCoeToFun.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toHasMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.hasMul.{u1} α _inst_1))) (Multiplicative.hasMul.{u1} (WithBot.{u1} α) (WithBot.hasAdd.{u1} α _inst_1))) (WithZero.toMulBot.{u1} α _inst_1) (OfNat.ofNat.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) 0 (OfNat.mk.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) 0 (Zero.zero.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.zero.{u1} (Multiplicative.{u1} α)))))) (coeFn.{succ u1, succ u1} (Equiv.{succ u1, succ u1} (WithBot.{u1} α) (Multiplicative.{u1} (WithBot.{u1} α))) (fun (_x : Equiv.{succ u1, succ u1} (WithBot.{u1} α) (Multiplicative.{u1} (WithBot.{u1} α))) => (WithBot.{u1} α) -> (Multiplicative.{u1} (WithBot.{u1} α))) (Equiv.hasCoeToFun.{succ u1, succ u1} (WithBot.{u1} α) (Multiplicative.{u1} (WithBot.{u1} α))) (Multiplicative.ofAdd.{u1} (WithBot.{u1} α)) (Bot.bot.{u1} (WithBot.{u1} α) (WithBot.hasBot.{u1} α)))
but is expected to have type
  forall {α : Type.{u1}} [_inst_1 : Add.{u1} α], Eq.{succ u1} ((fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : WithZero.{u1} (Multiplicative.{u1} α)) => Multiplicative.{u1} (WithBot.{u1} α)) (OfNat.ofNat.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) 0 (Zero.toOfNat0.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.zero.{u1} (Multiplicative.{u1} α))))) (FunLike.coe.{succ u1, succ u1, succ u1} (MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1))) (WithZero.{u1} (Multiplicative.{u1} α)) (fun (_x : WithZero.{u1} (Multiplicative.{u1} α)) => (fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : WithZero.{u1} (Multiplicative.{u1} α)) => Multiplicative.{u1} (WithBot.{u1} α)) _x) (EmbeddingLike.toFunLike.{succ u1, succ u1, succ u1} (MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1))) (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (EquivLike.toEmbeddingLike.{succ u1, succ u1, succ u1} (MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1))) (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulEquivClass.toEquivLike.{u1, u1, u1} (MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1))) (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1)) (MulEquiv.instMulEquivClassMulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1)))))) (WithZero.toMulBot.{u1} α _inst_1) (OfNat.ofNat.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) 0 (Zero.toOfNat0.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.zero.{u1} (Multiplicative.{u1} α))))) (FunLike.coe.{succ u1, succ u1, succ u1} (Equiv.{succ u1, succ u1} (WithBot.{u1} α) (Multiplicative.{u1} (WithBot.{u1} α))) (WithBot.{u1} α) (fun (_x : WithBot.{u1} α) => (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : WithBot.{u1} α) => Multiplicative.{u1} (WithBot.{u1} α)) _x) (Equiv.instFunLikeEquiv.{succ u1, succ u1} (WithBot.{u1} α) (Multiplicative.{u1} (WithBot.{u1} α))) (Multiplicative.ofAdd.{u1} (WithBot.{u1} α)) (Bot.bot.{u1} (WithBot.{u1} α) (WithBot.bot.{u1} α)))
Case conversion may be inaccurate. Consider using '#align with_zero.to_mul_bot_zero WithZero.toMulBot_zeroₓ'. -/
@[simp]
theorem toMulBot_zero : toMulBot (0 : WithZero (Multiplicative α)) = Multiplicative.ofAdd ⊥ :=
  rfl
#align with_zero.to_mul_bot_zero WithZero.toMulBot_zero

/- warning: with_zero.to_mul_bot_coe -> WithZero.toMulBot_coe is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} [_inst_1 : Add.{u1} α] (x : Multiplicative.{u1} α), Eq.{succ u1} (Multiplicative.{u1} (WithBot.{u1} α)) (coeFn.{succ u1, succ u1} (MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toHasMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.hasMul.{u1} α _inst_1))) (Multiplicative.hasMul.{u1} (WithBot.{u1} α) (WithBot.hasAdd.{u1} α _inst_1))) (fun (_x : MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toHasMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.hasMul.{u1} α _inst_1))) (Multiplicative.hasMul.{u1} (WithBot.{u1} α) (WithBot.hasAdd.{u1} α _inst_1))) => (WithZero.{u1} (Multiplicative.{u1} α)) -> (Multiplicative.{u1} (WithBot.{u1} α))) (MulEquiv.hasCoeToFun.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toHasMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.hasMul.{u1} α _inst_1))) (Multiplicative.hasMul.{u1} (WithBot.{u1} α) (WithBot.hasAdd.{u1} α _inst_1))) (WithZero.toMulBot.{u1} α _inst_1) ((fun (a : Type.{u1}) (b : Type.{u1}) [self : HasLiftT.{succ u1, succ u1} a b] => self.0) (Multiplicative.{u1} α) (WithZero.{u1} (Multiplicative.{u1} α)) (HasLiftT.mk.{succ u1, succ u1} (Multiplicative.{u1} α) (WithZero.{u1} (Multiplicative.{u1} α)) (CoeTCₓ.coe.{succ u1, succ u1} (Multiplicative.{u1} α) (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.hasCoeT.{u1} (Multiplicative.{u1} α)))) x)) (coeFn.{succ u1, succ u1} (Equiv.{succ u1, succ u1} (WithBot.{u1} α) (Multiplicative.{u1} (WithBot.{u1} α))) (fun (_x : Equiv.{succ u1, succ u1} (WithBot.{u1} α) (Multiplicative.{u1} (WithBot.{u1} α))) => (WithBot.{u1} α) -> (Multiplicative.{u1} (WithBot.{u1} α))) (Equiv.hasCoeToFun.{succ u1, succ u1} (WithBot.{u1} α) (Multiplicative.{u1} (WithBot.{u1} α))) (Multiplicative.ofAdd.{u1} (WithBot.{u1} α)) ((fun (a : Type.{u1}) (b : Type.{u1}) [self : HasLiftT.{succ u1, succ u1} a b] => self.0) α (WithBot.{u1} α) (HasLiftT.mk.{succ u1, succ u1} α (WithBot.{u1} α) (CoeTCₓ.coe.{succ u1, succ u1} α (WithBot.{u1} α) (WithBot.hasCoeT.{u1} α))) (coeFn.{succ u1, succ u1} (Equiv.{succ u1, succ u1} (Multiplicative.{u1} α) α) (fun (_x : Equiv.{succ u1, succ u1} (Multiplicative.{u1} α) α) => (Multiplicative.{u1} α) -> α) (Equiv.hasCoeToFun.{succ u1, succ u1} (Multiplicative.{u1} α) α) (Multiplicative.toAdd.{u1} α) x)))
but is expected to have type
  forall {α : Type.{u1}} [_inst_1 : Add.{u1} α] (x : Multiplicative.{u1} α), Eq.{succ u1} ((fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : WithZero.{u1} (Multiplicative.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x))) => Multiplicative.{u1} (WithBot.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x))) (WithZero.coe.{u1} (Multiplicative.{u1} α) x)) (FunLike.coe.{succ u1, succ u1, succ u1} (MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x))) (Multiplicative.{u1} (WithBot.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x))) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x))) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x)) (Multiplicative.mul.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x) _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x)) (WithBot.add.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x) _inst_1))) (WithZero.{u1} (Multiplicative.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x))) (fun (_x : WithZero.{u1} (Multiplicative.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x))) => (fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : WithZero.{u1} (Multiplicative.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x))) => Multiplicative.{u1} (WithBot.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x))) _x) (EmbeddingLike.toFunLike.{succ u1, succ u1, succ u1} (MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x))) (Multiplicative.{u1} (WithBot.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x))) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x))) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x)) (Multiplicative.mul.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x) _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x)) (WithBot.add.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x) _inst_1))) (WithZero.{u1} (Multiplicative.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x))) (Multiplicative.{u1} (WithBot.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x))) (EquivLike.toEmbeddingLike.{succ u1, succ u1, succ u1} (MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x))) (Multiplicative.{u1} (WithBot.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x))) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x))) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x)) (Multiplicative.mul.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x) _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x)) (WithBot.add.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x) _inst_1))) (WithZero.{u1} (Multiplicative.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x))) (Multiplicative.{u1} (WithBot.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x))) (MulEquivClass.toEquivLike.{u1, u1, u1} (MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x))) (Multiplicative.{u1} (WithBot.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x))) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x))) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x)) (Multiplicative.mul.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x) _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x)) (WithBot.add.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x) _inst_1))) (WithZero.{u1} (Multiplicative.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x))) (Multiplicative.{u1} (WithBot.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x))) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x))) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x)) (Multiplicative.mul.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x) _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x)) (WithBot.add.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x) _inst_1)) (MulEquiv.instMulEquivClassMulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x))) (Multiplicative.{u1} (WithBot.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x))) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x))) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x)) (Multiplicative.mul.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x) _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x)) (WithBot.add.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x) _inst_1)))))) (WithZero.toMulBot.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x) _inst_1) (WithZero.coe.{u1} (Multiplicative.{u1} α) x)) (FunLike.coe.{succ u1, succ u1, succ u1} (Equiv.{succ u1, succ u1} (WithBot.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x)) (Multiplicative.{u1} (WithBot.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x)))) (WithBot.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x)) (fun (_x : WithBot.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x)) => (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : WithBot.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x)) => Multiplicative.{u1} (WithBot.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x))) _x) (Equiv.instFunLikeEquiv.{succ u1, succ u1} (WithBot.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x)) (Multiplicative.{u1} (WithBot.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x)))) (Multiplicative.ofAdd.{u1} (WithBot.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x))) (WithBot.some.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) x) (FunLike.coe.{succ u1, succ u1, succ u1} (Equiv.{succ u1, succ u1} (Multiplicative.{u1} α) α) (Multiplicative.{u1} α) (fun (_x : Multiplicative.{u1} α) => (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Multiplicative.{u1} α) => α) _x) (Equiv.instFunLikeEquiv.{succ u1, succ u1} (Multiplicative.{u1} α) α) (Multiplicative.toAdd.{u1} α) x)))
Case conversion may be inaccurate. Consider using '#align with_zero.to_mul_bot_coe WithZero.toMulBot_coeₓ'. -/
@[simp]
theorem toMulBot_coe (x : Multiplicative α) :
    toMulBot ↑x = Multiplicative.ofAdd (x.toAdd : WithBot α) :=
  rfl
#align with_zero.to_mul_bot_coe WithZero.toMulBot_coe

/- warning: with_zero.to_mul_bot_symm_bot -> WithZero.toMulBot_symm_bot is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} [_inst_1 : Add.{u1} α], Eq.{succ u1} (WithZero.{u1} (Multiplicative.{u1} α)) (coeFn.{succ u1, succ u1} (MulEquiv.{u1, u1} (Multiplicative.{u1} (WithBot.{u1} α)) (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.hasMul.{u1} (WithBot.{u1} α) (WithBot.hasAdd.{u1} α _inst_1)) (MulZeroClass.toHasMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.hasMul.{u1} α _inst_1)))) (fun (_x : MulEquiv.{u1, u1} (Multiplicative.{u1} (WithBot.{u1} α)) (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.hasMul.{u1} (WithBot.{u1} α) (WithBot.hasAdd.{u1} α _inst_1)) (MulZeroClass.toHasMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.hasMul.{u1} α _inst_1)))) => (Multiplicative.{u1} (WithBot.{u1} α)) -> (WithZero.{u1} (Multiplicative.{u1} α))) (MulEquiv.hasCoeToFun.{u1, u1} (Multiplicative.{u1} (WithBot.{u1} α)) (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.hasMul.{u1} (WithBot.{u1} α) (WithBot.hasAdd.{u1} α _inst_1)) (MulZeroClass.toHasMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.hasMul.{u1} α _inst_1)))) (MulEquiv.symm.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toHasMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.hasMul.{u1} α _inst_1))) (Multiplicative.hasMul.{u1} (WithBot.{u1} α) (WithBot.hasAdd.{u1} α _inst_1)) (WithZero.toMulBot.{u1} α _inst_1)) (coeFn.{succ u1, succ u1} (Equiv.{succ u1, succ u1} (WithBot.{u1} α) (Multiplicative.{u1} (WithBot.{u1} α))) (fun (_x : Equiv.{succ u1, succ u1} (WithBot.{u1} α) (Multiplicative.{u1} (WithBot.{u1} α))) => (WithBot.{u1} α) -> (Multiplicative.{u1} (WithBot.{u1} α))) (Equiv.hasCoeToFun.{succ u1, succ u1} (WithBot.{u1} α) (Multiplicative.{u1} (WithBot.{u1} α))) (Multiplicative.ofAdd.{u1} (WithBot.{u1} α)) (Bot.bot.{u1} (WithBot.{u1} α) (WithBot.hasBot.{u1} α)))) (OfNat.ofNat.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) 0 (OfNat.mk.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) 0 (Zero.zero.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.zero.{u1} (Multiplicative.{u1} α)))))
but is expected to have type
  forall {α : Type.{u1}} [_inst_1 : Add.{u1} α], Eq.{succ u1} ((fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : Multiplicative.{u1} (WithBot.{u1} α)) => WithZero.{u1} (Multiplicative.{u1} α)) (FunLike.coe.{succ u1, succ u1, succ u1} (Equiv.{succ u1, succ u1} (WithBot.{u1} α) (Multiplicative.{u1} (WithBot.{u1} α))) (WithBot.{u1} α) (fun (a : WithBot.{u1} α) => (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : WithBot.{u1} α) => Multiplicative.{u1} (WithBot.{u1} α)) a) (Equiv.instFunLikeEquiv.{succ u1, succ u1} (WithBot.{u1} α) (Multiplicative.{u1} (WithBot.{u1} α))) (Multiplicative.ofAdd.{u1} (WithBot.{u1} α)) (Bot.bot.{u1} (WithBot.{u1} α) (WithBot.bot.{u1} α)))) (FunLike.coe.{succ u1, succ u1, succ u1} (MulEquiv.{u1, u1} (Multiplicative.{u1} (WithBot.{u1} α)) (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1)))) (Multiplicative.{u1} (WithBot.{u1} α)) (fun (_x : Multiplicative.{u1} (WithBot.{u1} α)) => (fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : Multiplicative.{u1} (WithBot.{u1} α)) => WithZero.{u1} (Multiplicative.{u1} α)) _x) (EmbeddingLike.toFunLike.{succ u1, succ u1, succ u1} (MulEquiv.{u1, u1} (Multiplicative.{u1} (WithBot.{u1} α)) (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1)))) (Multiplicative.{u1} (WithBot.{u1} α)) (WithZero.{u1} (Multiplicative.{u1} α)) (EquivLike.toEmbeddingLike.{succ u1, succ u1, succ u1} (MulEquiv.{u1, u1} (Multiplicative.{u1} (WithBot.{u1} α)) (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1)))) (Multiplicative.{u1} (WithBot.{u1} α)) (WithZero.{u1} (Multiplicative.{u1} α)) (MulEquivClass.toEquivLike.{u1, u1, u1} (MulEquiv.{u1, u1} (Multiplicative.{u1} (WithBot.{u1} α)) (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1)))) (Multiplicative.{u1} (WithBot.{u1} α)) (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (MulEquiv.instMulEquivClassMulEquiv.{u1, u1} (Multiplicative.{u1} (WithBot.{u1} α)) (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))))))) (MulEquiv.symm.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1)) (WithZero.toMulBot.{u1} α _inst_1)) (FunLike.coe.{succ u1, succ u1, succ u1} (Equiv.{succ u1, succ u1} (WithBot.{u1} α) (Multiplicative.{u1} (WithBot.{u1} α))) (WithBot.{u1} α) (fun (_x : WithBot.{u1} α) => (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : WithBot.{u1} α) => Multiplicative.{u1} (WithBot.{u1} α)) _x) (Equiv.instFunLikeEquiv.{succ u1, succ u1} (WithBot.{u1} α) (Multiplicative.{u1} (WithBot.{u1} α))) (Multiplicative.ofAdd.{u1} (WithBot.{u1} α)) (Bot.bot.{u1} (WithBot.{u1} α) (WithBot.bot.{u1} α)))) (OfNat.ofNat.{u1} ((fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : Multiplicative.{u1} (WithBot.{u1} α)) => WithZero.{u1} (Multiplicative.{u1} α)) (FunLike.coe.{succ u1, succ u1, succ u1} (Equiv.{succ u1, succ u1} (WithBot.{u1} α) (Multiplicative.{u1} (WithBot.{u1} α))) (WithBot.{u1} α) (fun (a : WithBot.{u1} α) => (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : WithBot.{u1} α) => Multiplicative.{u1} (WithBot.{u1} α)) a) (Equiv.instFunLikeEquiv.{succ u1, succ u1} (WithBot.{u1} α) (Multiplicative.{u1} (WithBot.{u1} α))) (Multiplicative.ofAdd.{u1} (WithBot.{u1} α)) (Bot.bot.{u1} (WithBot.{u1} α) (WithBot.bot.{u1} α)))) 0 (Zero.toOfNat0.{u1} ((fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : Multiplicative.{u1} (WithBot.{u1} α)) => WithZero.{u1} (Multiplicative.{u1} α)) (FunLike.coe.{succ u1, succ u1, succ u1} (Equiv.{succ u1, succ u1} (WithBot.{u1} α) (Multiplicative.{u1} (WithBot.{u1} α))) (WithBot.{u1} α) (fun (a : WithBot.{u1} α) => (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : WithBot.{u1} α) => Multiplicative.{u1} (WithBot.{u1} α)) a) (Equiv.instFunLikeEquiv.{succ u1, succ u1} (WithBot.{u1} α) (Multiplicative.{u1} (WithBot.{u1} α))) (Multiplicative.ofAdd.{u1} (WithBot.{u1} α)) (Bot.bot.{u1} (WithBot.{u1} α) (WithBot.bot.{u1} α)))) (WithZero.zero.{u1} (Multiplicative.{u1} α))))
Case conversion may be inaccurate. Consider using '#align with_zero.to_mul_bot_symm_bot WithZero.toMulBot_symm_botₓ'. -/
@[simp]
theorem toMulBot_symm_bot : toMulBot.symm (Multiplicative.ofAdd (⊥ : WithBot α)) = 0 :=
  rfl
#align with_zero.to_mul_bot_symm_bot WithZero.toMulBot_symm_bot

/- warning: with_zero.to_mul_bot_coe_of_add -> WithZero.toMulBot_coe_ofAdd is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} [_inst_1 : Add.{u1} α] (x : α), Eq.{succ u1} (WithZero.{u1} (Multiplicative.{u1} α)) (coeFn.{succ u1, succ u1} (MulEquiv.{u1, u1} (Multiplicative.{u1} (WithBot.{u1} α)) (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.hasMul.{u1} (WithBot.{u1} α) (WithBot.hasAdd.{u1} α _inst_1)) (MulZeroClass.toHasMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.hasMul.{u1} α _inst_1)))) (fun (_x : MulEquiv.{u1, u1} (Multiplicative.{u1} (WithBot.{u1} α)) (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.hasMul.{u1} (WithBot.{u1} α) (WithBot.hasAdd.{u1} α _inst_1)) (MulZeroClass.toHasMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.hasMul.{u1} α _inst_1)))) => (Multiplicative.{u1} (WithBot.{u1} α)) -> (WithZero.{u1} (Multiplicative.{u1} α))) (MulEquiv.hasCoeToFun.{u1, u1} (Multiplicative.{u1} (WithBot.{u1} α)) (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.hasMul.{u1} (WithBot.{u1} α) (WithBot.hasAdd.{u1} α _inst_1)) (MulZeroClass.toHasMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.hasMul.{u1} α _inst_1)))) (MulEquiv.symm.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toHasMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.hasMul.{u1} α _inst_1))) (Multiplicative.hasMul.{u1} (WithBot.{u1} α) (WithBot.hasAdd.{u1} α _inst_1)) (WithZero.toMulBot.{u1} α _inst_1)) (coeFn.{succ u1, succ u1} (Equiv.{succ u1, succ u1} (WithBot.{u1} α) (Multiplicative.{u1} (WithBot.{u1} α))) (fun (_x : Equiv.{succ u1, succ u1} (WithBot.{u1} α) (Multiplicative.{u1} (WithBot.{u1} α))) => (WithBot.{u1} α) -> (Multiplicative.{u1} (WithBot.{u1} α))) (Equiv.hasCoeToFun.{succ u1, succ u1} (WithBot.{u1} α) (Multiplicative.{u1} (WithBot.{u1} α))) (Multiplicative.ofAdd.{u1} (WithBot.{u1} α)) ((fun (a : Type.{u1}) (b : Type.{u1}) [self : HasLiftT.{succ u1, succ u1} a b] => self.0) α (WithBot.{u1} α) (HasLiftT.mk.{succ u1, succ u1} α (WithBot.{u1} α) (CoeTCₓ.coe.{succ u1, succ u1} α (WithBot.{u1} α) (WithBot.hasCoeT.{u1} α))) x))) ((fun (a : Type.{u1}) (b : Type.{u1}) [self : HasLiftT.{succ u1, succ u1} a b] => self.0) (Multiplicative.{u1} α) (WithZero.{u1} (Multiplicative.{u1} α)) (HasLiftT.mk.{succ u1, succ u1} (Multiplicative.{u1} α) (WithZero.{u1} (Multiplicative.{u1} α)) (CoeTCₓ.coe.{succ u1, succ u1} (Multiplicative.{u1} α) (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.hasCoeT.{u1} (Multiplicative.{u1} α)))) (coeFn.{succ u1, succ u1} (Equiv.{succ u1, succ u1} α (Multiplicative.{u1} α)) (fun (_x : Equiv.{succ u1, succ u1} α (Multiplicative.{u1} α)) => α -> (Multiplicative.{u1} α)) (Equiv.hasCoeToFun.{succ u1, succ u1} α (Multiplicative.{u1} α)) (Multiplicative.ofAdd.{u1} α) x))
but is expected to have type
  forall {α : Type.{u1}} [_inst_1 : Add.{u1} α] (x : α), Eq.{succ u1} ((fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : Multiplicative.{u1} (WithBot.{u1} α)) => WithZero.{u1} (Multiplicative.{u1} α)) (FunLike.coe.{succ u1, succ u1, succ u1} (Equiv.{succ u1, succ u1} (WithBot.{u1} α) (Multiplicative.{u1} (WithBot.{u1} α))) (WithBot.{u1} α) (fun (a : WithBot.{u1} α) => (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : WithBot.{u1} α) => Multiplicative.{u1} (WithBot.{u1} α)) a) (Equiv.instFunLikeEquiv.{succ u1, succ u1} (WithBot.{u1} α) (Multiplicative.{u1} (WithBot.{u1} α))) (Multiplicative.ofAdd.{u1} (WithBot.{u1} α)) (WithBot.some.{u1} α x))) (FunLike.coe.{succ u1, succ u1, succ u1} (MulEquiv.{u1, u1} (Multiplicative.{u1} (WithBot.{u1} α)) (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1)))) (Multiplicative.{u1} (WithBot.{u1} α)) (fun (_x : Multiplicative.{u1} (WithBot.{u1} α)) => (fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : Multiplicative.{u1} (WithBot.{u1} α)) => WithZero.{u1} (Multiplicative.{u1} α)) _x) (EmbeddingLike.toFunLike.{succ u1, succ u1, succ u1} (MulEquiv.{u1, u1} (Multiplicative.{u1} (WithBot.{u1} α)) (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1)))) (Multiplicative.{u1} (WithBot.{u1} α)) (WithZero.{u1} (Multiplicative.{u1} α)) (EquivLike.toEmbeddingLike.{succ u1, succ u1, succ u1} (MulEquiv.{u1, u1} (Multiplicative.{u1} (WithBot.{u1} α)) (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1)))) (Multiplicative.{u1} (WithBot.{u1} α)) (WithZero.{u1} (Multiplicative.{u1} α)) (MulEquivClass.toEquivLike.{u1, u1, u1} (MulEquiv.{u1, u1} (Multiplicative.{u1} (WithBot.{u1} α)) (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1)))) (Multiplicative.{u1} (WithBot.{u1} α)) (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (MulEquiv.instMulEquivClassMulEquiv.{u1, u1} (Multiplicative.{u1} (WithBot.{u1} α)) (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))))))) (MulEquiv.symm.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1)) (WithZero.toMulBot.{u1} α _inst_1)) (FunLike.coe.{succ u1, succ u1, succ u1} (Equiv.{succ u1, succ u1} (WithBot.{u1} α) (Multiplicative.{u1} (WithBot.{u1} α))) (WithBot.{u1} α) (fun (_x : WithBot.{u1} α) => (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : WithBot.{u1} α) => Multiplicative.{u1} (WithBot.{u1} α)) _x) (Equiv.instFunLikeEquiv.{succ u1, succ u1} (WithBot.{u1} α) (Multiplicative.{u1} (WithBot.{u1} α))) (Multiplicative.ofAdd.{u1} (WithBot.{u1} α)) (WithBot.some.{u1} α x))) (WithZero.coe.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : α) => Multiplicative.{u1} α) x) (FunLike.coe.{succ u1, succ u1, succ u1} (Equiv.{succ u1, succ u1} α (Multiplicative.{u1} α)) α (fun (_x : α) => (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : α) => Multiplicative.{u1} α) _x) (Equiv.instFunLikeEquiv.{succ u1, succ u1} α (Multiplicative.{u1} α)) (Multiplicative.ofAdd.{u1} α) x))
Case conversion may be inaccurate. Consider using '#align with_zero.to_mul_bot_coe_of_add WithZero.toMulBot_coe_ofAddₓ'. -/
@[simp]
theorem toMulBot_coe_ofAdd (x : α) :
    toMulBot.symm (Multiplicative.ofAdd (x : WithBot α)) = Multiplicative.ofAdd x :=
  rfl
#align with_zero.to_mul_bot_coe_of_add WithZero.toMulBot_coe_ofAdd

variable [Preorder α] (a b : WithZero (Multiplicative α))

/- warning: with_zero.to_mul_bot_strict_mono -> WithZero.toMulBot_strictMono is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} [_inst_1 : Add.{u1} α] [_inst_2 : Preorder.{u1} α], StrictMono.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (WithZero.preorder.{u1} (Multiplicative.{u1} α) (Multiplicative.preorder.{u1} α _inst_2)) (Multiplicative.preorder.{u1} (WithBot.{u1} α) (WithBot.preorder.{u1} α _inst_2)) (coeFn.{succ u1, succ u1} (MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toHasMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.hasMul.{u1} α _inst_1))) (Multiplicative.hasMul.{u1} (WithBot.{u1} α) (WithBot.hasAdd.{u1} α _inst_1))) (fun (_x : MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toHasMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.hasMul.{u1} α _inst_1))) (Multiplicative.hasMul.{u1} (WithBot.{u1} α) (WithBot.hasAdd.{u1} α _inst_1))) => (WithZero.{u1} (Multiplicative.{u1} α)) -> (Multiplicative.{u1} (WithBot.{u1} α))) (MulEquiv.hasCoeToFun.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toHasMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.hasMul.{u1} α _inst_1))) (Multiplicative.hasMul.{u1} (WithBot.{u1} α) (WithBot.hasAdd.{u1} α _inst_1))) (WithZero.toMulBot.{u1} α _inst_1))
but is expected to have type
  forall {α : Type.{u1}} [_inst_1 : Add.{u1} α] [_inst_2 : Preorder.{u1} α], StrictMono.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (WithZero.preorder.{u1} (Multiplicative.{u1} α) (Multiplicative.preorder.{u1} α _inst_2)) (Multiplicative.preorder.{u1} (WithBot.{u1} α) (WithBot.preorder.{u1} α _inst_2)) (FunLike.coe.{succ u1, succ u1, succ u1} (MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1))) (WithZero.{u1} (Multiplicative.{u1} α)) (fun (_x : WithZero.{u1} (Multiplicative.{u1} α)) => (fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : WithZero.{u1} (Multiplicative.{u1} α)) => Multiplicative.{u1} (WithBot.{u1} α)) _x) (EmbeddingLike.toFunLike.{succ u1, succ u1, succ u1} (MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1))) (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (EquivLike.toEmbeddingLike.{succ u1, succ u1, succ u1} (MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1))) (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulEquivClass.toEquivLike.{u1, u1, u1} (MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1))) (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1)) (MulEquiv.instMulEquivClassMulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1)))))) (WithZero.toMulBot.{u1} α _inst_1))
Case conversion may be inaccurate. Consider using '#align with_zero.to_mul_bot_strict_mono WithZero.toMulBot_strictMonoₓ'. -/
theorem toMulBot_strictMono : StrictMono (@toMulBot α _) := fun x y => id
#align with_zero.to_mul_bot_strict_mono WithZero.toMulBot_strictMono

/- warning: with_zero.to_mul_bot_le -> WithZero.toMulBot_le is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} [_inst_1 : Add.{u1} α] [_inst_2 : Preorder.{u1} α] (a : WithZero.{u1} (Multiplicative.{u1} α)) (b : WithZero.{u1} (Multiplicative.{u1} α)), Iff (LE.le.{u1} (Multiplicative.{u1} (WithBot.{u1} α)) (Multiplicative.hasLe.{u1} (WithBot.{u1} α) (Preorder.toLE.{u1} (WithBot.{u1} α) (WithBot.preorder.{u1} α _inst_2))) (coeFn.{succ u1, succ u1} (MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toHasMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.hasMul.{u1} α _inst_1))) (Multiplicative.hasMul.{u1} (WithBot.{u1} α) (WithBot.hasAdd.{u1} α _inst_1))) (fun (_x : MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toHasMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.hasMul.{u1} α _inst_1))) (Multiplicative.hasMul.{u1} (WithBot.{u1} α) (WithBot.hasAdd.{u1} α _inst_1))) => (WithZero.{u1} (Multiplicative.{u1} α)) -> (Multiplicative.{u1} (WithBot.{u1} α))) (MulEquiv.hasCoeToFun.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toHasMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.hasMul.{u1} α _inst_1))) (Multiplicative.hasMul.{u1} (WithBot.{u1} α) (WithBot.hasAdd.{u1} α _inst_1))) (WithZero.toMulBot.{u1} α _inst_1) a) (coeFn.{succ u1, succ u1} (MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toHasMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.hasMul.{u1} α _inst_1))) (Multiplicative.hasMul.{u1} (WithBot.{u1} α) (WithBot.hasAdd.{u1} α _inst_1))) (fun (_x : MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toHasMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.hasMul.{u1} α _inst_1))) (Multiplicative.hasMul.{u1} (WithBot.{u1} α) (WithBot.hasAdd.{u1} α _inst_1))) => (WithZero.{u1} (Multiplicative.{u1} α)) -> (Multiplicative.{u1} (WithBot.{u1} α))) (MulEquiv.hasCoeToFun.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toHasMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.hasMul.{u1} α _inst_1))) (Multiplicative.hasMul.{u1} (WithBot.{u1} α) (WithBot.hasAdd.{u1} α _inst_1))) (WithZero.toMulBot.{u1} α _inst_1) b)) (LE.le.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Preorder.toLE.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.preorder.{u1} (Multiplicative.{u1} α) (Multiplicative.preorder.{u1} α _inst_2))) a b)
but is expected to have type
  forall {α : Type.{u1}} [_inst_1 : Add.{u1} α] [_inst_2 : Preorder.{u1} α] (a : WithZero.{u1} (Multiplicative.{u1} α)) (b : WithZero.{u1} (Multiplicative.{u1} α)), Iff (LE.le.{u1} ((fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : WithZero.{u1} (Multiplicative.{u1} α)) => Multiplicative.{u1} (WithBot.{u1} α)) a) (instForAllLEMultiplicative.{u1} (WithBot.{u1} α) (Preorder.toLE.{u1} (WithBot.{u1} α) (WithBot.preorder.{u1} α _inst_2))) (FunLike.coe.{succ u1, succ u1, succ u1} (MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1))) (WithZero.{u1} (Multiplicative.{u1} α)) (fun (_x : WithZero.{u1} (Multiplicative.{u1} α)) => (fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : WithZero.{u1} (Multiplicative.{u1} α)) => Multiplicative.{u1} (WithBot.{u1} α)) _x) (EmbeddingLike.toFunLike.{succ u1, succ u1, succ u1} (MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1))) (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (EquivLike.toEmbeddingLike.{succ u1, succ u1, succ u1} (MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1))) (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulEquivClass.toEquivLike.{u1, u1, u1} (MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1))) (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1)) (MulEquiv.instMulEquivClassMulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1)))))) (WithZero.toMulBot.{u1} α _inst_1) a) (FunLike.coe.{succ u1, succ u1, succ u1} (MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1))) (WithZero.{u1} (Multiplicative.{u1} α)) (fun (_x : WithZero.{u1} (Multiplicative.{u1} α)) => (fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : WithZero.{u1} (Multiplicative.{u1} α)) => Multiplicative.{u1} (WithBot.{u1} α)) _x) (EmbeddingLike.toFunLike.{succ u1, succ u1, succ u1} (MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1))) (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (EquivLike.toEmbeddingLike.{succ u1, succ u1, succ u1} (MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1))) (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulEquivClass.toEquivLike.{u1, u1, u1} (MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1))) (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1)) (MulEquiv.instMulEquivClassMulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1)))))) (WithZero.toMulBot.{u1} α _inst_1) b)) (LE.le.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Preorder.toLE.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.preorder.{u1} (Multiplicative.{u1} α) (Multiplicative.preorder.{u1} α _inst_2))) a b)
Case conversion may be inaccurate. Consider using '#align with_zero.to_mul_bot_le WithZero.toMulBot_leₓ'. -/
@[simp]
theorem toMulBot_le : toMulBot a ≤ toMulBot b ↔ a ≤ b :=
  Iff.rfl
#align with_zero.to_mul_bot_le WithZero.toMulBot_le

/- warning: with_zero.to_mul_bot_lt -> WithZero.toMulBot_lt is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} [_inst_1 : Add.{u1} α] [_inst_2 : Preorder.{u1} α] (a : WithZero.{u1} (Multiplicative.{u1} α)) (b : WithZero.{u1} (Multiplicative.{u1} α)), Iff (LT.lt.{u1} (Multiplicative.{u1} (WithBot.{u1} α)) (Multiplicative.hasLt.{u1} (WithBot.{u1} α) (Preorder.toLT.{u1} (WithBot.{u1} α) (WithBot.preorder.{u1} α _inst_2))) (coeFn.{succ u1, succ u1} (MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toHasMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.hasMul.{u1} α _inst_1))) (Multiplicative.hasMul.{u1} (WithBot.{u1} α) (WithBot.hasAdd.{u1} α _inst_1))) (fun (_x : MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toHasMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.hasMul.{u1} α _inst_1))) (Multiplicative.hasMul.{u1} (WithBot.{u1} α) (WithBot.hasAdd.{u1} α _inst_1))) => (WithZero.{u1} (Multiplicative.{u1} α)) -> (Multiplicative.{u1} (WithBot.{u1} α))) (MulEquiv.hasCoeToFun.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toHasMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.hasMul.{u1} α _inst_1))) (Multiplicative.hasMul.{u1} (WithBot.{u1} α) (WithBot.hasAdd.{u1} α _inst_1))) (WithZero.toMulBot.{u1} α _inst_1) a) (coeFn.{succ u1, succ u1} (MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toHasMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.hasMul.{u1} α _inst_1))) (Multiplicative.hasMul.{u1} (WithBot.{u1} α) (WithBot.hasAdd.{u1} α _inst_1))) (fun (_x : MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toHasMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.hasMul.{u1} α _inst_1))) (Multiplicative.hasMul.{u1} (WithBot.{u1} α) (WithBot.hasAdd.{u1} α _inst_1))) => (WithZero.{u1} (Multiplicative.{u1} α)) -> (Multiplicative.{u1} (WithBot.{u1} α))) (MulEquiv.hasCoeToFun.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toHasMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.hasMul.{u1} α _inst_1))) (Multiplicative.hasMul.{u1} (WithBot.{u1} α) (WithBot.hasAdd.{u1} α _inst_1))) (WithZero.toMulBot.{u1} α _inst_1) b)) (LT.lt.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Preorder.toLT.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.preorder.{u1} (Multiplicative.{u1} α) (Multiplicative.preorder.{u1} α _inst_2))) a b)
but is expected to have type
  forall {α : Type.{u1}} [_inst_1 : Add.{u1} α] [_inst_2 : Preorder.{u1} α] (a : WithZero.{u1} (Multiplicative.{u1} α)) (b : WithZero.{u1} (Multiplicative.{u1} α)), Iff (LT.lt.{u1} ((fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : WithZero.{u1} (Multiplicative.{u1} α)) => Multiplicative.{u1} (WithBot.{u1} α)) a) (instForAllLTMultiplicative.{u1} (WithBot.{u1} α) (Preorder.toLT.{u1} (WithBot.{u1} α) (WithBot.preorder.{u1} α _inst_2))) (FunLike.coe.{succ u1, succ u1, succ u1} (MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1))) (WithZero.{u1} (Multiplicative.{u1} α)) (fun (_x : WithZero.{u1} (Multiplicative.{u1} α)) => (fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : WithZero.{u1} (Multiplicative.{u1} α)) => Multiplicative.{u1} (WithBot.{u1} α)) _x) (EmbeddingLike.toFunLike.{succ u1, succ u1, succ u1} (MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1))) (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (EquivLike.toEmbeddingLike.{succ u1, succ u1, succ u1} (MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1))) (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulEquivClass.toEquivLike.{u1, u1, u1} (MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1))) (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1)) (MulEquiv.instMulEquivClassMulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1)))))) (WithZero.toMulBot.{u1} α _inst_1) a) (FunLike.coe.{succ u1, succ u1, succ u1} (MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1))) (WithZero.{u1} (Multiplicative.{u1} α)) (fun (_x : WithZero.{u1} (Multiplicative.{u1} α)) => (fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : WithZero.{u1} (Multiplicative.{u1} α)) => Multiplicative.{u1} (WithBot.{u1} α)) _x) (EmbeddingLike.toFunLike.{succ u1, succ u1, succ u1} (MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1))) (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (EquivLike.toEmbeddingLike.{succ u1, succ u1, succ u1} (MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1))) (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulEquivClass.toEquivLike.{u1, u1, u1} (MulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1))) (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1)) (MulEquiv.instMulEquivClassMulEquiv.{u1, u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Multiplicative.{u1} (WithBot.{u1} α)) (MulZeroClass.toMul.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.mulZeroClass.{u1} (Multiplicative.{u1} α) (Multiplicative.mul.{u1} α _inst_1))) (Multiplicative.mul.{u1} (WithBot.{u1} α) (WithBot.add.{u1} α _inst_1)))))) (WithZero.toMulBot.{u1} α _inst_1) b)) (LT.lt.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (Preorder.toLT.{u1} (WithZero.{u1} (Multiplicative.{u1} α)) (WithZero.preorder.{u1} (Multiplicative.{u1} α) (Multiplicative.preorder.{u1} α _inst_2))) a b)
Case conversion may be inaccurate. Consider using '#align with_zero.to_mul_bot_lt WithZero.toMulBot_ltₓ'. -/
@[simp]
theorem toMulBot_lt : toMulBot a < toMulBot b ↔ a < b :=
  Iff.rfl
#align with_zero.to_mul_bot_lt WithZero.toMulBot_lt

end WithZero


import data.multiset
import data.list
import data.nat.prime
import ent.order

open order
open list
open nat

local notation `prod` := list.prod

/-
set_option pp.all true

variables {x : ℕ} {lx : list ℕ}
set_option pp.all true
#check prod (map succ (x :: lx))
-/

-- def prime_factorization := multiset PP

section

-- factors facts

lemma factors_lemma_nil : ∀ (n : ℕ), factors n = [] → n = 0 ∨ n = 1
| 0 h := or.inl rfl
| 1 h := or.inr rfl
| n@(k+2) h := absurd h dec_trivial

lemma factors_lemma_cons : ∀ (n : ℕ) (m : ℕ) (fs' : list ℕ),
  factors n = m :: fs' → n ≠ 1 ∧ min_fac n = m ∧ factors (n / min_fac n) = fs'
| 0 _ _ h := absurd h dec_trivial
| 1 _ _ h := absurd h dec_trivial
| n@(k+2) m fs' hn := ⟨dec_trivial, cons.inj hn⟩

-- wouldn't it be easier to just start from scratch
-- almost certainly
def factors_as_primes :
  Π (fs : list ℕ) (n : ℕ) (h : factors n = fs),
    {l : list PP // l.map subtype.val = fs}
| [] _ _ := ⟨[], rfl⟩
| (m :: fs') n h :=
begin
  rcases factors_lemma_cons n m fs' h with ⟨n_ne_1, hm, hfs'⟩,
  let r := factors_as_primes fs' (n / min_fac n) hfs',
  have prime_m := min_fac_prime n_ne_1, rw hm at prime_m,
  existsi subtype.mk m prime_m :: r.val,
  transitivity list.cons m (map subtype.val (r.val)),
  apply map_cons subtype.val,
  rw r.property
end

lemma factors_as_factorization :
  ∀ (fs : list ℕ) (n : ℕ) (h : factors n = fs), n > 0 → prod fs = n
| [] n h n_pos := eq.symm $
  (factors_lemma_nil n h).resolve_left
  (λ e, absurd (calc 0 = n : e.symm ... > 0 : n_pos) dec_trivial)
| (m :: fs') n h n_pos :=
begin
  rcases factors_lemma_cons n m fs' h with ⟨_, hm, hfs'⟩,
  have : min_fac n ∣ n := min_fac_dvd n,
  rw hm at this hfs',
  let n' := n / m,
  have p : m * n' = n := nat.mul_div_cancel' this,
  have : n' > 0 := pos_of_mul_pos_left (p.symm ▸ n_pos : 0 < m * n') dec_trivial,
  have r' := factors_as_factorization fs' n' hfs' this,
  rw ←r' at p, rwa prod_cons
end

def factors_prime_factorization (n : ℕ) (n_pos : n > 0) :
  {l : list PP // (l.map subtype.val).prod = n} :=
let ⟨l, h⟩ := factors_as_primes (factors n) n rfl in
⟨l, h.symm ▸ factors_as_factorization (factors n) n rfl n_pos⟩

-- or just
lemma factors_is_factorization (n : ℕ) (n_pos : n > 0) :
  (factors n).prod = n :=
factors_as_factorization (factors n) n rfl n_pos

-- ∀ m ∈ factors n, prime m

/-
instance {α β : Sort*} [has_coe α β] : has_coe (list α) (list β) := ⟨map coe⟩

lemma coe_cons {α β : Sort*} [has_coe α β] (hd : α) (tl : list α) :
  (↑(@list.cons α hd tl)) = (@list.cons β hd tl) := sorry
@[reducible] def prodN := @list.prod ℕ
-/

def p_to_pnat (p : PP) : ℕ+ := ↑p

lemma ord_of_prod (l : list PP) (p : PP) :
  ord p (prod (l.map p_to_pnat)) = count p l :=
begin
  induction l with l_hd l_tl ih,
  { exact ord_one },
  { by_cases h : p = l_hd,

    exact calc
      ord p (prod (map p_to_pnat (l_hd :: l_tl)))
          = ord p (prod (p_to_pnat l_hd :: (l_tl.map p_to_pnat)))  : rfl
      ... = ord p (p_to_pnat l_hd * prod (l_tl.map p_to_pnat))     : by rw prod_cons
      ... = ord p (p_to_pnat p * prod (l_tl.map p_to_pnat))  : by rw ←h
      ... = ord p (p * prod (l_tl.map p_to_pnat))  : rfl
      ... = succ (ord p (prod (l_tl.map p_to_pnat)))  : by rw ord_div
      ... = succ (count p l_tl)                    : by rw ih
      ... = count p (p :: l_tl)                    : by simp [count_cons]
      ... = count p (l_hd :: l_tl)                 : by rw h,

    let q := l_hd,
    have : ord p q = 0 :=
      ord_not_div.mp
        ((prime.coprime_iff_not_dvd p.property).mp
         ((coprime_primes p.property q.property).mpr (mt subtype.eq h))),
    exact calc
      ord p (prod (map p_to_pnat (l_hd :: l_tl)))
          = ord p (prod (p_to_pnat l_hd :: (l_tl.map p_to_pnat)))  : rfl
      ... = ord p (p_to_pnat l_hd * prod (l_tl.map p_to_pnat))     : by rw prod_cons
      ... = ord p (p_to_pnat q * prod (l_tl.map p_to_pnat))  : rfl
      ... = ord p (q * prod (l_tl.map p_to_pnat))  : rfl
      ... = ord p q + ord p (prod (l_tl.map p_to_pnat))  : by rw ord_mul
      ... = ord p (prod (l_tl.map p_to_pnat))      : by simp [this]
      ... = count p l_tl                           : by rw ih
      ... = count p (l_hd :: l_tl)                 : by simp [count_cons, h]
  }
end

lemma ord_of_prod_multi (l : multiset PP) (p : PP) :
  ord p ((l.map p_to_pnat).prod) = l.count p :=
begin
  revert l, apply quot.ind, intro l,
  exact calc
    ord p ((multiset.map p_to_pnat ↑l).prod)
        = ord p (prod (l.map p_to_pnat))  : by simp
    ... = count p l                       : by rw ord_of_prod
    ... = multiset.count p ↑l  : by simp
end

lemma uniq (l1 l2 : multiset PP) :
  (l1.map p_to_pnat).prod = (l2.map p_to_pnat).prod → l1 = l2 :=
begin
  intro h,
  rw multiset.ext, intro p,
  rw [←ord_of_prod_multi, ←ord_of_prod_multi, h]
end

-- old weird stuff below

/-

def orders := PP →₀ ℕ

-- Yuck
lemma big_prime (p : PP) (n : ℕ+) : (p : ℕ) > n → ord p n = 0 :=
λ p_big, ord_not_div.mp (λ d, not_le_of_gt p_big (nat.le_of_dvd n.pos d))

lemma big_prime_2 (p : PP) (n : ℕ+) : ord p n ≠ 0 → (p : ℕ) ≤ n :=
le_of_not_gt ∘ mt (big_prime p n)

lemma val_is_injective {α : Type} {p : α → Prop} :
  injective (subtype.val : subtype p → α) :=
λ a1 a2 e, subtype.eq e

-- euclid's lesser known theorem
lemma finitely_many_primes (n : ℕ) : finite {p : PP | ↑p ≤ n} :=
@finite_preimage PP ℕ {i : ℕ | i ≤ n} (λ p, p.val) val_is_injective (finite_le_nat n)

lemma primes_contained (n : ℕ+) : {p | ord p n ≠ 0} ⊆ {p : PP | (p : ℕ) ≤ n} :=
swap big_prime_2 n

def prime_orders (n : ℕ+) : orders :=
⟨λ p, ord p n, finite_subset (finitely_many_primes n) (primes_contained n)⟩

-- Multiplying

noncomputable def product : orders → ℕ+ :=
λ os, finsupp.prod os (λ p r, pnat.pow p r)

-/

end