/-
Copyright (c) 2022 Yaël Dillies, Bhavik Mehta. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Yaël Dillies, Bhavik Mehta
-/
import data.set.equitable
import order.partition.finpartition

/-!
# Finite equipartitions

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

This file defines finite equipartitions, the partitions whose parts all are the same size up to a
difference of `1`.

## Main declarations

* `finpartition.is_equipartition`: Predicate for a `finpartition` to be an equipartition.
-/

open finset fintype

namespace finpartition
variables {α : Type*} [decidable_eq α] {s t : finset α} (P : finpartition s)

/-- An equipartition is a partition whose parts are all the same size, up to a difference of `1`. -/
def is_equipartition : Prop := (P.parts : set (finset α)).equitable_on card

lemma is_equipartition_iff_card_parts_eq_average : P.is_equipartition ↔
  ∀ a : finset α, a ∈ P.parts → a.card = s.card/P.parts.card ∨ a.card = s.card/P.parts.card + 1 :=
by simp_rw [is_equipartition, finset.equitable_on_iff, P.sum_card_parts]

variables {P}

lemma _root_.set.subsingleton.is_equipartition (h : (P.parts : set (finset α)).subsingleton) :
  P.is_equipartition :=
h.equitable_on _

lemma is_equipartition.card_parts_eq_average (hP : P.is_equipartition) (ht : t ∈ P.parts) :
  t.card = s.card / P.parts.card ∨ t.card = s.card / P.parts.card + 1 :=
P.is_equipartition_iff_card_parts_eq_average.1 hP _ ht

lemma is_equipartition.card_part_le_average_add_one (hP : P.is_equipartition) (ht : t ∈ P.parts) :
  t.card ≤ s.card / P.parts.card + 1 :=
by { rw ←P.sum_card_parts, exact equitable_on.le_add_one hP ht }

/-! ### Discrete and indiscrete finpartition -/

variables (s)

lemma bot_is_equipartition : (⊥ : finpartition s).is_equipartition :=
set.equitable_on_iff_exists_eq_eq_add_one.2 ⟨1, by simp⟩

lemma top_is_equipartition : (⊤ : finpartition s).is_equipartition :=
(parts_top_subsingleton _).is_equipartition

lemma indiscrete_is_equipartition {hs : s ≠ ∅} : (indiscrete hs).is_equipartition :=
by { rw [is_equipartition, indiscrete_parts, coe_singleton], exact set.equitable_on_singleton s _ }

end finpartition


/-
Copyright (c) 2014 Parikshit Khanna. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Parikshit Khanna, Jeremy Avigad, Leonardo de Moura, Floris van Doorn, Mario Carneiro
-/
import data.list.big_operators

/-!
# Counting in lists

This file proves basic properties of `list.countp` and `list.count`, which count the number of
elements of a list satisfying a predicate and equal to a given element respectively. Their
definitions can be found in [`data.list.defs`](./data/list/defs).
-/

open nat

variables {α β : Type*} {l l₁ l₂ : list α}

namespace list

section countp
variables (p : α → Prop) [decidable_pred p]

@[simp] lemma countp_nil : countp p [] = 0 := rfl

@[simp] lemma countp_cons_of_pos {a : α} (l) (pa : p a) : countp p (a::l) = countp p l + 1 :=
if_pos pa

@[simp] lemma countp_cons_of_neg {a : α} (l) (pa : ¬ p a) : countp p (a::l) = countp p l :=
if_neg pa

lemma length_eq_countp_add_countp (l) : length l = countp p l + countp (λ a, ¬p a) l :=
by induction l with x h ih; [refl, by_cases p x];
  [simp only [countp_cons_of_pos _ _ h, countp_cons_of_neg (λ a, ¬p a) _ (decidable.not_not.2 h),
    ih, length],
   simp only [countp_cons_of_pos (λ a, ¬p a) _ h, countp_cons_of_neg _ _ h, ih, length]]; ac_refl

lemma countp_eq_length_filter (l) : countp p l = length (filter p l) :=
by induction l with x l ih; [refl, by_cases (p x)];
  [simp only [filter_cons_of_pos _ h, countp, ih, if_pos h],
   simp only [countp_cons_of_neg _ _ h, ih, filter_cons_of_neg _ h]]; refl

