Zulip Chat Archive

Stream: new members

Topic: Synthesize placeholder error after finishing proof on have


Johannes Tantow (Apr 17 2024 at 13:11):

Hi,

I have a problem with a theorem where I am quite sure that it should work but as soon as I finish the last goal suddenly I get a lot "don't know how to synthesize placeholder" errors in my have and by_cases tactics. This is not what I would expect and I do not find any question marks or underscores in the context or goal. Are there any other signs I need to look out for. I don't think I could write it in a simple way without these tactics . In the induction base I can have a have-statement without leading to the error.

My proof and statement is unfortunately rather long and I did not manage to find a shorter example. I thought it might be connected with Fin, but I also get it when trying to show true=true. I have tested it also in the browser and the error persists. It might be a longshot but does anyone have an idea what is behind that ?

import Std.Data.HashMap
import Std.Data.AssocList
import Std.Classes.BEq
import Mathlib.Data.List.Defs
import Mathlib.Data.Finset.Basic
import Mathlib.Data.Bool.AllAny

namespace Std

lemma foldl_reinsertAux {A:Type} [Hashable A] [DecidableEq A] {B: Type} [DecidableEq B] (source:(AssocList A B)) (target: HashMap.Imp.Buckets A B) (ab: A × B): ( (bkt: AssocList A B), bkt  (List.foldl (fun d x => HashMap.Imp.reinsertAux d x.1 x.2) target (AssocList.toList source)).1  ab  bkt.toList )  ( (bkt: AssocList A B),  bkt  target.1  ab  bkt.toList)  ab  source.toList := by sorry

lemma HashMap.Imp.expand_go_mem {A:Type} [Hashable A] [DecidableEq A] {B: Type} [DecidableEq B]
(i : Nat) (source : Array (AssocList A B)) (target : Buckets A B) (ab: A × B):
 ( (bkt: AssocList A B), bkt  (HashMap.Imp.expand.go i source target).1  ab  bkt.toList) 
 (bkt: AssocList A B), (bkt  target.1 
 (j: Fin source.size), j.val  i  bkt = source[j])  ab  bkt.toList := by
  induction' h:(source.size - i)  with n ih generalizing source i target

  rw [Nat.sub_eq_zero_iff_le] at h
  unfold expand.go
  have if_cond: ¬ i < Array.size source := by
    apply Nat.not_lt_of_le
    apply h
  simp [if_cond]

  constructor
  intro g
  rcases g with bkt, bkt_mem, ab_mem
  use bkt
  constructor
  left
  apply bkt_mem
  apply ab_mem

  intro g
  rcases g with bkt, g, ab_mem
  cases g with
  | inl g =>
    use bkt
  | inr g =>
    rcases g with j, i_le_j, _
    have lt_self: Array.size source < Array.size source := by
      apply Nat.lt_of_le_of_lt (m:=j.val)
      apply Nat.le_trans
      apply h
      apply i_le_j
      apply j.isLt
    simp at lt_self

  --step
  have t: true = true := by
    rfl

  unfold expand.go
  have h_i: i < source.size := by
    apply Nat.lt_of_sub_eq_succ h
  simp [h_i]
  specialize ih (i+1) (source.set (Fin.mk i h_i) AssocList.nil) (List.foldl (fun d x => reinsertAux d x.1 x.2) target (AssocList.toList source[i]))
  simp at ih
  have h': Array.size source - (i + 1) = n := by
    rw [ Nat.succ_eq_add_one, Nat.sub_succ, h]
    simp
  specialize ih h'
  rw [ih]

  simp_rw [or_and_right, exists_or]
  constructor
  intro g
  cases g with
  | inl g =>
    rw [foldl_reinsertAux] at g
    cases g with
    | inl g =>
      left
      apply g
    | inr g =>
      right
      use source.get (Fin.mk i h_i)
      constructor
      use (Fin.mk i h_i)
      simp
      apply g
  | inr g =>
    rcases g with bkt,g,ab_mem
    right
    use bkt
    rcases g with j, j_i, bkt_set
    constructor
    rw [Array.get_set] at bkt_set
    simp at bkt_set
    have j_isLt: j.val < Array.size source := by
      have h: j.val < Array.size (Array.set source {val:=i, isLt := h_i} AssocList.nil) := by
        apply j.isLt
      simp at h
      exact h
    use Fin.mk j j_isLt
    simp
    constructor
    apply Nat.le_trans (m:= i+1)
    simp
    apply j_i
    rw [bkt_set]
    split
    rename_i i_j
    rw [ i_j] at j_i
    rw [ Nat.succ_eq_add_one, Nat.succ_le] at j_i
    simp at j_i

    simp
    apply ab_mem

  intro g
  rw [foldl_reinsertAux]
  cases g with
  | inl g =>
    left
    left
    apply g
  | inr g =>
    rcases g with bkt, g, ab_mem
    rcases g with j,i_j, bkt_j
    by_cases j_i: i = j.val
    left
    right
    have source_eq: source[i] = source[j.val] := by
      congr
    rw [source_eq,  bkt_j]
    apply ab_mem

    right
    use bkt
    have h_k:  (k: Fin (Array.size (Array.set source { val := i, isLt := h_i } AssocList.nil))), k.val = j.val := by
      have k': j.val < (Array.size (Array.set source { val := i, isLt := h_i } AssocList.nil)) := by
        rw [Array.size_set]
        apply j.isLt
      use Fin.mk j.val k'
    rcases h_k with k, k_j
    constructor
    use k
    constructor
    rw [k_j,  Nat.succ_eq_add_one, Nat.succ_le_iff]
    apply Nat.lt_of_le_of_ne
    apply i_j
    apply j_i
    rw [Array.get_set]
    simp
    split
    rename_i i_k
    rw [i_k] at j_i
    contradiction

    rw [bkt_j]
    congr
    exact ab_mem

