Skip to content

Commit

Permalink
KD: Case-split example
Browse files Browse the repository at this point in the history
  • Loading branch information
LeventErkok committed Sep 21, 2024
1 parent adefd88 commit dcbbe4f
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 0 deletions.
91 changes: 91 additions & 0 deletions Documentation/SBV/Examples/KnuckleDragger/CaseSplit.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
-----------------------------------------------------------------------------

Check failure on line 1 in Documentation/SBV/Examples/KnuckleDragger/CaseSplit.hs

View workflow job for this annotation

GitHub Actions / hlint

Error: Parse error: Unsupported extension: TypeAbstractions ▫︎ Found: "-----------------------------------------------------------------------------\n-- |\n-- Module : Documentation.SBV.Examples.KnuckleDragger.CaseSplit\n-- Copyright : (c) Levent Erkok\n-- License : BSD3\n-- Maintainer: [email protected]\n-- Stability : experimental\n--\n-- Use KnuckleDragger to prove @2n^2 + n + 1@ is never divisible by @3@.\n-----------------------------------------------------------------------------\n\n{-# LANGUAGE CPP #-}\n{-# LANGUAGE DataKinds #-}\n{-# LANGUAGE TypeAbstractions #-}\n\n{-# OPTIONS_GHC -Wall -Werror #-}\n\nmodule Documentation.SBV.Examples.KnuckleDragger.CaseSplit where\n\nimport Prelude hiding (sum, length)\n\nimport Data.SBV\nimport Data.SBV.Tools.KnuckleDragger\n\n-- | The default settings for z3 have trouble running this proof out-of-the-box.\n-- We have to pass auto_config=false to z3!\nz3NoAutoConfig :: KDConfig\nz3NoAutoConfig = z3KD{kdExtraSolverArgs = [\"auto_config=false\"]}\n\n-- | Prove that @2n^2 + n + 1@ is not divisible by @3@.\n--\n-- We have:\n--\n-- >>> notDiv3\n-- Chain: case_n_mod_3_eq_0\n-- Lemma: case_n_mod_3_eq_0.1 Q.E.D.\n-- Lemma: case_n_mod_3_eq_0.2 Q.E.D.\n-- Lemma: case_n_mod_3_eq_0 Q.E.D.\n-- Chain: case_n_mod_3_eq_1\n-- Lemma: case_n_mod_3_eq_1.1 Q.E.D.\n-- Lemma: case_n_mod_3_eq_1.2 Q.E.D.\n-- Lemma: case_n_mod_3_eq_1 Q.E.D.\n-- Chain: case_n_mod_3_eq_2\n-- Lemma: case_n_mod_3_eq_2.1 Q.E.D.\n-- Lemma: case_n_mod_3_eq_2.2 Q.E.D.\n-- Lemma: case_n_mod_3_eq_2 Q.E.D.\n-- Lemma: notDiv3 Q.E.D.\nnotDiv3 :: IO Proof\nnotDiv3 = runKDWith z3NoAutoConfig $ do\n\n let s n = 2 * n * n + n + 1\n p n = s n `sEMod` 3 ./= 0\n\n -- Do the proof in 3 phases; one each for the possible value of n `mod` 3 being 0, 1, and 2\n -- Note that we use the euclidian definition of division/modulus.\n\n -- Case 0: n = 0 (mod 3)\n case0 <- chainLemma \"case_n_mod_3_eq_0\"\n (\\(Forall @\"n\" n) -> (n `sEMod` 3 .== 0) .=> p n)\n (\\n -> let k = n `sEDiv` 3\n in [ n `sEMod` 3 .== 0\n , n .== 3 * k\n , s n .== s (3 * k)\n ])\n []\n\n -- Case 1: n = 1 (mod 3)\n case1 <- chainLemma \"case_n_mod_3_eq_1\"\n (\\(Forall @\"n\" n) -> (n `sEMod` 3 .== 1) .=> p n)\n (\\n -> let k = n `sEDiv` 3\n in [ n `sEMod` 3 .== 1\n , n .== 3 * k + 1\n , s n .== s (3 * k + 1)\n ])\n []\n\n -- Case 2: n = 2 (mod 3)\n case2 <- chainLemma \"case_n_mod_3_eq_2\"\n (\\(Forall @\"n\" n) -> (n `sEMod` 3 .== 2) .=> p n)\n (\\n -> let k = n `sEDiv` 3\n in [ n `sEMod` 3 .== 2\n , n .== 3 * k + 2\n , s n .== s (3 * k + 2)\n ])\n []\n\n -- Note that z3 is smart enough to figure out the above cases are complete, so\n -- no extra completeness helper is needed.\n lemma \"notDiv3\"\n (\\(Forall @\"n\" n) -> p n)\n [case0, case1, case2]\n"
-- |
-- Module : Documentation.SBV.Examples.KnuckleDragger.CaseSplit
-- Copyright : (c) Levent Erkok
-- License : BSD3
-- Maintainer: [email protected]
-- Stability : experimental
--
-- Use KnuckleDragger to prove @2n^2 + n + 1@ is never divisible by @3@.
-----------------------------------------------------------------------------

