Zulip Chat Archive

Stream: new members

Topic: Propagate proof state in match?


Daniel Fabian (Aug 24 2019 at 11:26):

As an exercise, I'm working on an red-black-tree. And I'm trying to show, that the re-balancing doesn't change the interpretation as a set.

universes u
variables α : Type u

inductive color
| red
| black

inductive node (α)
| leaf {} : node
| tree {} (color : color) (left : node) (val : α) (right : node) : node

def to_set {α} : node α → set α
| node.leaf := ∅
| (node.tree _ l y r) := to_set l ∪ {y} ∪ to_set r

instance node_to_set_coe : has_coe (node α) (set α) := ⟨to_set⟩

def balance {α} : color → node α → α → node α → node α
| color.black (node.tree color.red (node.tree color.red a x b) y c) z d :=
    node.tree color.red (node.tree color.black a x b) y (node.tree color.black c z d)
| color.black (node.tree color.red a x (node.tree color.red b y c)) z d :=
    node.tree color.red (node.tree color.black a x b) y (node.tree color.black c z d)
| color.black a x (node.tree color.red (node.tree color.red b y c) z d) :=
    node.tree color.red (node.tree color.black a x b) y (node.tree color.black c z d)
| color.black a x (node.tree color.red b y (node.tree color.red c z d)) :=
    node.tree color.red (node.tree color.black a x b) y (node.tree color.black c z d)
| color a x b := node.tree color a x b

lemma balance_mem {α} :
∀ c l (v : α) r, (node.tree c l v r : set α) = (balance c l v r : set α) :=
begin
    intros,
    from match c, l, v, r with
    | color.black, node.tree color.red (node.tree color.red a x b) y c, z, d :=
        begin
            unfold balance,
            sorry
        end
    | color.black, node.tree color.red a x (node.tree color.red b y c), z, d := begin sorry end
    | color.black, a, x, node.tree color.red (node.tree color.red b y c) z d := begin sorry end
    | color.black, a, x, node.tree color.red b y (node.tree color.red c z d) := begin sorry end
    | _, _, _, _ := begin sorry end
    end
end

Initially, I was thinking to just do it using cases by each variable, but it turns into 100s of cases and doesn't scale at all. What I really want to do is pattern match exactly the right cases and then unfold the definition of balance.

I'm a bit confused here. The goal inside the begin looks right, it wants me to prove

⊢ ↑(node.tree color.black (node.tree color.red (node.tree color.red a x b) y c) z d) =
    ↑(balance color.black (node.tree color.red (node.tree color.red a x b) y c) z d)

so balance should be happy to unfold into:

node.tree color.red (node.tree color.black a x b) y (node.tree color.black c z d)

However the tactic fails, any idea what I'm doing wrong?

Mario Carneiro (Aug 24 2019 at 12:12):

Use #print prefix balance and look for the _eqn_* theorems to see the actual equations lean will rewrite with

Mario Carneiro (Aug 24 2019 at 12:13):

Most likely, lean has done an additional case split on one of the other variables, and you will have to do that same split in the proof of properties of it

Mario Carneiro (Aug 24 2019 at 12:15):

looks like lean did quite a lot of case splitting - there are 122 equations for the definition

Mario Carneiro (Aug 24 2019 at 12:16):

I suggest rewriting balance with explicit cases applications so that you don't get so many superfluous splits

Mario Carneiro (Aug 24 2019 at 12:16):

Or make an intermediate definition or two

Daniel Fabian (Aug 24 2019 at 13:48):

oh wow, that's a lot of equations. I'll look into reducing the number of them by the strategy suggested.

Daniel Fabian (Aug 24 2019 at 14:01):

this is interesting: when I change the definition of balance to one w.r.t. to match, it's much happier. Consider these two (I believe) equivalent formulations

def balance {α} : color → node α → α → node α → node α
:=
begin
    intros c l v r,
    from match c, l, v, r with
    | color.black, node.tree color.red (node.tree color.red a x b) y c, z, d :=
        node.tree color.red (node.tree color.black a x b) y (node.tree color.black c z d)
    | color.black, node.tree color.red a x (node.tree color.red b y c), z, d :=
        node.tree color.red (node.tree color.black a x b) y (node.tree color.black c z d)
    | color.black, a, x, node.tree color.red (node.tree color.red b y c) z d :=
        node.tree color.red (node.tree color.black a x b) y (node.tree color.black c z d)
    | color.black, a, x, node.tree color.red b y (node.tree color.red c z d) :=
        node.tree color.red (node.tree color.black a x b) y (node.tree color.black c z d)
    | color, a, x, b := node.tree color a x b
    end
end
-- | color.black (node.tree color.red (node.tree color.red a x b) y c) z d :=
--     node.tree color.red (node.tree color.black a x b) y (node.tree color.black c z d)
-- | color.black (node.tree color.red a x (node.tree color.red b y c)) z d :=
--     node.tree color.red (node.tree color.black a x b) y (node.tree color.black c z d)
-- | color.black a x (node.tree color.red (node.tree color.red b y c) z d) :=
--     node.tree color.red (node.tree color.black a x b) y (node.tree color.black c z d)
-- | color.black a x (node.tree color.red b y (node.tree color.red c z d)) :=
--     node.tree color.red (node.tree color.black a x b) y (node.tree color.black c z d)
-- | color a x b := node.tree color a x b

the first one works fine and the second one has the problem. Is this some kind of subtlety of the equation compiler here?

Daniel Fabian (Aug 24 2019 at 14:14):

upon further investigation, the second version has about twice as many equations as the first one...


Last updated: Dec 20 2023 at 11:08 UTC