lemma countp_le_length : countp p l ≤ l.length :=
by simpa only [countp_eq_length_filter] using length_le_of_sublist (filter_sublist _)

@[simp] lemma countp_append (l₁ l₂) : countp p (l₁ ++ l₂) = countp p l₁ + countp p l₂ :=
by simp only [countp_eq_length_filter, filter_append, length_append]

lemma countp_pos {l} : 0 < countp p l ↔ ∃ a ∈ l, p a :=
by simp only [countp_eq_length_filter, length_pos_iff_exists_mem, mem_filter, exists_prop]

lemma countp_eq_length {l} : countp p l = l.length ↔ ∀ a ∈ l, p a :=
by rw [countp_eq_length_filter, filter_length_eq_length]

lemma length_filter_lt_length_iff_exists (l) : length (filter p l) < length l ↔ ∃ x ∈ l, ¬p x :=
by rw [length_eq_countp_add_countp p l, ← countp_pos, countp_eq_length_filter, lt_add_iff_pos_right]

lemma sublist.countp_le (s : l₁ <+ l₂) : countp p l₁ ≤ countp p l₂ :=
by simpa only [countp_eq_length_filter] using length_le_of_sublist (s.filter p)

@[simp] lemma countp_filter {q} [decidable_pred q] (l : list α) :
  countp p (filter q l) = countp (λ a, p a ∧ q a) l :=
by simp only [countp_eq_length_filter, filter_filter]

@[simp] lemma countp_true : l.countp (λ _, true) = l.length :=
by simp [countp_eq_length_filter]

@[simp] lemma countp_false : l.countp (λ _, false) = 0 :=
by simp [countp_eq_length_filter]

end countp

/-! ### count -/

section count
variables [decidable_eq α]

@[simp] lemma count_nil (a : α) : count a [] = 0 := rfl

lemma count_cons (a b : α) (l : list α) :
  count a (b :: l) = if a = b then succ (count a l) else count a l := rfl

lemma count_cons' (a b : α) (l : list α) :
  count a (b :: l) = count a l + (if a = b then 1 else 0) :=
begin rw count_cons, split_ifs; refl end

@[simp] lemma count_cons_self (a : α) (l : list α) : count a (a::l) = succ (count a l) := if_pos rfl

@[simp, priority 990]
lemma count_cons_of_ne {a b : α} (h : a ≠ b) (l : list α) : count a (b::l) = count a l := if_neg h

lemma count_tail : Π (l : list α) (a : α) (h : 0 < l.length),
  l.tail.count a = l.count a - ite (a = list.nth_le l 0 h) 1 0
| (_ :: _) a h := by { rw [count_cons], split_ifs; simp }

lemma count_le_length (a : α) (l : list α) : count a l ≤ l.length :=
countp_le_length _

lemma sublist.count_le (h : l₁ <+ l₂) (a : α) : count a l₁ ≤ count a l₂ := h.countp_le _

lemma count_le_count_cons (a b : α) (l : list α) : count a l ≤ count a (b :: l) :=
(sublist_cons _ _).count_le _

lemma count_singleton (a : α) : count a [a] = 1 := if_pos rfl

lemma count_singleton' (a b : α) : count a [b] = ite (a = b) 1 0 := rfl

@[simp] lemma count_append (a : α) : ∀ l₁ l₂, count a (l₁ ++ l₂) = count a l₁ + count a l₂ :=
countp_append _

lemma count_concat (a : α) (l : list α) : count a (concat l a) = succ (count a l) :=
by simp [-add_comm]

@[simp] lemma count_pos {a : α} {l : list α} : 0 < count a l ↔ a ∈ l :=
by simp only [count, countp_pos, exists_prop, exists_eq_right']

@[simp] lemma one_le_count_iff_mem {a : α} {l : list α} : 1 ≤ count a l ↔ a ∈ l :=
count_pos

@[simp, priority 980]
lemma count_eq_zero_of_not_mem {a : α} {l : list α} (h : a ∉ l) : count a l = 0 :=
decidable.by_contradiction $ λ h', h $ count_pos.1 (nat.pos_of_ne_zero h')

lemma not_mem_of_count_eq_zero {a : α} {l : list α} (h : count a l = 0) : a ∉ l :=
λ h', (count_pos.2 h').ne' h

lemma count_eq_length {a : α} {l} : count a l = l.length ↔ ∀ b ∈ l, a = b :=
by rw [count, countp_eq_length]