{-# LANGUAGE CPP #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeAbstractions #-}

{-# OPTIONS_GHC -Wall -Werror #-}

module Documentation.SBV.Examples.KnuckleDragger.CaseSplit where

import Prelude hiding (sum, length)

import Data.SBV
import Data.SBV.Tools.KnuckleDragger

-- | The default settings for z3 have trouble running this proof out-of-the-box.
-- We have to pass auto_config=false to z3!
z3NoAutoConfig :: KDConfig
z3NoAutoConfig = z3KD{kdExtraSolverArgs = ["auto_config=false"]}

-- | Prove that @2n^2 + n + 1@ is not divisible by @3@.
--
-- We have:
--
-- >>> notDiv3
-- Chain: case_n_mod_3_eq_0
-- Lemma: case_n_mod_3_eq_0.1 Q.E.D.
-- Lemma: case_n_mod_3_eq_0.2 Q.E.D.
-- Lemma: case_n_mod_3_eq_0 Q.E.D.
-- Chain: case_n_mod_3_eq_1
-- Lemma: case_n_mod_3_eq_1.1 Q.E.D.
-- Lemma: case_n_mod_3_eq_1.2 Q.E.D.
-- Lemma: case_n_mod_3_eq_1 Q.E.D.
-- Chain: case_n_mod_3_eq_2
-- Lemma: case_n_mod_3_eq_2.1 Q.E.D.
-- Lemma: case_n_mod_3_eq_2.2 Q.E.D.
-- Lemma: case_n_mod_3_eq_2 Q.E.D.
-- Lemma: notDiv3 Q.E.D.
notDiv3 :: IO Proof
notDiv3 = runKDWith z3NoAutoConfig $ do

let s n = 2 * n * n + n + 1
p n = s n `sEMod` 3 ./= 0

-- Do the proof in 3 phases; one each for the possible value of n `mod` 3 being 0, 1, and 2
-- Note that we use the euclidian definition of division/modulus.

-- Case 0: n = 0 (mod 3)
case0 <- chainLemma "case_n_mod_3_eq_0"
(\(Forall @"n" n) -> (n `sEMod` 3 .== 0) .=> p n)
(\n -> let k = n `sEDiv` 3
in [ n `sEMod` 3 .== 0
, n .== 3 * k
, s n .== s (3 * k)
])
[]

-- Case 1: n = 1 (mod 3)
case1 <- chainLemma "case_n_mod_3_eq_1"
(\(Forall @"n" n) -> (n `sEMod` 3 .== 1) .=> p n)
(\n -> let k = n `sEDiv` 3
in [ n `sEMod` 3 .== 1
, n .== 3 * k + 1
, s n .== s (3 * k + 1)
])
[]

-- Case 2: n = 2 (mod 3)
case2 <- chainLemma "case_n_mod_3_eq_2"
(\(Forall @"n" n) -> (n `sEMod` 3 .== 2) .=> p n)
(\n -> let k = n `sEDiv` 3
in [ n `sEMod` 3 .== 2
, n .== 3 * k + 2
, s n .== s (3 * k + 2)
])
[]

-- Note that z3 is smart enough to figure out the above cases are complete, so
-- no extra completeness helper is needed.
lemma "notDiv3"
(\(Forall @"n" n) -> p n)
[case0, case1, case2]
1 change: 1 addition & 0 deletions sbv.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ Library
, Documentation.SBV.Examples.Lists.BoundedMutex
, Documentation.SBV.Examples.Lists.CountOutAndTransfer
, Documentation.SBV.Examples.KnuckleDragger.AppendRev
, Documentation.SBV.Examples.KnuckleDragger.CaseSplit
, Documentation.SBV.Examples.KnuckleDragger.Kleene
, Documentation.SBV.Examples.KnuckleDragger.Induction
, Documentation.SBV.Examples.KnuckleDragger.ListLen
Expand Down

0 comments on commit dcbbe4f

Please sign in to comment.