Zulip Chat Archive

Stream: lean4

Topic: solitaire undo


Locria Cyber (Apr 17 2023 at 20:35):

I have modeled a simple solitaire logic where you can put any cards anywhere.

I want to prove that every valid action can be undone. It's trivial to understand, but is hard to prove in Lean.

Code:

inductive Suit
| A
| B
| C
| D

structure Card where
  suit: Suit
  value: Nat

abbrev Track := List Card

def List.splitAt? : (n: Nat) -> (l: List α) -> Option (List α × List α)
| 0, l => .some ([], l)
| .succ _, [] => .none
| .succ i, (x :: xs) => do
  let (splited, xs') <- splitAt? i xs
  (x :: splited, xs')

def Fin.ofNat? (x: Nat) : Option (Fin n) :=
  if isLt : x < n then
    .some <| Fin.mk x isLt
  else
    .none

structure Deck where
  tracks: Array Track

inductive Action
/-- Move `amount` cards from track to track -/
| move (from_track: Nat) (to_track: Nat) (amount: Nat)

def Action.reverse : Action -> Action
| .move from_ to_ amt => .move to_ from_ amt

namespace Deck

def do? (deck: Deck) : (action: Action) -> Option Deck
| .move from_track to_track amount => do
  let from_track <- Fin.ofNat? from_track

  let tracks := deck.tracks
  let (taken, modified_track) <- tracks[from_track].splitAt? amount
  let tracks := tracks.set from_track modified_track
  let to_track <- Fin.ofNat? to_track
  let tracks := tracks.set to_track (List.append taken tracks[to_track])
  .some { tracks := tracks }

/-- valid Action are reversible -/
theorem biject_valid :
  do? deck action = some deck' ->
  do? deck' (action.reverse) = some deck
:= by sorry -- no idea how to prove this

theorem biject (deck: Deck) (action: Action)
: match do? deck action with
  | .none => True
  | .some deck' => do? deck' action.reverse = .some deck
:=match h: do? deck action with
  | .none => True.intro
  | .some _deck' => biject_valid h

end Deck

Locria Cyber (Apr 17 2023 at 20:35):

Also, is there a way to do property testing in Lean?

Andrés Goens (Apr 17 2023 at 20:38):

Locria Cyber said:

Also, is there a way to do property testing in Lean?

have you seen LSpec/SlimCheck? https://github.com/lurk-lab/LSpec

Locria Cyber (Apr 17 2023 at 20:49):

Andrés Goens said:

Locria Cyber said:

Also, is there a way to do property testing in Lean?

have you seen LSpec/SlimCheck? https://github.com/lurk-lab/LSpec

no. thanks! I'll try it out

Locria Cyber (Apr 17 2023 at 21:21):

On match unification

For some reason, this is not type checking

abbrev biject_T (deck: Deck) (action: Action) :=
match do? deck action with
  | .none => True
  | .some deck' => do? deck' action.reverse = Option.some deck

def biject (deck: Deck) (action: Action)
: biject_T deck action
:=
  match h: do? deck action with
  | .none => True.intro
  | .some _deck' => biject_valid h

Isn't abbrev suppose to expand biject_T deck action?

The if I manually expand the expression biject_T deck action it works (see first code sample of this thread).

Sebastian Ullrich (Apr 18 2023 at 07:16):

No, abbrev does not immediately expand to its definition, it merely makes the definition always reducible (especially under typeclass search, unlike def). But the discriminant generalization of match works basically syntactically, without reduction.

Locria Cyber (Apr 18 2023 at 23:11):

Sebastian Ullrich said:

No, abbrev does not immediately expand to its definition, it merely makes the definition always reducible (especially under typeclass search, unlike def). But the discriminant generalization of match works basically syntactically, without reduction.

How do I make it expand when used as type?

Mac Malone (Apr 19 2023 at 00:04):

(edit: forget what I said; I misunderstood what you wanted)


Last updated: Dec 20 2023 at 11:08 UTC