@[simp] lemma count_repeat (a : α) (n : ℕ) : count a (repeat a n) = n :=
by rw [count, countp_eq_length_filter, filter_eq_self.2, length_repeat];
   exact λ b m, (eq_of_mem_repeat m).symm

lemma le_count_iff_repeat_sublist {a : α} {l : list α} {n : ℕ} :
  n ≤ count a l ↔ repeat a n <+ l :=
⟨λ h, ((repeat_sublist_repeat a).2 h).trans $
  have filter (eq a) l = repeat a (count a l), from eq_repeat.2
    ⟨by simp only [count, countp_eq_length_filter], λ b m, (of_mem_filter m).symm⟩,
  by rw ← this; apply filter_sublist,
 λ h, by simpa only [count_repeat] using h.count_le a⟩

lemma repeat_count_eq_of_count_eq_length  {a : α} {l : list α} (h : count a l = length l)  :
  repeat a (count a l) = l :=
eq_of_sublist_of_length_eq (le_count_iff_repeat_sublist.mp (le_refl (count a l)))
    (eq.trans (length_repeat a (count a l)) h)

@[simp] lemma count_filter {p} [decidable_pred p]
  {a} {l : list α} (h : p a) : count a (filter p l) = count a l :=
by simp only [count, countp_filter, show (λ b, a = b ∧ p b) = eq a, by { ext b, constructor; cc }]

lemma count_bind {α β} [decidable_eq β] (l : list α) (f : α → list β) (x : β)  :
  count x (l.bind f) = sum (map (count x ∘ f) l) :=
begin
  induction l with hd tl IH,
  { simp },
  { simpa }
end

@[simp] lemma count_map_of_injective {α β} [decidable_eq α] [decidable_eq β]
  (l : list α) (f : α → β) (hf : function.injective f) (x : α) :
  count (f x) (map f l) = count x l :=
