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

Fix termination crash due to empty permutation #3081

Merged
merged 2 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -131,37 +131,48 @@ recursiveBehaviour re =
(re ^. reflexiveEdgeFun)
(map callMatrixDiag (toList $ re ^. reflexiveEdgeMatrices))

type SparseMatrix = [[Indexed SizeRel]]

findOrder :: RecursiveBehaviour -> Maybe LexOrder
findOrder rb = LexOrder <$> listToMaybe (mapMaybe (isLexOrder >=> nonEmpty) allPerms)
where
b0 :: [[SizeRel]]
b0 = rb ^. recursiveBehaviourMatrix

indexed = map (zip [0 :: Int ..] . take minLength) b0
indexed = map (indexFrom 0 . take minLength) b0
where
minLength = minimum (map length b0)

startB :: SparseMatrix
startB = removeUselessColumns indexed

-- removes columns that don't have at least one ≺ in them
removeUselessColumns :: [[(Int, SizeRel)]] -> [[(Int, SizeRel)]]
removeUselessColumns = transpose . filter (any (isLess . snd)) . transpose
-- removes columns that don't have at least one ≺ in them because we know
-- they'll never contribute to finding a decreasing lex order
removeUselessColumns :: SparseMatrix -> SparseMatrix
removeUselessColumns = transpose . filter (any (isLess . getRel)) . transpose

getIx :: Indexed SizeRel -> Int
getIx = (^. indexedIx)

getRel :: Indexed SizeRel -> SizeRel
getRel = (^. indexedThing)

isLexOrder :: [Int] -> Maybe [Int]
isLexOrder = go startB
where
go :: [[(Int, SizeRel)]] -> [Int] -> Maybe [Int]
go :: SparseMatrix -> [Int] -> Maybe [Int]
go [] _ = Just []
go b perm = case perm of
[] -> error "The permutation should have one element at least!"
(p0 : ptail)
| Just r <- find (isLess . snd . (!! p0)) b,
all (notNothing . snd . (!! p0)) b,
[] -> Nothing
p0 : ptail
| Just r <- find (isLess . getRel . (!! p0)) b,
all (notNothing . getRel . (!! p0)) b,
Just perm' <- go (b' p0) (map pred ptail) ->
Just (fst (r !! p0) : perm')
Just (getIx (r !! p0) : perm')
| otherwise -> Nothing
where
b' i = map r' (filter (not . isLess . snd . (!! i)) b)
b' :: Int -> SparseMatrix
b' i = map r' (filter (not . isLess . getRel . (!! i)) b)
where
r' r = case splitAt i r of
(x, y) -> x ++ drop 1 y
Expand Down
6 changes: 5 additions & 1 deletion test/Typecheck/Positive.hs
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,11 @@ tests =
posTest
"Default argument with trait in signature"
$(mkRelDir ".")
$(mkRelFile "issue2994.juvix")
$(mkRelFile "issue2994.juvix"),
posTest
"Termination crash because of empty permutation"
$(mkRelDir ".")
$(mkRelFile "issue3064.juvix")
]
<> [ compilationTest t | t <- Compilation.tests
]
35 changes: 35 additions & 0 deletions tests/positive/issue3064.juvix
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
module issue3064;

import Stdlib.Prelude open;

type Expression :=
-- Put both of these into a Const type
| Const Nat
| Str String
| Var String
| Lam String Expression
| App Expression Expression;

axiom undefined : {A : Type} -> A;

Environment : Type := List (Pair String Expression) ;

type Return :=
| RNatural Nat
| RString String;

terminating eval (env : Environment) : Expression -> Maybe Return
| (Const x) := RNatural x |> just
| (Str str) := RString str |> just
| (App f x) := eval-lookup env f x
| (Var var) := lookup-var env var >>= eval env
| _ := undefined;

eval-lookup (env : Environment) (f : Expression) (x : Expression) : Maybe Return :=
let recursive : _ -- Expression -> Return
| (Lam variable body) := eval ((variable , x) :: env) body
| _ := undefined;
in recursive f;

lookup-var (env : Environment) (to-lookup : String) : Maybe Expression
:= (snd <$> find \{ x := fst x == to-lookup } env);
Loading