Ruben Van de Velde (Apr 17 2024 at 13:35):

This is a little shorter; the issue seems to be that congr gets confused because the goal includes the other side goal

import Std.Data.HashMap
import Std.Data.AssocList
import Std.Classes.BEq
import Mathlib.Data.List.Defs
import Mathlib.Data.Finset.Basic
import Mathlib.Data.Bool.AllAny

namespace Std

lemma foldl_reinsertAux {A:Type} [Hashable A] [DecidableEq A] {B: Type} [DecidableEq B] (source:(AssocList A B)) (target: HashMap.Imp.Buckets A B) (ab: A × B): ( (bkt: AssocList A B), bkt  (List.foldl (fun d x => HashMap.Imp.reinsertAux d x.1 x.2) target (AssocList.toList source)).1  ab  bkt.toList )  ( (bkt: AssocList A B),  bkt  target.1  ab  bkt.toList)  ab  source.toList := by sorry

lemma HashMap.Imp.expand_go_mem {A:Type} [Hashable A] [DecidableEq A] {B: Type} [DecidableEq B]
    (i : Nat) (source : Array (AssocList A B)) (target : Buckets A B) (ab: A × B):
    ( (bkt: AssocList A B), bkt  (HashMap.Imp.expand.go i source target).1  ab  bkt.toList) 
     (bkt: AssocList A B), (bkt  target.1 
     (j: Fin source.size), j.val  i  bkt = source[j])  ab  bkt.toList := by
  induction' h:(source.size - i)  with n ih generalizing source i target
  · sorry
  unfold expand.go
  have h_i: i < source.size := sorry
  simp only [h_i, reduceDite, Array.get_eq_getElem, AssocList.foldl_eq, ge_iff_le, getElem_fin]
  specialize ih (i+1) (source.set (Fin.mk i h_i) AssocList.nil) (List.foldl (fun d x => reinsertAux d x.1 x.2) target (AssocList.toList source[i]))
  simp only [Array.size_set, ge_iff_le, getElem_fin] at ih
  specialize ih sorry
  rw [ih]

  simp_rw [or_and_right, exists_or]
  constructor
  · sorry
  intro g
  rw [foldl_reinsertAux]
  cases g with
  | inl g =>
    sorry
  | inr g =>
    rcases g with bkt, g, ab_mem
    rcases g with j,i_j, bkt_j
    right
    use bkt
    have h_k:  (k: Fin (Array.size (Array.set source { val := i, isLt := h_i } AssocList.nil))), k.val = j.val := sorry
    rcases h_k with k, k_j
    constructor
    · use k
      constructor
      · sorry
      rw [Array.get_set]
      · simp only
        split
        · sorry
        · rw [bkt_j]
          congr
    · sorry

This works:

        · rw [bkt_j]
          swap; sorry
          congr
          sorry
          sorry

Would be good if someone could create a mathlib-free example

Johannes Tantow (Apr 17 2024 at 13:45):

Ok, I do not understand why but after replacing the congr in a no longer get an error in the backwards direction of the induction step. The previous errors remain.

Johannes Tantow (Apr 17 2024 at 14:27):

So this is the current look. I added everything back to the back direction and removed the congr. In the front direction the errors remain. I have purged the congr tactic completely. Do you have another suspect ? I have also minimized the mathlib imports, but to do it completely without it seems difficult. I would need to reprove the results about nats and introduce the induction tactic and use tactic again. Is that important ?

import Std.Data.HashMap
import Std.Data.AssocList
import Std.Classes.BEq
import Mathlib.Data.Nat.Defs
import Mathlib.Order.Lattice


namespace Std

lemma foldl_reinsertAux {A:Type} [Hashable A] [DecidableEq A] {B: Type} [DecidableEq B] (source:(AssocList A B)) (target: HashMap.Imp.Buckets A B) (ab: A × B): ( (bkt: AssocList A B), bkt  (List.foldl (fun d x => HashMap.Imp.reinsertAux d x.1 x.2) target (AssocList.toList source)).1  ab  bkt.toList )  ( (bkt: AssocList A B),  bkt  target.1  ab  bkt.toList)  ab  source.toList := by sorry