begin
  induction l with y l IH generalizing x,
  { simp },
  { simp [map_cons, count_cons', IH, hf.eq_iff] }
end

lemma count_le_count_map [decidable_eq β] (l : list α) (f : α → β) (x : α) :
  count x l ≤ count (f x) (map f l) :=
begin
  induction l with a as IH, { simp },
  rcases eq_or_ne x a with rfl | hxa,
  { simp [succ_le_succ IH] },
  { simp [hxa, le_add_right IH, count_cons'] }
end

@[simp] lemma count_erase_self (a : α) :
  ∀ (s : list α), count a (list.erase s a) = pred (count a s)
| [] := by simp
| (h :: t) :=
begin
  rw erase_cons,
  by_cases p : h = a,
  { rw [if_pos p, count_cons', if_pos p.symm], simp },
  { rw [if_neg p, count_cons', count_cons', if_neg (λ x : a = h, p x.symm), count_erase_self],
    simp }
end

@[simp] lemma count_erase_of_ne {a b : α} (ab : a ≠ b) :
  ∀ (s : list α), count a (list.erase s b) = count a s
| [] := by simp
| (x :: xs) :=
begin
  rw erase_cons,
  split_ifs with h,
  { rw [count_cons', h, if_neg ab], simp },
  { rw [count_cons', count_cons', count_erase_of_ne] }
end

end count

end list


/-
Copyright (c) 2020 Aaron Anderson. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Aaron Anderson

! This file was ported from Lean 3 source module ring_theory.simple_module
! leanprover-community/mathlib commit cce7f68a7eaadadf74c82bbac20721cdc03a1cc1
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.LinearAlgebra.Isomorphisms
import Mathbin.Order.JordanHolder

/-!
# Simple Modules

## Main Definitions
  * `is_simple_module` indicates that a module has no proper submodules
  (the only submodules are `⊥` and `⊤`).
  * `is_semisimple_module` indicates that every submodule has a complement, or equivalently,
    the module is a direct sum of simple modules.
  * A `division_ring` structure on the endomorphism ring of a simple module.

## Main Results
  * Schur's Lemma: `bijective_or_eq_zero` shows that a linear map between simple modules
  is either bijective or 0, leading to a `division_ring` structure on the endomorphism ring.

## TODO
  * Artin-Wedderburn Theory
  * Unify with the work on Schur's Lemma in a category theory context

-/

variable (R : Type _) [Ring R] (M : Type _) [AddCommGroup M] [Module R M]

/-- A module is simple when it has only two submodules, `⊥` and `⊤`. -/
abbrev IsSimpleModule :=
  IsSimpleOrder (Submodule R M)
#align is_simple_module IsSimpleModule

/-- A module is semisimple when every submodule has a complement, or equivalently, the module
  is a direct sum of simple modules. -/
abbrev IsSemisimpleModule :=
  ComplementedLattice (Submodule R M)
#align is_semisimple_module IsSemisimpleModule

-- Making this an instance causes the linter to complain of "dangerous instances"
theorem IsSimpleModule.nontrivial [IsSimpleModule R M] : Nontrivial M :=
  ⟨⟨0, by
      have h : (⊥ : Submodule R M) ≠ ⊤ := bot_ne_top
      contrapose! h
      ext
      simp [Submodule.mem_bot, Submodule.mem_top, h x]⟩⟩
#align is_simple_module.nontrivial IsSimpleModule.nontrivial

variable {R} {M} {m : Submodule R M} {N : Type _} [AddCommGroup N] [Module R N]

theorem IsSimpleModule.congr (l : M ≃ₗ[R] N) [IsSimpleModule R N] : IsSimpleModule R M :=
  (Submodule.orderIsoMapComap l).IsSimpleOrder
#align is_simple_module.congr IsSimpleModule.congr

theorem isSimpleModule_iff_isAtom : IsSimpleModule R m ↔ IsAtom m :=
  by
  rw [← Set.isSimpleOrder_Iic_iff_isAtom]
  apply OrderIso.isSimpleOrder_iff
  exact Submodule.MapSubtype.relIso m
#align is_simple_module_iff_is_atom isSimpleModule_iff_isAtom

theorem isSimpleModule_iff_isCoatom : IsSimpleModule R (M ⧸ m) ↔ IsCoatom m :=
  by
  rw [← Set.isSimpleOrder_Ici_iff_isCoatom]
  apply OrderIso.isSimpleOrder_iff
  exact Submodule.comapMkQRelIso m
#align is_simple_module_iff_is_coatom isSimpleModule_iff_isCoatom

theorem covby_iff_quot_is_simple {A B : Submodule R M} (hAB : A ≤ B) :
    A ⋖ B ↔ IsSimpleModule R (B ⧸ Submodule.comap B.Subtype A) :=
  by
  set f : Submodule R B ≃o Set.Iic B := Submodule.MapSubtype.relIso B with hf
  rw [covby_iff_coatom_Iic hAB, isSimpleModule_iff_isCoatom, ← OrderIso.isCoatom_iff f, hf]
  simp [-OrderIso.isCoatom_iff, Submodule.MapSubtype.relIso, Submodule.map_comap_subtype,
    inf_eq_right.2 hAB]
#align covby_iff_quot_is_simple covby_iff_quot_is_simple

namespace IsSimpleModule

variable [hm : IsSimpleModule R m]

@[simp]
theorem isAtom : IsAtom m :=
  isSimpleModule_iff_isAtom.1 hm
#align is_simple_module.is_atom IsSimpleModule.isAtom

end IsSimpleModule

theorem is_semisimple_of_supₛ_simples_eq_top
    (h : supₛ { m : Submodule R M | IsSimpleModule R m } = ⊤) : IsSemisimpleModule R M :=
  complementedLattice_of_supₛ_atoms_eq_top (by simp_rw [← h, isSimpleModule_iff_isAtom])
#align is_semisimple_of_Sup_simples_eq_top is_semisimple_of_supₛ_simples_eq_top

namespace IsSemisimpleModule

variable [IsSemisimpleModule R M]

theorem supₛ_simples_eq_top : supₛ { m : Submodule R M | IsSimpleModule R m } = ⊤ :=
  by
  simp_rw [isSimpleModule_iff_isAtom]
  exact supₛ_atoms_eq_top
#align is_semisimple_module.Sup_simples_eq_top IsSemisimpleModule.supₛ_simples_eq_top

instance is_semisimple_submodule {m : Submodule R M} : IsSemisimpleModule R m :=
  haveI f : Submodule R m ≃o Set.Iic m := Submodule.MapSubtype.relIso m
  f.complemented_lattice_iff.2 IsModularLattice.complementedLattice_Iic
#align is_semisimple_module.is_semisimple_submodule IsSemisimpleModule.is_semisimple_submodule

end IsSemisimpleModule

theorem is_semisimple_iff_top_eq_supₛ_simples :
    supₛ { m : Submodule R M | IsSimpleModule R m } = ⊤ ↔ IsSemisimpleModule R M :=
  ⟨is_semisimple_of_supₛ_simples_eq_top, by
    intro
    exact IsSemisimpleModule.supₛ_simples_eq_top⟩
#align is_semisimple_iff_top_eq_Sup_simples is_semisimple_iff_top_eq_supₛ_simples

namespace LinearMap

theorem injective_or_eq_zero [IsSimpleModule R M] (f : M →ₗ[R] N) : Function.Injective f ∨ f = 0 :=
  by
  rw [← ker_eq_bot, ← ker_eq_top]
  apply eq_bot_or_eq_top
#align linear_map.injective_or_eq_zero LinearMap.injective_or_eq_zero

theorem injective_of_ne_zero [IsSimpleModule R M] {f : M →ₗ[R] N} (h : f ≠ 0) :
    Function.Injective f :=
  f.injective_or_eq_zero.resolve_right h
#align linear_map.injective_of_ne_zero LinearMap.injective_of_ne_zero

theorem surjective_or_eq_zero [IsSimpleModule R N] (f : M →ₗ[R] N) :
    Function.Surjective f ∨ f = 0 :=
  by
  rw [← range_eq_top, ← range_eq_bot, or_comm']
  apply eq_bot_or_eq_top
#align linear_map.surjective_or_eq_zero LinearMap.surjective_or_eq_zero

theorem surjective_of_ne_zero [IsSimpleModule R N] {f : M →ₗ[R] N} (h : f ≠ 0) :
    Function.Surjective f :=
  f.surjective_or_eq_zero.resolve_right h
#align linear_map.surjective_of_ne_zero LinearMap.surjective_of_ne_zero

/-- **Schur's Lemma** for linear maps between (possibly distinct) simple modules -/
theorem bijective_or_eq_zero [IsSimpleModule R M] [IsSimpleModule R N] (f : M →ₗ[R] N) :
    Function.Bijective f ∨ f = 0 := by
  by_cases h : f = 0
  · right
    exact h
  exact Or.intro_left _ ⟨injective_of_ne_zero h, surjective_of_ne_zero h⟩
#align linear_map.bijective_or_eq_zero LinearMap.bijective_or_eq_zero

theorem bijective_of_ne_zero [IsSimpleModule R M] [IsSimpleModule R N] {f : M →ₗ[R] N} (h : f ≠ 0) :
    Function.Bijective f :=
  f.bijective_or_eq_zero.resolve_right h
#align linear_map.bijective_of_ne_zero LinearMap.bijective_of_ne_zero

theorem isCoatom_ker_of_surjective [IsSimpleModule R N] {f : M →ₗ[R] N}
    (hf : Function.Surjective f) : IsCoatom f.ker :=
  by
  rw [← isSimpleModule_iff_isCoatom]
  exact IsSimpleModule.congr (f.quot_ker_equiv_of_surjective hf)
#align linear_map.is_coatom_ker_of_surjective LinearMap.isCoatom_ker_of_surjective

/-- Schur's Lemma makes the endomorphism ring of a simple module a division ring. -/
noncomputable instance Module.End.divisionRing [DecidableEq (Module.End R M)] [IsSimpleModule R M] :
    DivisionRing (Module.End R M) :=
  {
    (Module.End.ring :
      Ring
        (Module.End R
          M)) with
    inv := fun f =>
      if h : f = 0 then 0
      else
        LinearMap.inverse f (Equiv.ofBijective _ (bijective_of_ne_zero h)).invFun
          (Equiv.ofBijective _ (bijective_of_ne_zero h)).left_inv
          (Equiv.ofBijective _ (bijective_of_ne_zero h)).right_inv
    exists_pair_ne :=
      ⟨0, 1, by
        haveI := IsSimpleModule.nontrivial R M
        have h := exists_pair_ne M
        contrapose! h
        intro x y
        simp_rw [ext_iff, one_apply, zero_apply] at h
        rw [← h x, h y]⟩
    mul_inv_cancel := by
      intro a a0
      change a * dite _ _ _ = 1
      ext
      rw [dif_neg a0, mul_eq_comp, one_apply, comp_apply]
      exact (Equiv.ofBijective _ (bijective_of_ne_zero a0)).right_inv x
    inv_zero := dif_pos rfl }
#align module.End.division_ring Module.End.divisionRing

end LinearMap

instance jordanHolderModule : JordanHolderLattice (Submodule R M)
    where
  IsMaximal := (· ⋖ ·)
  lt_of_isMaximal x y := Covby.lt
  sup_eq_of_isMaximal x y z hxz hyz := Wcovby.sup_eq hxz.Wcovby hyz.Wcovby
  isMaximal_inf_left_of_isMaximal_sup A B := inf_covby_of_covby_sup_of_covby_sup_left
  Iso X Y := Nonempty <| (X.2 ⧸ X.1.comap X.2.Subtype) ≃ₗ[R] Y.2 ⧸ Y.1.comap Y.2.Subtype
  iso_symm := fun A B ⟨f⟩ => ⟨f.symm⟩
  iso_trans := fun A B C ⟨f⟩ ⟨g⟩ => ⟨f.trans g⟩
  second_iso A B h :=
    ⟨by
      rw [sup_comm, inf_comm]
      exact (LinearMap.quotientInfEquivSupQuotient B A).symm⟩
#align jordan_holder_module jordanHolderModule


import algebra.ring
import commutative_algebra.bool_field
import tactic.pi_instances tactic.squeeze

universes u v
variables (U : Type u) (V : Type v)

def ring_of_bool_subsets := (U → bool)

instance : comm_ring (ring_of_bool_subsets U) :=
 by { unfold ring_of_bool_subsets, pi_instance, }

lemma val_zero (x : U) : (0 : ring_of_bool_subsets U) x = ff := rfl
lemma val_one  (x : U) : (1 : ring_of_bool_subsets U) x = tt := rfl
lemma val_neg  (f : ring_of_bool_subsets U) (x : U) : (- f) x = f x := rfl
lemma val_add  (f g : ring_of_bool_subsets U) (x : U) : (f + g) x = bxor (f x) (g x) := rfl
lemma val_mul  (f g : ring_of_bool_subsets U) (x : U) : (f * g) x = band (f x) (g x) := rfl

open classical

def ring_of_subsets := set V

namespace ring_of_subsets

local attribute [instance] classical.dec

instance : has_zero (ring_of_subsets V) := ⟨(∅ : set V)⟩

instance : has_one  (ring_of_subsets V) := ⟨(set.univ : set V)⟩

instance : has_neg  (ring_of_subsets V) := ⟨(λ s, s)⟩

instance : has_add  (ring_of_subsets V) :=
 ⟨(λ s t : set V, (s \ t ∪ t \ s : set V))⟩

instance : has_mul (ring_of_subsets V) :=
 ⟨(λ s t : set V, (s ∩ t : set V))⟩

instance : has_mem V (ring_of_subsets V) :=
 ⟨λ (x : V) (s : set V), x ∈ s⟩

variable (x : V)

lemma mem_zero_iff : x ∈ (0 : ring_of_subsets V) ↔ false :=
 (iff_false _).mpr (set.not_mem_empty x)

lemma mem_one_iff : x ∈ (1 : ring_of_subsets V) ↔ true :=
 (iff_true _).mpr (set.mem_univ x)

lemma mem_neg_iff (s : ring_of_subsets V) : x ∈ (- s) ↔ x ∈ s :=
 by { change x ∈ s ↔ x ∈ s, refl }

lemma mem_add_iff (s t : ring_of_subsets V) :
 x ∈ s + t ↔ ((x ∈ s ∧ x ∉ t) ∨ (x∈ t ∧ x ∉ s)) :=
 by { unfold has_add.add, rw[set.mem_union,set.mem_diff,set.mem_diff],}

lemma mem_mul_iff (s t : ring_of_subsets V) :
 x ∈ s * t ↔ (x ∈ s ∧ x ∈ t) :=
 by { unfold has_mul.mul, rw[set.mem_inter_iff], }

instance : comm_ring (ring_of_subsets V) := {
  zero := (0 : ring_of_subsets V), one := 1,
  neg := has_neg.neg, add := (+), mul := (*),
  add_zero := λ a, by { ext x, rw[mem_add_iff, mem_zero_iff], simp },
  zero_add := λ a, by { ext x, rw[mem_add_iff, mem_zero_iff], simp },
  add_left_neg := λ a, begin
    ext x, rw[mem_add_iff, mem_neg_iff, mem_zero_iff],
    by_cases ha : x ∈ a;
    simp[ha]
  end,
  add_comm := λ a b, begin
    ext x, rw[mem_add_iff, mem_add_iff],
    by_cases ha : x ∈ a; by_cases hb : x ∈ b;
    simp[ha,hb]
  end,
  add_assoc := λ a b c, begin
    ext x, repeat { rw[mem_add_iff] },
    by_cases ha : x ∈ a; by_cases hb : x ∈ b; by_cases hc : x ∈ c;
    simp[ha,hb,hc],
  end,
  mul_one := λ a, by { ext x, rw[mem_mul_iff, mem_one_iff], simp },
  one_mul := λ a, by { ext x, rw[mem_mul_iff, mem_one_iff], simp },
  mul_comm := λ a b, begin
    ext x, rw[mem_mul_iff, mem_mul_iff, and_comm],
  end,
  mul_assoc := λ a b c, begin
    ext x, repeat { rw[mem_mul_iff] }, rw[and_assoc],
  end,
  left_distrib := λ a b c, begin
    ext x, rw[mem_add_iff, mem_mul_iff, mem_add_iff, mem_mul_iff, mem_mul_iff],
    by_cases ha : x ∈ a; by_cases hb : x ∈ b;
    simp[ha,hb]
  end,
  right_distrib := λ a b c, begin
    ext x, rw[mem_add_iff, mem_mul_iff, mem_add_iff, mem_mul_iff, mem_mul_iff],
    by_cases ha : x ∈ a; by_cases hb : x ∈ b;
    simp[ha,hb]
  end
 }

variable {V}

noncomputable def indicator : ring_of_subsets V →+* ring_of_bool_subsets V := {
 to_fun := λ s x, (if x ∈ s then tt else ff),
 map_zero' := by { ext x, rw[mem_zero_iff V x,if_false], refl },
 map_add' := λ s t, by {
  ext x,
  rw[mem_add_iff, val_add],
  by_cases hs : x ∈ s; by_cases ht : x ∈ t; simp[hs,ht],
 },
 map_one' := by { ext x, rw[mem_one_iff V x,if_true], refl },
 map_mul' := λ s t, by {
  ext x,
  rw[mem_mul_iff, val_mul],
  by_cases hs : x ∈ s; by_cases ht : x ∈ t;
  simp[hs, ht],
 }
}

end ring_of_subsets

namespace ring_of_bool_subsets

variable {U}

def support : (ring_of_bool_subsets U) →+* (ring_of_subsets U) := {
 to_fun := λ (f : U → bool), (λ x, f x = tt),
 map_zero' := begin
  ext x, rw[set.mem_def, val_zero, ring_of_subsets.mem_zero_iff], simp only [],
 end,
 map_add' := λ s t, begin
  ext x, rw[ring_of_subsets.mem_add_iff],
  repeat { rw[set.mem_def] },
  rw[val_add],
  cases (s x); cases (t x); rw[bxor]; exact dec_trivial,
 end,
 map_one' := begin
  ext x, rw[set.mem_def, val_one, ring_of_subsets.mem_one_iff, eq_self_iff_true]
 end,
 map_mul' := λ s t, begin
  ext x, rw[ring_of_subsets.mem_mul_iff],
  repeat { rw[set.mem_def] },
  rw[val_mul],
  cases (s x); cases (t x); rw[band]; exact dec_trivial,
 end,
}

end ring_of_bool_subsets

namespace ring_of_subsets

noncomputable def bool_equiv : (ring_of_subsets U) ≃ (ring_of_bool_subsets U) := {
 to_fun := @indicator U,
 inv_fun := @ring_of_bool_subsets.support U,
 left_inv := λ s, begin
  haveI := classical.dec,
  rw[ring_of_bool_subsets.support,indicator],
  ext x,dsimp[has_mem.mem,set.mem],
  split_ifs;simp only [h,iff_self,eq_self_iff_true],
 end,
 right_inv := λ f, begin
  ext x,
  dsimp[indicator,ring_of_bool_subsets.support,has_mem.mem,set.mem],
  cases f x; simp,
 end
}

end ring_of_subsets