l3lab/ntp-mathlib huggingface dataset:
/-- `pi m t` constructs the Cartesian product over `t` indexed by `m`. -/
def pi (m : Multiset α) (t : ∀ a, Multiset (β a)) : Multiset (∀ a ∈ m, β a) :=
  m.recOn {Pi.empty β}
    (fun a m (p : Multiset (∀ a ∈ m, β a)) => (t a).bind fun b => p.map <| Pi.cons m a b)
    (by
      intro a a' m n
      by_cases eq : a = a'
      · 

Proof state:
case pos
α : Type u_1
inst✝ : DecidableEq α
β : α → Type u
δ : α → Sort v
m✝ : Multiset α
t : (a : α) → Multiset (β a)
a a' : α
m : Multiset α
n : Multiset ((a : α) → a ∈ m → β a)
eq : a = a'
⊢ HEq (bind (t a) fun b => map (Pi.cons (a' ::ₘ m) a b) (bind (t a') fun b => map (Pi.cons m a' b) n))
    (bind (t a') fun b => map (Pi.cons (a ::ₘ m) a' b) (bind (t a) fun b => map (Pi.cons m a b) n))

Next tactic:
subst eq
/-- `pi m t` constructs the Cartesian product over `t` indexed by `m`. -/
def pi (m : Multiset α) (t : ∀ a, Multiset (β a)) : Multiset (∀ a ∈ m, β a) :=
  m.recOn {Pi.empty β}
    (fun a m (p : Multiset (∀ a ∈ m, β a)) => (t a).bind fun b => p.map <| Pi.cons m a b)
    (by
      intro a a' m n
      by_cases eq : a = a'
      · subst eq; 

Proof state:
case pos
α : Type u_1
inst✝ : DecidableEq α
β : α → Type u
δ : α → Sort v
m✝ : Multiset α
t : (a : α) → Multiset (β a)
a : α
m : Multiset α
n : Multiset ((a : α) → a ∈ m → β a)
⊢ HEq (bind (t a) fun b => map (Pi.cons (a ::ₘ m) a b) (bind (t a) fun b => map (Pi.cons m a b) n))
    (bind (t a) fun b => map (Pi.cons (a ::ₘ m) a b) (bind (t a) fun b => map (Pi.cons m a b) n))

Next tactic:
rfl
/-- `pi m t` constructs the Cartesian product over `t` indexed by `m`. -/
def pi (m : Multiset α) (t : ∀ a, Multiset (β a)) : Multiset (∀ a ∈ m, β a) :=
  m.recOn {Pi.empty β}
    (fun a m (p : Multiset (∀ a ∈ m, β a)) => (t a).bind fun b => p.map <| Pi.cons m a b)
    (by
      intro a a' m n
      by_cases eq : a = a'
      · subst eq; rfl
      · 

Proof state:
case neg
α : Type u_1
inst✝ : DecidableEq α
β : α → Type u
δ : α → Sort v
m✝ : Multiset α
t : (a : α) → Multiset (β a)
a a' : α
m : Multiset α
n : Multiset ((a : α) → a ∈ m → β a)
eq : ¬a = a'
⊢ HEq (bind (t a) fun b => map (Pi.cons (a' ::ₘ m) a b) (bind (t a') fun b => map (Pi.cons m a' b) n))
    (bind (t a') fun b => map (Pi.cons (a ::ₘ m) a' b) (bind (t a) fun b => map (Pi.cons m a b) n))

Next tactic:
simp [map_bind, bind_bind (t a') (t a)]
/-- `pi m t` constructs the Cartesian product over `t` indexed by `m`. -/
def pi (m : Multiset α) (t : ∀ a, Multiset (β a)) : Multiset (∀ a ∈ m, β a) :=
  m.recOn {Pi.empty β}
    (fun a m (p : Multiset (∀ a ∈ m, β a)) => (t a).bind fun b => p.map <| Pi.cons m a b)
    (by
      intro a a' m n
      by_cases eq : a = a'
      · subst eq; rfl
      · simp [map_bind, bind_bind (t a') (t a)]
        

Proof state:
case neg
α : Type u_1
inst✝ : DecidableEq α
β : α → Type u
δ : α → Sort v
m✝ : Multiset α
t : (a : α) → Multiset (β a)
a a' : α
m : Multiset α
n : Multiset ((a : α) → a ∈ m → β a)
eq : ¬a = a'
⊢ HEq (bind (t a) fun b => bind (t a') fun a_1 => map (fun x => Pi.cons (a' ::ₘ m) a b (Pi.cons m a' a_1 x)) n)
    (bind (t a) fun b => bind (t a') fun a_1 => map (fun x => Pi.cons (a ::ₘ m) a' a_1 (Pi.cons m a b x)) n)

Next tactic:
apply bind_hcongr
/-- `pi m t` constructs the Cartesian product over `t` indexed by `m`. -/
def pi (m : Multiset α) (t : ∀ a, Multiset (β a)) : Multiset (∀ a ∈ m, β a) :=
  m.recOn {Pi.empty β}
    (fun a m (p : Multiset (∀ a ∈ m, β a)) => (t a).bind fun b => p.map <| Pi.cons m a b)
    (by
      intro a a' m n
      by_cases eq : a = a'
      · subst eq; rfl
      · simp [map_bind, bind_bind (t a') (t a)]
        apply bind_hcongr
        · 

Proof state:
case neg.h
α : Type u_1
inst✝ : DecidableEq α
β : α → Type u
δ : α → Sort v
m✝ : Multiset α
t : (a : α) → Multiset (β a)
a a' : α
m : Multiset α
n : Multiset ((a : α) → a ∈ m → β a)
eq : ¬a = a'
⊢ ((a_1 : α) → a_1 ∈ a ::ₘ a' ::ₘ m → β a_1) = ((a_1 : α) → a_1 ∈ a' ::ₘ a ::ₘ m → β a_1)

Next tactic:
rw [cons_swap a a']
/-- `pi m t` constructs the Cartesian product over `t` indexed by `m`. -/
def pi (m : Multiset α) (t : ∀ a, Multiset (β a)) : Multiset (∀ a ∈ m, β a) :=
  m.recOn {Pi.empty β}
    (fun a m (p : Multiset (∀ a ∈ m, β a)) => (t a).bind fun b => p.map <| Pi.cons m a b)
    (by
      intro a a' m n
      by_cases eq : a = a'
      · subst eq; rfl
      · simp [map_bind, bind_bind (t a') (t a)]
        apply bind_hcongr
        · rw [cons_swap a a']
        

Proof state:
case neg.hf
α : Type u_1
inst✝ : DecidableEq α
β : α → Type u
δ : α → Sort v
m✝ : Multiset α
t : (a : α) → Multiset (β a)
a a' : α
m : Multiset α
n : Multiset ((a : α) → a ∈ m → β a)
eq : ¬a = a'
⊢ ∀ a_1 ∈ t a,
    HEq (bind (t a') fun a_3 => map (fun x => Pi.cons (a' ::ₘ m) a a_1 (Pi.cons m a' a_3 x)) n)
      (bind (t a') fun a_3 => map (fun x => Pi.cons (a ::ₘ m) a' a_3 (Pi.cons m a a_1 x)) n)

Next tactic:
intro b _
/-- `pi m t` constructs the Cartesian product over `t` indexed by `m`. -/
def pi (m : Multiset α) (t : ∀ a, Multiset (β a)) : Multiset (∀ a ∈ m, β a) :=
  m.recOn {Pi.empty β}
    (fun a m (p : Multiset (∀ a ∈ m, β a)) => (t a).bind fun b => p.map <| Pi.cons m a b)
    (by
      intro a a' m n
      by_cases eq : a = a'
      · subst eq; rfl
      · simp [map_bind, bind_bind (t a') (t a)]
        apply bind_hcongr
        · rw [cons_swap a a']
        intro b _
        

Proof state:
case neg.hf
α : Type u_1
inst✝ : DecidableEq α
β : α → Type u
δ : α → Sort v
m✝ : Multiset α
t : (a : α) → Multiset (β a)
a a' : α
m : Multiset α
n : Multiset ((a : α) → a ∈ m → β a)
eq : ¬a = a'
b : β a
a✝ : b ∈ t a
⊢ HEq (bind (t a') fun a_1 => map (fun x => Pi.cons (a' ::ₘ m) a b (Pi.cons m a' a_1 x)) n)
    (bind (t a') fun a_1 => map (fun x => Pi.cons (a ::ₘ m) a' a_1 (Pi.cons m a b x)) n)

Next tactic:
apply bind_hcongr
/-- `pi m t` constructs the Cartesian product over `t` indexed by `m`. -/
def pi (m : Multiset α) (t : ∀ a, Multiset (β a)) : Multiset (∀ a ∈ m, β a) :=
  m.recOn {Pi.empty β}
    (fun a m (p : Multiset (∀ a ∈ m, β a)) => (t a).bind fun b => p.map <| Pi.cons m a b)
    (by
      intro a a' m n
      by_cases eq : a = a'
      · subst eq; rfl
      · simp [map_bind, bind_bind (t a') (t a)]
        apply bind_hcongr
        · rw [cons_swap a a']
        intro b _
        apply bind_hcongr
        · 

Proof state:
case neg.hf.h
α : Type u_1
inst✝ : DecidableEq α
β : α → Type u
δ : α → Sort v
m✝ : Multiset α
t : (a : α) → Multiset (β a)
a a' : α
m : Multiset α
n : Multiset ((a : α) → a ∈ m → β a)
eq : ¬a = a'
b : β a
a✝ : b ∈ t a
⊢ ((a_1 : α) → a_1 ∈ a ::ₘ a' ::ₘ m → β a_1) = ((a_1 : α) → a_1 ∈ a' ::ₘ a ::ₘ m → β a_1)

Next tactic:
rw [cons_swap a a']
/-- `pi m t` constructs the Cartesian product over `t` indexed by `m`. -/
def pi (m : Multiset α) (t : ∀ a, Multiset (β a)) : Multiset (∀ a ∈ m, β a) :=
  m.recOn {Pi.empty β}
    (fun a m (p : Multiset (∀ a ∈ m, β a)) => (t a).bind fun b => p.map <| Pi.cons m a b)
    (by
      intro a a' m n
      by_cases eq : a = a'
      · subst eq; rfl
      · simp [map_bind, bind_bind (t a') (t a)]
        apply bind_hcongr
        · rw [cons_swap a a']
        intro b _
        apply bind_hcongr
        · rw [cons_swap a a']
        

Proof state:
case neg.hf.hf
α : Type u_1
inst✝ : DecidableEq α
β : α → Type u
δ : α → Sort v
m✝ : Multiset α
t : (a : α) → Multiset (β a)
a a' : α
m : Multiset α
n : Multiset ((a : α) → a ∈ m → β a)
eq : ¬a = a'
b : β a
a✝ : b ∈ t a
⊢ ∀ a_1 ∈ t a',
    HEq (map (fun x => Pi.cons (a' ::ₘ m) a b (Pi.cons m a' a_1 x)) n)
      (map (fun x => Pi.cons (a ::ₘ m) a' a_1 (Pi.cons m a b x)) n)

Next tactic:
intro b' _
/-- `pi m t` constructs the Cartesian product over `t` indexed by `m`. -/
def pi (m : Multiset α) (t : ∀ a, Multiset (β a)) : Multiset (∀ a ∈ m, β a) :=
  m.recOn {Pi.empty β}
    (fun a m (p : Multiset (∀ a ∈ m, β a)) => (t a).bind fun b => p.map <| Pi.cons m a b)
    (by
      intro a a' m n
      by_cases eq : a = a'
      · subst eq; rfl
      · simp [map_bind, bind_bind (t a') (t a)]
        apply bind_hcongr
        · rw [cons_swap a a']
        intro b _
        apply bind_hcongr
        · rw [cons_swap a a']
        intro b' _
        

Proof state:
case neg.hf.hf
α : Type u_1
inst✝ : DecidableEq α
β : α → Type u
δ : α → Sort v
m✝ : Multiset α
t : (a : α) → Multiset (β a)
a a' : α
m : Multiset α
n : Multiset ((a : α) → a ∈ m → β a)
eq : ¬a = a'
b : β a
a✝¹ : b ∈ t a
b' : β a'
a✝ : b' ∈ t a'
⊢ HEq (map (fun x => Pi.cons (a' ::ₘ m) a b (Pi.cons m a' b' x)) n)
    (map (fun x => Pi.cons (a ::ₘ m) a' b' (Pi.cons m a b x)) n)

Next tactic:
apply map_hcongr
/-- `pi m t` constructs the Cartesian product over `t` indexed by `m`. -/
def pi (m : Multiset α) (t : ∀ a, Multiset (β a)) : Multiset (∀ a ∈ m, β a) :=
  m.recOn {Pi.empty β}
    (fun a m (p : Multiset (∀ a ∈ m, β a)) => (t a).bind fun b => p.map <| Pi.cons m a b)
    (by
      intro a a' m n
      by_cases eq : a = a'
      · subst eq; rfl
      · simp [map_bind, bind_bind (t a') (t a)]
        apply bind_hcongr
        · rw [cons_swap a a']
        intro b _
        apply bind_hcongr
        · rw [cons_swap a a']
        intro b' _
        apply map_hcongr
        · 

Proof state:
case neg.hf.hf.h
α : Type u_1
inst✝ : DecidableEq α
β : α → Type u
δ : α → Sort v
m✝ : Multiset α
t : (a : α) → Multiset (β a)
a a' : α
m : Multiset α
n : Multiset ((a : α) → a ∈ m → β a)
eq : ¬a = a'
b : β a
a✝¹ : b ∈ t a
b' : β a'
a✝ : b' ∈ t a'
⊢ ((a_1 : α) → a_1 ∈ a ::ₘ a' ::ₘ m → β a_1) = ((a_1 : α) → a_1 ∈ a' ::ₘ a ::ₘ m → β a_1)

Next tactic:
rw [cons_swap a a']
/-- `pi m t` constructs the Cartesian product over `t` indexed by `m`. -/
def pi (m : Multiset α) (t : ∀ a, Multiset (β a)) : Multiset (∀ a ∈ m, β a) :=
  m.recOn {Pi.empty β}
    (fun a m (p : Multiset (∀ a ∈ m, β a)) => (t a).bind fun b => p.map <| Pi.cons m a b)
    (by
      intro a a' m n
      by_cases eq : a = a'
      · subst eq; rfl
      · simp [map_bind, bind_bind (t a') (t a)]
        apply bind_hcongr
        · rw [cons_swap a a']
        intro b _
        apply bind_hcongr
        · rw [cons_swap a a']
        intro b' _
        apply map_hcongr
        · rw [cons_swap a a']
        

Proof state:
case neg.hf.hf.hf
α : Type u_1
inst✝ : DecidableEq α
β : α → Type u
δ : α → Sort v
m✝ : Multiset α
t : (a : α) → Multiset (β a)
a a' : α
m : Multiset α
n : Multiset ((a : α) → a ∈ m → β a)
eq : ¬a = a'
b : β a
a✝¹ : b ∈ t a
b' : β a'
a✝ : b' ∈ t a'
⊢ ∀ a_1 ∈ n, HEq (Pi.cons (a' ::ₘ m) a b (Pi.cons m a' b' a_1)) (Pi.cons (a ::ₘ m) a' b' (Pi.cons m a b a_1))

Next tactic:
intro f _
/-- `pi m t` constructs the Cartesian product over `t` indexed by `m`. -/
def pi (m : Multiset α) (t : ∀ a, Multiset (β a)) : Multiset (∀ a ∈ m, β a) :=
  m.recOn {Pi.empty β}
    (fun a m (p : Multiset (∀ a ∈ m, β a)) => (t a).bind fun b => p.map <| Pi.cons m a b)
    (by
      intro a a' m n
      by_cases eq : a = a'
      · subst eq; rfl
      · simp [map_bind, bind_bind (t a') (t a)]
        apply bind_hcongr
        · rw [cons_swap a a']
        intro b _
        apply bind_hcongr
        · rw [cons_swap a a']
        intro b' _
        apply map_hcongr
        · rw [cons_swap a a']
        intro f _
        

Proof state:
case neg.hf.hf.hf
α : Type u_1
inst✝ : DecidableEq α
β : α → Type u
δ : α → Sort v
m✝ : Multiset α
t : (a : α) → Multiset (β a)
a a' : α
m : Multiset α
n : Multiset ((a : α) → a ∈ m → β a)
eq : ¬a = a'
b : β a
a✝² : b ∈ t a
b' : β a'
a✝¹ : b' ∈ t a'
f : (a : α) → a ∈ m → β a
a✝ : f ∈ n
⊢ HEq (Pi.cons (a' ::ₘ m) a b (Pi.cons m a' b' f)) (Pi.cons (a ::ₘ m) a' b' (Pi.cons m a b f))

Next tactic:
exact Pi.cons_swap eq
theorem card_pi (m : Multiset α) (t : ∀ a, Multiset (β a)) :
    card (pi m t) = prod (m.map fun a => card (t a)) :=
  Multiset.induction_on m (by 

Proof state:
α : Type u_1
inst✝ : DecidableEq α
β : α → Type u
δ : α → Sort v
m : Multiset α
t : (a : α) → Multiset (β a)
⊢ card (pi 0 t) = prod (map (fun a => card (t a)) 0)

Next tactic:
simp
theorem card_pi (m : Multiset α) (t : ∀ a, Multiset (β a)) :
    card (pi m t) = prod (m.map fun a => card (t a)) :=
  Multiset.induction_on m (by simp) (by 

Proof state:
α : Type u_1
inst✝ : DecidableEq α
β : α → Type u
δ : α → Sort v
m : Multiset α
t : (a : α) → Multiset (β a)
⊢ ∀ ⦃a : α⦄ {s : Multiset α},
    card (pi s t) = prod (map (fun a => card (t a)) s) →
      card (pi (a ::ₘ s) t) = prod (map (fun a => card (t a)) (a ::ₘ s))

Next tactic:
simp (config := { contextual := true }) [mul_comm]
protected theorem Nodup.pi {s : Multiset α} {t : ∀ a, Multiset (β a)} :
    Nodup s → (∀ a ∈ s, Nodup (t a)) → Nodup (pi s t) :=
  Multiset.induction_on s (fun _ _ => nodup_singleton _)
    (by
      

Proof state:
α : Type u_1
inst✝ : DecidableEq α
β : α → Type u
δ : α → Sort v
s : Multiset α
t : (a : α) → Multiset (β a)
⊢ ∀ ⦃a : α⦄ {s : Multiset α},
    (Nodup s → (∀ a ∈ s, Nodup (t a)) → Nodup (pi s t)) →
      Nodup (a ::ₘ s) → (∀ a_3 ∈ a ::ₘ s, Nodup (t a_3)) → Nodup (pi (a ::ₘ s) t)

Next tactic:
intro a s ih hs ht
protected theorem Nodup.pi {s : Multiset α} {t : ∀ a, Multiset (β a)} :
    Nodup s → (∀ a ∈ s, Nodup (t a)) → Nodup (pi s t) :=
  Multiset.induction_on s (fun _ _ => nodup_singleton _)
    (by
      intro a s ih hs ht
      

Proof state:
α : Type u_1
inst✝ : DecidableEq α
β : α → Type u
δ : α → Sort v
s✝ : Multiset α
t : (a : α) → Multiset (β a)
a : α
s : Multiset α
ih : Nodup s → (∀ a ∈ s, Nodup (t a)) → Nodup (pi s t)
hs : Nodup (a ::ₘ s)
ht : ∀ a_1 ∈ a ::ₘ s, Nodup (t a_1)
⊢ Nodup (pi (a ::ₘ s) t)

Next tactic:
have has : a ∉ s := by simp at hs; exact hs.1
protected theorem Nodup.pi {s : Multiset α} {t : ∀ a, Multiset (β a)} :
    Nodup s → (∀ a ∈ s, Nodup (t a)) → Nodup (pi s t) :=
  Multiset.induction_on s (fun _ _ => nodup_singleton _)
    (by
      intro a s ih hs ht
      have has : a ∉ s := by 

Proof state:
α : Type u_1
inst✝ : DecidableEq α
β : α → Type u
δ : α → Sort v
s✝ : Multiset α
t : (a : α) → Multiset (β a)
a : α
s : Multiset α
ih : Nodup s → (∀ a ∈ s, Nodup (t a)) → Nodup (pi s t)
hs : Nodup (a ::ₘ s)
ht : ∀ a_1 ∈ a ::ₘ s, Nodup (t a_1)
⊢ a ∉ s

Next tactic:
simp at hs
protected theorem Nodup.pi {s : Multiset α} {t : ∀ a, Multiset (β a)} :
    Nodup s → (∀ a ∈ s, Nodup (t a)) → Nodup (pi s t) :=
  Multiset.induction_on s (fun _ _ => nodup_singleton _)
    (by
      intro a s ih hs ht
      have has : a ∉ s := by simp at hs; 

Proof state:
α : Type u_1
inst✝ : DecidableEq α
β : α → Type u
δ : α → Sort v
s✝ : Multiset α
t : (a : α) → Multiset (β a)
a : α
s : Multiset α
ih : Nodup s → (∀ a ∈ s, Nodup (t a)) → Nodup (pi s t)
ht : ∀ a_1 ∈ a ::ₘ s, Nodup (t a_1)
hs : a ∉ s ∧ Nodup s
⊢ a ∉ s

Next tactic:
exact hs.1
protected theorem Nodup.pi {s : Multiset α} {t : ∀ a, Multiset (β a)} :
    Nodup s → (∀ a ∈ s, Nodup (t a)) → Nodup (pi s t) :=
  Multiset.induction_on s (fun _ _ => nodup_singleton _)
    (by
      intro a s ih hs ht
      have has : a ∉ s := by simp at hs; exact hs.1
      

Proof state:
α : Type u_1
inst✝ : DecidableEq α
β : α → Type u
δ : α → Sort v
s✝ : Multiset α
t : (a : α) → Multiset (β a)
a : α
s : Multiset α
ih : Nodup s → (∀ a ∈ s, Nodup (t a)) → Nodup (pi s t)
hs : Nodup (a ::ₘ s)
ht : ∀ a_1 ∈ a ::ₘ s, Nodup (t a_1)
has : a ∉ s
⊢ Nodup (pi (a ::ₘ s) t)

Next tactic:
have hs : Nodup s := by simp at hs; exact hs.2
protected theorem Nodup.pi {s : Multiset α} {t : ∀ a, Multiset (β a)} :
    Nodup s → (∀ a ∈ s, Nodup (t a)) → Nodup (pi s t) :=
  Multiset.induction_on s (fun _ _ => nodup_singleton _)
    (by
      intro a s ih hs ht
      have has : a ∉ s := by simp at hs; exact hs.1
      have hs : Nodup s := by 

Proof state:
α : Type u_1
inst✝ : DecidableEq α
β : α → Type u
δ : α → Sort v
s✝ : Multiset α
t : (a : α) → Multiset (β a)
a : α
s : Multiset α
ih : Nodup s → (∀ a ∈ s, Nodup (t a)) → Nodup (pi s t)
hs : Nodup (a ::ₘ s)
ht : ∀ a_1 ∈ a ::ₘ s, Nodup (t a_1)
has : a ∉ s
⊢ Nodup s

Next tactic:
simp at hs
protected theorem Nodup.pi {s : Multiset α} {t : ∀ a, Multiset (β a)} :
    Nodup s → (∀ a ∈ s, Nodup (t a)) → Nodup (pi s t) :=
  Multiset.induction_on s (fun _ _ => nodup_singleton _)
    (by
      intro a s ih hs ht
      have has : a ∉ s := by simp at hs; exact hs.1
      have hs : Nodup s := by simp at hs; 

Proof state:
α : Type u_1
inst✝ : DecidableEq α
β : α → Type u
δ : α → Sort v
s✝ : Multiset α
t : (a : α) → Multiset (β a)
a : α
s : Multiset α
ih : Nodup s → (∀ a ∈ s, Nodup (t a)) → Nodup (pi s t)
ht : ∀ a_1 ∈ a ::ₘ s, Nodup (t a_1)
has : a ∉ s
hs : a ∉ s ∧ Nodup s
⊢ Nodup s

Next tactic:
exact hs.2
protected theorem Nodup.pi {s : Multiset α} {t : ∀ a, Multiset (β a)} :
    Nodup s → (∀ a ∈ s, Nodup (t a)) → Nodup (pi s t) :=
  Multiset.induction_on s (fun _ _ => nodup_singleton _)
    (by
      intro a s ih hs ht
      have has : a ∉ s := by simp at hs; exact hs.1
      have hs : Nodup s := by simp at hs; exact hs.2
      

Proof state:
α : Type u_1
inst✝ : DecidableEq α
β : α → Type u
δ : α → Sort v
s✝ : Multiset α
t : (a : α) → Multiset (β a)
a : α
s : Multiset α
ih : Nodup s → (∀ a ∈ s, Nodup (t a)) → Nodup (pi s t)
hs✝ : Nodup (a ::ₘ s)
ht : ∀ a_1 ∈ a ::ₘ s, Nodup (t a_1)
has : a ∉ s
hs : Nodup s
⊢ Nodup (pi (a ::ₘ s) t)

Next tactic:
simp only [pi_cons, nodup_bind]
protected theorem Nodup.pi {s : Multiset α} {t : ∀ a, Multiset (β a)} :
    Nodup s → (∀ a ∈ s, Nodup (t a)) → Nodup (pi s t) :=
  Multiset.induction_on s (fun _ _ => nodup_singleton _)
    (by
      intro a s ih hs ht
      have has : a ∉ s := by simp at hs; exact hs.1
      have hs : Nodup s := by simp at hs; exact hs.2
      simp only [pi_cons, nodup_bind]
      

Proof state:
α : Type u_1
inst✝ : DecidableEq α
β : α → Type u
δ : α → Sort v
s✝ : Multiset α
t : (a : α) → Multiset (β a)
a : α
s : Multiset α
ih : Nodup s → (∀ a ∈ s, Nodup (t a)) → Nodup (pi s t)
hs✝ : Nodup (a ::ₘ s)
ht : ∀ a_1 ∈ a ::ₘ s, Nodup (t a_1)
has : a ∉ s
hs : Nodup s
⊢ (∀ a_1 ∈ t a, Nodup (Multiset.map (Pi.cons s a a_1) (pi s t))) ∧
    Pairwise (fun a_1 b => Disjoint (Multiset.map (Pi.cons s a a_1) (pi s t)) (Multiset.map (Pi.cons s a b) (pi s t)))
      (t a)

Next tactic:
refine'
        ⟨fun b _ => ((ih hs) fun a' h' => ht a' <| mem_cons_of_mem h').map (Pi.cons_injective has),
          _⟩
protected theorem Nodup.pi {s : Multiset α} {t : ∀ a, Multiset (β a)} :
    Nodup s → (∀ a ∈ s, Nodup (t a)) → Nodup (pi s t) :=
  Multiset.induction_on s (fun _ _ => nodup_singleton _)
    (by
      intro a s ih hs ht
      have has : a ∉ s := by simp at hs; exact hs.1
      have hs : Nodup s := by simp at hs; exact hs.2
      simp only [pi_cons, nodup_bind]
      refine'
        ⟨fun b _ => ((ih hs) fun a' h' => ht a' <| mem_cons_of_mem h').map (Pi.cons_injective has),
          _⟩
      

Proof state:
α : Type u_1
inst✝ : DecidableEq α
β : α → Type u
δ : α → Sort v
s✝ : Multiset α
t : (a : α) → Multiset (β a)
a : α
s : Multiset α
ih : Nodup s → (∀ a ∈ s, Nodup (t a)) → Nodup (pi s t)
hs✝ : Nodup (a ::ₘ s)
ht : ∀ a_1 ∈ a ::ₘ s, Nodup (t a_1)
has : a ∉ s
hs : Nodup s
⊢ Pairwise (fun a_1 b => Disjoint (Multiset.map (Pi.cons s a a_1) (pi s t)) (Multiset.map (Pi.cons s a b) (pi s t)))
    (t a)

Next tactic:
refine' (ht a <| mem_cons_self _ _).pairwise _
protected theorem Nodup.pi {s : Multiset α} {t : ∀ a, Multiset (β a)} :
    Nodup s → (∀ a ∈ s, Nodup (t a)) → Nodup (pi s t) :=
  Multiset.induction_on s (fun _ _ => nodup_singleton _)
    (by
      intro a s ih hs ht
      have has : a ∉ s := by simp at hs; exact hs.1
      have hs : Nodup s := by simp at hs; exact hs.2
      simp only [pi_cons, nodup_bind]
      refine'
        ⟨fun b _ => ((ih hs) fun a' h' => ht a' <| mem_cons_of_mem h').map (Pi.cons_injective has),
          _⟩
      refine' (ht a <| mem_cons_self _ _).pairwise _
      

Proof state:
α : Type u_1
inst✝ : DecidableEq α
β : α → Type u
δ : α → Sort v
s✝ : Multiset α
t : (a : α) → Multiset (β a)
a : α
s : Multiset α
ih : Nodup s → (∀ a ∈ s, Nodup (t a)) → Nodup (pi s t)
hs✝ : Nodup (a ::ₘ s)
ht : ∀ a_1 ∈ a ::ₘ s, Nodup (t a_1)
has : a ∉ s
hs : Nodup s
⊢ ∀ a_1 ∈ t a,
    ∀ b ∈ t a, a_1 ≠ b → Disjoint (Multiset.map (Pi.cons s a a_1) (pi s t)) (Multiset.map (Pi.cons s a b) (pi s t))

Next tactic:
exact fun b₁ _ b₂ _ neb =>
        disjoint_map_map.2 fun f _ g _ eq =>
          have : Pi.cons s a b₁ f a (mem_cons_self _ _) = Pi.cons s a b₂ g a (mem_cons_self _ _) :=
            by rw [eq]
          neb <| show b₁ = b₂ by rwa [Pi.cons_same, Pi.cons_same] at this
protected theorem Nodup.pi {s : Multiset α} {t : ∀ a, Multiset (β a)} :
    Nodup s → (∀ a ∈ s, Nodup (t a)) → Nodup (pi s t) :=
  Multiset.induction_on s (fun _ _ => nodup_singleton _)
    (by
      intro a s ih hs ht
      have has : a ∉ s := by simp at hs; exact hs.1
      have hs : Nodup s := by simp at hs; exact hs.2
      simp only [pi_cons, nodup_bind]
      refine'
        ⟨fun b _ => ((ih hs) fun a' h' => ht a' <| mem_cons_of_mem h').map (Pi.cons_injective has),
          _⟩
      refine' (ht a <| mem_cons_self _ _).pairwise _
      exact fun b₁ _ b₂ _ neb =>
        disjoint_map_map.2 fun f _ g _ eq =>
          have : Pi.cons s a b₁ f a (mem_cons_self _ _) = Pi.cons s a b₂ g a (mem_cons_self _ _) :=
            by 

Proof state:
α : Type u_1
inst✝ : DecidableEq α
β : α → Type u
δ : α → Sort v
s✝ : Multiset α
t : (a : α) → Multiset (β a)
a : α
s : Multiset α
ih : Nodup s → (∀ a ∈ s, Nodup (t a)) → Nodup (pi s t)
hs✝ : Nodup (a ::ₘ s)
ht : ∀ a_1 ∈ a ::ₘ s, Nodup (t a_1)
has : a ∉ s
hs : Nodup s
b₁ : β a
x✝³ : b₁ ∈ t a
b₂ : β a
x✝² : b₂ ∈ t a
neb : b₁ ≠ b₂
f : (a : α) → a ∈ s → β a
x✝¹ : f ∈ pi s t
g : (a : α) → a ∈ s → β a
x✝ : g ∈ pi s t
eq : Pi.cons s a b₁ f = Pi.cons s a b₂ g
⊢ Pi.cons s a b₁ f a (_ : a ∈ a ::ₘ s) = Pi.cons s a b₂ g a (_ : a ∈ a ::ₘ s)

Next tactic:
rw [eq]
protected theorem Nodup.pi {s : Multiset α} {t : ∀ a, Multiset (β a)} :
    Nodup s → (∀ a ∈ s, Nodup (t a)) → Nodup (pi s t) :=
  Multiset.induction_on s (fun _ _ => nodup_singleton _)
    (by
      intro a s ih hs ht
      have has : a ∉ s := by simp at hs; exact hs.1
      have hs : Nodup s := by simp at hs; exact hs.2
      simp only [pi_cons, nodup_bind]
      refine'
        ⟨fun b _ => ((ih hs) fun a' h' => ht a' <| mem_cons_of_mem h').map (Pi.cons_injective has),
          _⟩
      refine' (ht a <| mem_cons_self _ _).pairwise _
      exact fun b₁ _ b₂ _ neb =>
        disjoint_map_map.2 fun f _ g _ eq =>
          have : Pi.cons s a b₁ f a (mem_cons_self _ _) = Pi.cons s a b₂ g a (mem_cons_self _ _) :=
            by rw [eq]
          neb <| show b₁ = b₂ by 

Proof state:
α : Type u_1
inst✝ : DecidableEq α
β : α → Type u
δ : α → Sort v
s✝ : Multiset α
t : (a : α) → Multiset (β a)
a : α
s : Multiset α
ih : Nodup s → (∀ a ∈ s, Nodup (t a)) → Nodup (pi s t)
hs✝ : Nodup (a ::ₘ s)
ht : ∀ a_1 ∈ a ::ₘ s, Nodup (t a_1)
has : a ∉ s
hs : Nodup s
b₁ : β a
x✝³ : b₁ ∈ t a
b₂ : β a
x✝² : b₂ ∈ t a
neb : b₁ ≠ b₂
f : (a : α) → a ∈ s → β a
x✝¹ : f ∈ pi s t
g : (a : α) → a ∈ s → β a
x✝ : g ∈ pi s t
eq : Pi.cons s a b₁ f = Pi.cons s a b₂ g
this : Pi.cons s a b₁ f a (_ : a ∈ a ::ₘ s) = Pi.cons s a b₂ g a (_ : a ∈ a ::ₘ s)
⊢ b₁ = b₂

Next tactic:
rwa [Pi.cons_same, Pi.cons_same] at this
theorem mem_pi (m : Multiset α) (t : ∀ a, Multiset (β a)) :
    ∀ f : ∀ a ∈ m, β a, f ∈ pi m t ↔ ∀ (a) (h : a ∈ m), f a h ∈ t a := by
  

Proof state:
α : Type u_1
inst✝ : DecidableEq α
β : α → Type u
δ : α → Sort v
m : Multiset α
t : (a : α) → Multiset (β a)
⊢ ∀ (f : (a : α) → a ∈ m → β a), f ∈ pi m t ↔ ∀ (a : α) (h : a ∈ m), f a h ∈ t a

Next tactic:
intro f
theorem mem_pi (m : Multiset α) (t : ∀ a, Multiset (β a)) :
    ∀ f : ∀ a ∈ m, β a, f ∈ pi m t ↔ ∀ (a) (h : a ∈ m), f a h ∈ t a := by
  intro f
  

Proof state:
α : Type u_1
inst✝ : DecidableEq α
β : α → Type u
δ : α → Sort v
m : Multiset α
t : (a : α) → Multiset (β a)
f : (a : α) → a ∈ m → β a
⊢ f ∈ pi m t ↔ ∀ (a : α) (h : a ∈ m), f a h ∈ t a

Next tactic:
induction' m using Multiset.induction_on with a m ih
theorem mem_pi (m : Multiset α) (t : ∀ a, Multiset (β a)) :
    ∀ f : ∀ a ∈ m, β a, f ∈ pi m t ↔ ∀ (a) (h : a ∈ m), f a h ∈ t a := by
  intro f
  induction' m using Multiset.induction_on with a m ih
  · 

Proof state:
case empty
α : Type u_1
inst✝ : DecidableEq α
β : α → Type u
δ : α → Sort v
t : (a : α) → Multiset (β a)
f : (a : α) → a ∈ 0 → β a
⊢ f ∈ pi 0 t ↔ ∀ (a : α) (h : a ∈ 0), f a h ∈ t a

Next tactic:
have : f = Pi.empty β := funext (fun _ => funext fun h => (not_mem_zero _ h).elim)