content: module Main where
  import qualified Data.Matrix            as M
  import qualified Data.Vector            as V
  import           Numeric.Field.Fraction (Fraction)
  import           Test.Hspec
  import           Test.Hspec.QuickCheck
  import           Test.QuickCheck
  import           Utils
  
  main :: IO ()
  main = hspec $ do
    describe "luDecomp'" $ do
      prop "works correctly" $ prop_luDecomp
    return ()
  
  prop_luDecomp :: Property
  prop_luDecomp = forAll (resize 10 arbitrary)  $ \(MatrixCase ms) ->
        let m = M.fromLists ms :: M.Matrix (Fraction Integer)
            Just (u,l,p,q,_,_) = M.luDecomp' m
        in collect (minimum $ map (minimum . map abs) ms) $ collect (M.ncols m, M.nrows m) $
           p * m * q == l * u && isUpperTriangle u && isLowerTriangle l && M.diagProd l == 1
  
  isLowerTriangle :: (Num r, Eq r) => M.Matrix r -> Bool
  isLowerTriangle m = all (\i -> all (\j -> m M.! (i, j) == 0) [i+1..M.ncols m]) [1..M.nrows m]
  
  isUpperTriangle :: (Num r, Eq r) => M.Matrix r -> Bool
  isUpperTriangle m = all (\i -> all (\j -> m M.! (i, j) == 0) [1..min (i-1) (M.ncols m)]) [1..M.nrows m]
  
  rank :: (Eq r, Num r, Ord r, Fractional r) => M.Matrix r -> Int
  rank mat =
    let Just (u, _, _, _,_, _) = M.luDecomp' mat
    in V.foldr (\a acc -> if a /= 0 then acc + 1 else acc) (0 :: Int) $ M.getDiag u
  
  