lemma HashMap.Imp.expand_go_mem {A:Type} [Hashable A] [DecidableEq A] {B: Type} [DecidableEq B](i : Nat) (source : Array (AssocList A B)) (target : Buckets A B) (ab: A × B): ( (bkt: AssocList A B), bkt  (HashMap.Imp.expand.go i source target).1  ab  bkt.toList)   (bkt: AssocList A B), (bkt  target.1   (j: Fin source.size), j.val  i  bkt = source[j])  ab  bkt.toList := by
  induction' h:(source.size - i)  with n ih generalizing source i target

  rw [Nat.sub_eq_zero_iff_le] at h
  unfold expand.go
  have if_cond: ¬ i < Array.size source := by
    apply Nat.not_lt_of_le
    apply h
  simp [if_cond]

  constructor
  intro g
  rcases g with bkt, bkt_mem, ab_mem
  use bkt
  constructor
  left
  apply bkt_mem
  apply ab_mem

  intro g
  rcases g with bkt, g, ab_mem
  cases g with
  | inl g =>
    use bkt
  | inr g =>
    rcases g with j, i_le_j, _
    have lt_self: Array.size source < Array.size source := by
      apply Nat.lt_of_le_of_lt (m:=j.val)
      apply Nat.le_trans
      apply h
      apply i_le_j
      apply j.isLt
    simp at lt_self

  --step
  unfold expand.go
  have h_i: i < source.size := by
    apply Nat.lt_of_sub_eq_succ h
  simp [h_i]
  specialize ih (i+1) (source.set (Fin.mk i h_i) AssocList.nil) (List.foldl (fun d x => reinsertAux d x.1 x.2) target (AssocList.toList source[i]))
  simp at ih
  have h': Array.size source - (i + 1) = n := by
    rw [ Nat.succ_eq_add_one, Nat.sub_succ, h]
    simp
  specialize ih h'
  rw [ih]

  simp_rw [or_and_right, exists_or]
  constructor
  intro g
  cases g with
  | inl g =>
    rw [foldl_reinsertAux] at g
    cases g with
    | inl g =>
      left
      apply g
    | inr g =>
      right
      use source.get (Fin.mk i h_i)
      constructor
      use (Fin.mk i h_i)
      simp
      apply g
  | inr g =>
    rcases g with bkt,g,ab_mem
    right
    use bkt
    rcases g with j, j_i, bkt_set
    constructor
    rw [Array.get_set] at bkt_set
    simp at bkt_set
    have j_isLt: j.val < Array.size source := by
      have h: j.val < Array.size (Array.set source {val:=i, isLt := h_i} AssocList.nil) := by
        apply j.isLt
      simp at h
      exact h
    use Fin.mk j j_isLt
    simp
    constructor
    apply Nat.le_trans (m:= i+1)
    simp
    apply j_i
    rw [bkt_set]
    split
    rename_i i_j
    rw [ i_j] at j_i
    rw [ Nat.succ_eq_add_one, Nat.succ_le_iff] at j_i
    simp at j_i
    simp
    apply ab_mem

  intro g
  rw [foldl_reinsertAux]
  cases g with
  | inl g =>
    left
    left
    apply g
  | inr g =>
    rcases g with bkt, g, ab_mem
    rcases g with j,i_j, bkt_j
    by_cases j_i: i = j.val
    left
    right
    have source_eq: source[i] = source[j.val] := by
      simp_rw [j_i]
    rw [source_eq,  bkt_j]
    apply ab_mem

    right
    use bkt
    have h_k:  (k: Fin (Array.size (Array.set source { val := i, isLt := h_i } AssocList.nil))), k.val = j.val := by
      have k': j.val < (Array.size (Array.set source { val := i, isLt := h_i } AssocList.nil)) := by
        rw [Array.size_set]
        apply j.isLt
      use Fin.mk j.val k'
    rcases h_k with k, k_j
    · constructor
      use k
      constructor
      · rw [k_j,  Nat.succ_eq_add_one, Nat.succ_le_iff]
        apply Nat.lt_of_le_of_ne
        apply i_j
        exact j_i
      rw [Array.get_set]
      simp
      split
      · rename_i i_k
        rw [i_k] at j_i
        contradiction

      · rw [bkt_j]
        simp_rw [k_j]
        have h': source.size = Array.size (Array.set source { val := i, isLt := h_i } AssocList.nil) := by
          simp
        simp_rw [h']
        exact k.isLt
      exact ab_mem

Johannes Tantow (Apr 17 2024 at 15:15):

I reordered the forward direction a bit and added another lemma to simplify the proof and now it works. Thank you for your help.


Last updated: May 02 2025 at 03:31 UTC