module Numeric.LinearAlgebra.Array.Display (
formatArray, formatFixed, formatScaled, printA, dummyAt, noIdx, showBases,
) where
import Numeric.LinearAlgebra.Array.Internal
import Data.Packed
import Numeric.Container(format)
import Data.List
import Text.Printf
showBases x = f $ concatMap (shbld) x
where shbld (c,[]) = shsign c ++ showc c
shbld (c,l) = shsign c ++ g (showc c) ++ "{"++ concatMap show l++"}"
shsign c = if c < 0 then " - " else " + "
showc c
| abs (fromIntegral (round c :: Int) c) <1E-10 = show (round $ abs c::Int)
| otherwise = printf "%.3f" (abs c)
f (' ':'+':' ':rs) = rs
f (' ':'-':' ':rs) = '-':rs
f a = a
g "1" = ""
g a = a
data Rect = Rect { li :: Int, co :: Int, els :: [String] }
rect s = pad r c (Rect r 0 ss)
where ss = lines s
r = length ss
c = maximum (map length ss)
pad nr nc (Rect r c ss) = Rect (r+r') (c+c') ss'' where
r' = max 0 (nrr)
c' = max 0 (ncc)
ss' = map (padH nc) ss
ss'' = replicate r' (replicate nc '-') ++ ss'
padH l s = take (llength s) (" | "++repeat ' ') ++ s
dispH :: Int -> [Rect] -> Rect
dispH k rs = Rect nr nc nss where
nr = maximum (map li rs)
nss' = mapTail (\x-> pad nr (co x + k) x) rs
nss = foldl1' (zipWith (++)) (map els nss')
nc = length (head nss)
dispV :: Int -> [Rect] -> Rect
dispV k rs = Rect nr nc nss where
nc = maximum (map co rs)
nss' = mapTail (\x-> pad (li x + k) nc x) rs
nss = concatMap els nss'
nr = length nss
mapTail f (a:b) = a : map f b
mapTail _ x = x
formatAux f x = unlines . addds . els . fmt ms $ x where
fmt [] _ = undefined
fmt (g:gs) t
| order t == 0 = rect (f (coords t @> 0))
| order t == 1 = rect $ unwords $ map f (toList $ coords t)
| order t == 2 = decor t $ rect $ w1 $ format " " f (reshape (iDim $ last $ dims t) (coords t))
| otherwise = decor t (g ps)
where ps = map (fmt gs ) (partsRaw t (head (namesR t)))
ds = showNice (filter ((/='*').head.iName) $ dims x)
addds = if null ds then (showRawDims (dims x) :) else (ds:)
w1 = unlines . map (' ':) . lines
ms = cycle [dispV 1, dispH 2]
decor t | odd (order t) = id
| otherwise = decorLeft (namesR t!!0) . decorUp (namesR t!!1)
showNice x = unwords . intersperse "x" . map show $ x
showRawDims = showNice . map iDim . filter ((/="*").iName)
formatArray :: (Coord t, Compat i)
=> (t -> String)
-> NArray i t
-> String
formatArray f t | odd (order t) = formatAux f (dummyAt 0 t)
| otherwise = formatAux f t
decorUp s rec
| head s == '*' = rec
| otherwise = dispV 0 [rs,rec]
where
c = co rec
c1 = (c length s) `div` 2
c2 = c length s c1
rs = rect $ replicate c1 ' ' ++ s ++ replicate c2 ' '
decorLeft s rec
| head s == '*' = rec
| otherwise = dispH 0 [rs,rec]
where
c = li rec
r1 = (c length s+1) `div` 2
r2 = c length s r1
rs = rect $ unlines $ replicate r1 spc ++ s : replicate (r2) spc
spc = replicate (length s) ' '
printA :: (Coord t, Compat i, PrintfArg t) => String -> NArray i t -> IO ()
printA f t = putStrLn (formatArray (printf f) t)
formatScaled :: (Compat i)
=> Int
-> NArray i Double
-> String
formatScaled dec t = unlines (('(':d++") E"++show o) : m)
where ss = formatArray (printf fmt. g) t
d:m = lines ss
g x | o >= 0 = x/10^(o::Int)
| otherwise = x*10^(o)
o = floor $ maximum $ map (logBase 10 . abs) $ toList $ coords t
fmt = '%':show (dec+3) ++ '.':show dec ++"f"
formatFixed :: (Compat i)
=> Int
-> NArray i Double
-> String
formatFixed dec t
| isInt t = formatArray (printf ('%': show (width t) ++".0f")) t
| otherwise = formatArray (printf ('%': show (width t+dec+1) ++"."++show dec ++"f")) t
isInt = all lookslikeInt . toList . coords
lookslikeInt x = show (round x :: Int) ++".0" == shx || "-0.0" == shx
where shx = show x
width = maximum . map (length . (printf "%.0f"::Double->String)) . toList . coords
dummyAt :: Coord t => Int -> NArray i t -> NArray i t
dummyAt k t = mkNArray d' (coords t) where
(d1,d2) = splitAt k (dims t)
d' = d1 ++ d : d2
d = Idx (iType (head (dims t))) 1 "*"
noIdx :: Compat i => NArray i t -> NArray i t
noIdx t = renameSuperRaw t (map ('*':) (namesR t))