Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable choice of term ordering for REST #1930

Open
wants to merge 13 commits into
base: develop
Choose a base branch
from
25 changes: 25 additions & 0 deletions docs/mkDocs/docs/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -446,3 +446,28 @@ verification attempts.

It is also possible to generate *slide shows* from the above.
See the [slides directory](https://github.com/ucsd-progsys/liquidhaskell/tree/develop/docs/slides) for an example.

## Rewrite Rules

Liquid Haskell provdes experimental support for automatic axiom instantiation
zgrannan marked this conversation as resolved.
Show resolved Hide resolved
via rewriting. Usage examples are contained in the `Rewrite` tests
[here](https://github.com/ucsd-progsys/liquidhaskell/tree/develop/tests/pos).

Termination checking for rewriting can be enabled with the argument
`--rw-termination-check`. Enabling this setting uses REST to ensure termination,
REST is described [in this
paper](https://s3.us-west-1.wasabisys.com/zg-public/paper.pdf).

The ordering constraint algebra used by REST can be adjusted by setting the
`--rest-ordering` flag. Available options are:

- `rpo`: Recursive Path Ordering (default)
- `kbo`: Knuth-Bendix Ordering
- `lpo`: Lexicographic Path Ordering
- `fuelN`: Only apply `N` consecutive rewriting steps in a row (i.e `fuel5`, `fuel10`, etc).

The default ordering (`rpo`) is expected to work well for most use cases.
Understanding when other rewrite orderings are preferable requires a bit of
knowledge about termination orders for rewriting; [this survey
paper](https://www.cs.tau.ac.il/~nachumd/papers/termination.pdf) may provide a
good starting place.
1 change: 1 addition & 0 deletions src/Language/Haskell/Liquid/Constraint/ToFixpoint.hs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ fixConfig tgt cfg = def
, FC.fuel = fuel cfg
, FC.noEnvironmentReduction = not (environmentReduction cfg)
, FC.inlineANFBindings = inlineANFBindings cfg
, FC.restOrdering = restOrdering cfg
}

cgInfoFInfo :: TargetInfo -> CGInfo -> IO (F.FInfo Cinfo)
Expand Down
11 changes: 10 additions & 1 deletion src/Language/Haskell/Liquid/UX/CmdLine.hs
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,15 @@ config = cmdArgsMode $ Config {
, "Sometimes improves performance and sometimes worsens it."
, "Disabled by --no-environment-reduction"
])
, pandocHtml
, restOrdering
= "rpo"
&= name "rest-ordering"
&= help (unwords
[ "Ordering Constraints Algebra to use for REST."
, "Available options are rpo|kbo|lpo|fuelN (where N is some positive integer)."
, "rpo is the default option"
])
, pandocHtml
= False
&= name "pandoc-html"
&= help "Use pandoc to generate html."
Expand Down Expand Up @@ -720,6 +728,7 @@ defConfig = Config
, environmentReduction = False
, noEnvironmentReduction = False
, inlineANFBindings = False
, restOrdering = "rpo"
, pandocHtml = False
}

Expand Down
1 change: 1 addition & 0 deletions src/Language/Haskell/Liquid/UX/Config.hs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ data Config = Config
, noEnvironmentReduction :: Bool -- ^ Don't perform environment reduction
, inlineANFBindings :: Bool -- ^ Inline ANF bindings.
-- Sometimes improves performance and sometimes worsens it.
, restOrdering :: String -- ^ The ordering to use for REST
, pandocHtml :: Bool -- ^ Use pandoc to generate html
} deriving (Generic, Data, Typeable, Show, Eq)

Expand Down
4 changes: 2 additions & 2 deletions stack.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ packages:
- .
extra-deps:
- hashable-1.3.0.0
- git: https://github.com/facundominguez/rest
commit: 31e974979c90e910efe5199ee0d3721b791667f6
- git: https://github.com/zgrannan/rest
commit: 2833a743c310747eee1accba2a5bf0b5338e7bb6

