packages feed

repa-examples-1.0.0.0: lib/Vector.hs

-- | Reading and writing vectors as ASCII files.
--	We use ASCII so we can generate and check simple test data by hand,
--	and we don't want to fool around with byte order issues.
--
--   Vector file format is like:
--
--	VECTOR			-- header
--	100			-- length of vector
--	1.23 1.56 1.23 ...	-- data, separated by whitespace
--	....
--
--
module Vector
	( readVectorFromTextFile
	, writeVectorAsTextFile
	, genRandomVector

	, readValues
	, hWriteValues
	, genRandomUArray)
where
import Data.List				as L
import Data.Array.Repa				as A
import qualified Data.Array.Parallel.Unlifted	as U
import Prelude					as P
import System.IO
import Control.Monad
import Data.Char
import System.Random


-- | Read a vector from a text file.
readVectorFromTextFile
	:: (U.Elt a, Num a, Read a)
	=> FilePath			-- ^ File name of vector file.
	-> IO (Array DIM1 a)	

readVectorFromTextFile fileName
 = do	handle		<- openFile fileName ReadMode
	
	"VECTOR"	<- hGetLine handle
	[len]		<- liftM (P.map readInt . words) $ hGetLine handle
	str		<- hGetContents handle
	let vals	= readValues str

	let dims	= Z :. len
	let vec		= fromList dims vals

	return vec

readInt :: String -> Int
readInt str
	| and $ P.map isDigit str
	= read str
	
	
-- | Write a vector as a text file.
writeVectorAsTextFile 
	:: (U.Elt a, Show a)
	=> Array DIM1 a			-- ^ Vector to write.
	-> FilePath			-- ^ File name of output file.
	-> IO ()

writeVectorAsTextFile arr fileName
 = do	file	<- openFile fileName WriteMode	

	hPutStrLn file "VECTOR"

	let Z :. len
		= extent arr

	hPutStrLn file 	$ show len
	hWriteValues file $ toList arr
	hClose file
	

-- | Generate a random(ish) vector.
genRandomVector 
	:: DIM2 
	-> IO (Array DIM2 Double)

genRandomVector sh
 = do	uarr	<- genRandomUArray (A.size sh)
	return	$ fromUArray sh uarr
			


-- Stuff shared with Matrix module -------------------------------------------------------------
-- | Write out values to a file.
hWriteValues
	:: Show a
	=> Handle 
	-> [a] 				-- ^ Data values.
	-> IO ()

hWriteValues handle xx
 = go xx
 where
	go []		= return ()
	go (x:xs)
	 = do	hPutStr handle $ show x
		hPutStr handle $ "\n"
		go xs


-- | Read a string containing ints separated by whitespace.	
readValues :: (Num a, Read a) => String -> [a]
readValues cs	= readValues' [] cs
 where	readValues' _ []	= []
	readValues' acc (c : rest)
		| isSpace c
		= if null acc 
			then readValues' [] rest
			else read (reverse acc) : readValues' [] rest

		| isDigit c || c == '.' || c == 'e' || c == '-'
		= readValues' (c : acc) rest

		| otherwise
		= error $ "unexpected char in Matrix file " ++ show (ord c)


-- | Generate a random(ish) UArray of doubles.
-- The std random function is too slow to generate really big vectors
-- with.  Instead, we generate a short random vector and repeat that.
genRandomUArray :: Int -> IO (U.Array Double)
genRandomUArray n 
 = do	let k		= 1000
    	rg		<- newStdGen
    	let randvec	= U.randomRs k (-100, 100) rg
	let vec		= U.map (\i -> randvec U.!: (i `mod` k)) (U.enumFromTo 0 (n-1))
	return vec