resolver: lts-18.14
compiler: ghc-8.10.7
Expand Down
14 changes: 7 additions & 7 deletions stack.yaml.lock
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ packages:
hackage: hashable-1.3.0.0
- completed:
name: rest-rewrite
version: 0.2.0
git: https://github.com/facundominguez/rest
version: 0.2.1
git: https://github.com/zgrannan/rest
pantry-tree:
size: 4013
sha256: 2a91674ccab6b0bd43dcc41fa5e2cb60cbfd35ad585df8293c2884466091d0c0
commit: 31e974979c90e910efe5199ee0d3721b791667f6
size: 4368
sha256: 725fad92ed6299d02fb26aec13b6dd383be111f09377532363277228d2c28658
commit: 2833a743c310747eee1accba2a5bf0b5338e7bb6
original:
git: https://github.com/facundominguez/rest
commit: 31e974979c90e910efe5199ee0d3721b791667f6
git: https://github.com/zgrannan/rest
commit: 2833a743c310747eee1accba2a5bf0b5338e7bb6
snapshots:
- completed:
size: 586069
Expand Down
75 changes: 75 additions & 0 deletions tests/pos/RewriteKBO.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
module RewriteKBO where

{-@ LIQUID "--ple" @-}
{-@ LIQUID "--reflection" @-}
{-@ LIQUID "--fast" @-}
{-@ LIQUID "--rw-termination-check" @-}
{-@ LIQUID "--rest-ordering=kbo" @-}

import Language.Haskell.Liquid.ProofCombinators

data Set = Empty | Tree Int Set Set

{-@ infix \/ @-}
{-@ measure \/ :: Set -> Set -> Set @-}
{-@ assume \/ :: a : Set -> b : Set -> { v : Set | v = a \/ b } @-}
(\/) :: Set -> Set -> Set
a \/ b = undefined


{-@ infix /\ @-}
{-@ measure /\ :: Set -> Set -> Set @-}
{-@ assume /\ :: a : Set -> b : Set -> { v : Set | v = a /\ b } @-}
(/\) :: Set -> Set -> Set
a /\ b = undefined

{-@ measure emptySet :: Set @-}
{-@ assume emptySet :: {v : Set | v = emptySet} @-}
emptySet :: Set
emptySet = undefined

{-@ predicate IsSubset M1 M2 = M1 \/ M2 = M2 @-}
{-@ predicate IsDisjoint M1 M2 = M1 /\ M2 = emptySet @-}

{-@ rewrite unionIntersect @-}
{-@ assume unionIntersect :: s0 : Set -> s1 : Set -> s2 : Set -> { (s0 \/ s1) /\ s2 = (s0 /\ s2) \/ (s1 /\ s2) } @-}
unionIntersect :: Set -> Set -> Set -> Proof
unionIntersect _ _ _ = ()

{-@ rewrite intersectSelf @-}
{-@ assume intersectSelf :: s0 : Set -> { s0 /\ s0 = s0 } @-}
intersectSelf :: Set -> Proof
intersectSelf _ = ()

{-@ rewrite unionIdemp @-}
{-@ assume unionIdemp :: ma : Set -> {v : () | IsSubset ma ma } @-}
unionIdemp :: Set -> Proof
unionIdemp _ = ()

{-@ rewrite unionAssoc @-}
{-@ assume unionAssoc :: ma : Set -> mb : Set -> mc : Set -> {v : () | (ma \/ mb) \/ mc = ma \/ (mb \/ mc) } @-}
unionAssoc :: Set -> Set -> Set -> Proof
unionAssoc _ _ _ = ()

{-@ rewrite unionComm @-}
{-@ assume unionComm :: ma : Set -> mb : Set -> {v : () | ma \/ mb = mb \/ ma } @-}
unionComm :: Set -> Set -> Proof
unionComm _ _ = ()

{-@ rewrite intersectComm @-}
{-@ assume intersectComm :: ma : Set -> mb : Set -> {v : () | ma /\ mb = mb /\ ma } @-}
intersectComm :: Set -> Set -> Proof
intersectComm _ _ = ()

{-@ rewrite unionEmpty @-}
{-@ assume unionEmpty :: ma : Set -> {v : () | ma \/ emptySet = ma } @-}
unionEmpty :: Set -> Proof
unionEmpty _ = ()

{-======================================================
Proofs
=======================================================-}

{-@ unionMono :: s : Set -> s2 : Set -> {s1 : Set | IsSubset s1 s2 } -> { IsSubset (s \/ s1) (s \/ s2)} @-}
unionMono :: Set -> Set -> Set -> Proof
unionMono s s2 s1 = ()