matrix-as-xyz (empty) → 0.1.1.0
raw patch · 13 files changed
+802/−0 lines, 13 filesdep +QuickCheckdep +basedep +doctestsetup-changed
Dependencies added: QuickCheck, base, doctest, hspec, matrix, matrix-as-xyz, parsec
Files
- ChangeLog.md +13/−0
- LICENSE +30/−0
- README.md +10/−0
- Setup.hs +2/−0
- matrix-as-xyz.cabal +85/−0
- src/Data/Matrix/AsXYZ.hs +161/−0
- src/Data/Matrix/AsXYZ/Parse.hs +225/−0
- src/Data/Ratio/ParseFloat.hs +117/−0
- src/Data/Ratio/Slash.hs +67/−0
- test/AsXYZSpec.hs +54/−0
- test/SlashSpec.hs +30/−0
- test/Spec.hs +1/−0
- test/doctests.hs +7/−0
+ ChangeLog.md view
@@ -0,0 +1,13 @@+# Revision history for matrix-as-xyz++## 0.1.1.0 -- 2018-06-05++* CabalからStackに変更+* API変更+* 挙動の変更+* Documentの整備+* その他色々++## 0.1.0.0 -- 2017-03-11++* First version. Released on an unsuspecting world.
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2017, narumij++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of narumij nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,10 @@+# matrix-as-xyz++Haskell General equivalent positions Library++Treat matrix as xyz representation like International Tables for X-ray Crystallography++## License++See the [LICENSE](https://github.com/narumij/matrix-as-xyz/LICENSE)+file in the repository.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ matrix-as-xyz.cabal view
@@ -0,0 +1,85 @@+-- This file has been generated from package.yaml by hpack version 0.28.2.+--+-- see: https://github.com/sol/hpack+--+-- hash: 19899810c3d6696ddbcceefa6fcb228661c87238cefcfc1bcdde512fba3dd8ba++name: matrix-as-xyz+version: 0.1.1.0+synopsis: Read and Display representation of matrix like "x,y,z"+description: Please see the README on GitHub at <https://github.com/narumij/matrix-as-xyz#readme>+category: Chemistry+homepage: https://github.com/narumij/matrix-as-xyz#readme+bug-reports: https://github.com/narumij/matrix-as-xyz/issues+author: Jun Narumi+maintainer: narumij@gmail.com+copyright: Jun Narumi+license: BSD3+license-file: LICENSE+build-type: Simple+cabal-version: >= 1.10+extra-source-files:+ ChangeLog.md+ README.md++source-repository head+ type: git+ location: https://github.com/narumij/matrix-as-xyz++library+ exposed-modules:+ Data.Matrix.AsXYZ+ Data.Matrix.AsXYZ.Parse+ Data.Ratio.ParseFloat+ Data.Ratio.Slash+ other-modules:+ Paths_matrix_as_xyz+ hs-source-dirs:+ src+ build-depends:+ QuickCheck+ , base >=4.7 && <5+ , hspec+ , matrix+ , parsec+ default-language: Haskell2010++test-suite matrix-as-xyz-doctest+ type: exitcode-stdio-1.0+ main-is: doctests.hs+ other-modules:+ AsXYZSpec+ SlashSpec+ Spec+ Paths_matrix_as_xyz+ hs-source-dirs:+ test+ ghc-options: -threaded -rtsopts -with-rtsopts=-N+ build-depends:+ QuickCheck+ , base >=4.7 && <5+ , doctest+ , hspec+ , matrix+ , matrix-as-xyz+ , parsec+ default-language: Haskell2010++test-suite matrix-as-xyz-test+ type: exitcode-stdio-1.0+ main-is: Spec.hs+ other-modules:+ AsXYZSpec+ SlashSpec+ Paths_matrix_as_xyz+ hs-source-dirs:+ test+ ghc-options: -threaded -rtsopts -with-rtsopts=-N+ build-depends:+ QuickCheck+ , base >=4.7 && <5+ , hspec+ , matrix+ , matrix-as-xyz+ , parsec+ default-language: Haskell2010
+ src/Data/Matrix/AsXYZ.hs view
@@ -0,0 +1,161 @@+{- |+Module : Data.Matrix.AsXYZ+Copyright : (c) Jun Narumi 2017-2018+License : BSD3+Maintainer : narumij@gmail.com+Stability : experimental+Portability : ?++Read and Display matrix with xyz reperesentation. (like general equivalnet position of International tables of Crystallography.)++-}+module Data.Matrix.AsXYZ (+ fromXYZ,+ fromXYZ',+ fromABC,+ prettyXYZ,+ prettyABC,+ ) where++import Control.Monad (join)+import Data.Char (isAlpha)+import Data.List (intercalate)+import Data.Ratio (Ratio)+import Data.Matrix (Matrix,fromList,fromLists,toLists,identity,zero,(<->))+import Text.ParserCombinators.Parsec (parse,ParseError)++import Data.Ratio.Slash (getRatio,Slash(..))+import Data.Matrix.AsXYZ.Parse (equivalentPositions,transformPpABC,ratio)++-- | Create a matirx from xyz coordinate string of general equivalent position+--+-- > ( 1 % 1 0 % 1 0 % 1 0 % 1 )+-- > ( 0 % 1 1 % 1 0 % 1 0 % 1 )+-- > ( 0 % 1 0 % 1 1 % 1 0 % 1 )+-- > fromXYZ "x,y,z" :: Matrix Rational = ( 0 % 1 0 % 1 0 % 1 1 % 1 )+-- >+-- > ( 1 % 1 0 % 1 0 % 1 1 % 2 )+-- > ( 0 % 1 1 % 1 0 % 1 1 % 3 )+-- > ( 0 % 1 0 % 1 1 % 1 1 % 4 )+-- > fromXYZ "x+1/2,y+1/3,z+1/4" :: Matrix Rational = ( 0 % 1 0 % 1 0 % 1 1 % 1 )+-- >+-- > ( 1 2 3 4 )+-- > ( 5 6 7 8 )+-- > ( 9 10 11 12 )+-- > fromXYZ "x+2y+3z+4,5x+6y+7z+8,9x+10y+11z+12" :: Matrix Int = ( 0 0 0 1 )+fromXYZ :: Integral a => String -> Matrix (Ratio a)+fromXYZ input = unsafeGet $ makeMatrix <$> parse (equivalentPositions ratio) input input++-- | Maybe version+fromXYZ' :: Integral a => String -> Maybe (Matrix (Ratio a))+fromXYZ' input = get $ makeMatrix <$> parse (equivalentPositions ratio) input input++-- | It's uses abc instead of xyz+--+-- > ( 1 % 1 0 % 1 0 % 1 0 % 1 )+-- > ( 0 % 1 1 % 1 0 % 1 0 % 1 )+-- > ( 0 % 1 0 % 1 1 % 1 0 % 1 )+-- > fromXYZ "a,b,c" :: Matrix Rational = ( 0 % 1 0 % 1 0 % 1 1 % 1 )+fromABC :: Integral a => String -> Matrix (Ratio a)+fromABC input = unsafeGet $ makeMatrix <$> parse (transformPpABC ratio) input input++makeMatrix :: Num a => [[a]] -> Matrix a+makeMatrix m = fromLists m <-> fromLists [[0,0,0,1]]++unsafeGet :: Either ParseError a -> a+unsafeGet e = case e of+ Left s -> error $ show s+ Right m -> m++get :: Either ParseError a -> Maybe a+get e = case e of+ Left s -> Nothing+ Right m -> Just m++----------------------------------++-- +または-が銭湯に必ずあるようにする+addPlusSign :: String -> String+addPlusSign xs@('-':_) = xs+addPlusSign xs = '+' : xs++-- 符号付きの数値文字列にする+numStr :: (Integral a) => Ratio a -> String+numStr = addPlusSign . show . Slash++varString :: (Integral a) => Ratio a -> String -> String+varString num label+ -- 0の場合省略+ | num == 0 = ""+ -- 4番目の項目で、変数が付かない場合、数値文字列化+ | null label = numStr num+ -- 数値が1で変数がある場合、数値を省略+ | num == 1 = "+" ++ label+ -- 数値が-1で変数がある場合、数値を省略+ | num == -1 = "-" ++ label+ -- それ以外では数値と変数を文字列化+ | otherwise = numStr num ++ label++-- 正の係数がついた変数である+isPrimary :: String -> Bool+isPrimary x = (hasLetter . reverse) x && isPositive x++hasLetter :: String -> Bool+hasLetter (x:_) = isAlpha x+hasLetter _ = False++isPositive :: String -> Bool+isPositive ('+':_) = True+isPositive _ = False++-- 正の係数がついた変数を先頭にする+varSort :: [String] -> [String]+varSort parts = filter isPrimary parts ++ filter (not . isPrimary) parts++row :: (Integral a) => [String] -> [Ratio a] -> String+row labels line = join . varSort $ zipWith varString line labels++refineRow :: String -> String+refineRow s+ -- 全ての項目が省略されていると空文字列になっているので、0+ | null s = "0"+ -- 先頭の項目が正の場合、+記号を省略できるので削る+ | head s == '+' = tail s+ | otherwise = s++rowString :: (Integral a) => [String] -> [Ratio a] -> String+rowString labels line = refineRow (row labels line)++xyzLabel :: [String]+xyzLabel = ["x","y","z",""]++abcLabel :: [String]+abcLabel = ["a","b","c",""]++showAs :: (Integral a) => [String] -> Matrix (Ratio a) -> String+showAs labels = intercalate "," . map (rowString labels) . take 3 . toLists+++-- | Get the xyz representation of matrix+--+-- >>> prettyXYZ (identity 4 :: Matrix Rational)+-- "x,y,z"+--+-- > ( 0 % 1 0 % 1 0 % 1 1 % 2 )+-- > ( 0 % 1 0 % 1 0 % 1 2 % 3 )+-- > ( 0 % 1 0 % 1 0 % 1 4 % 5 )+-- > prettyXYZ ( 0 % 1 0 % 1 0 % 1 1 % 1 ) = "1/2,2/3,4/5"+prettyXYZ :: (Integral a) =>+ Matrix (Ratio a) -- ^ 3x3, 3x4 or 4x4 matrix+ -> String+prettyXYZ = showAs xyzLabel+++-- | It's uses abc instead of xyz+--+-- >>> prettyABC (identity 4 :: Matrix Rational)+-- "a,b,c"+prettyABC :: (Integral a) =>+ Matrix (Ratio a) -- ^ 3x3, 3x4 or 4x4 matrix+ -> String+prettyABC = showAs abcLabel
+ src/Data/Matrix/AsXYZ/Parse.hs view
@@ -0,0 +1,225 @@+{- |+Module : Data.Matrix.AsXYZ.Parse+Copyright : (c) Jun Narumi 2018+License : BSD3+Maintainer : narumij@gmail.com+Stability : experimental+Portability : ?+-}+module Data.Matrix.AsXYZ.Parse (+ Value,+ equivalentPositions,+ transformPpABC,+ transformQqXYZ,+ ratio,+ integral,+ floating,+ ) where++import Control.Monad+import Data.Maybe+import Data.List+import Text.ParserCombinators.Parsec++import Data.Ratio+import Data.Ratio.Slash++import Data.Ratio.ParseFloat (readFloatingPoint)++import Data.Matrix (fromList,fromLists,Matrix(..),joinBlocks,(<->))++-- | General equivalent positions parser+equivalentPositions :: Num a =>+ ReadNum a -- ^ use converter below+ -> CharParser () [[a]]+equivalentPositions = components xyz++-- | Same as equivalentPositions but uses abc instead of xyz+transformPpABC :: Num a => ReadNum a -> CharParser () [[a]]+transformPpABC = components abc++-- | Alias of equivalentPositions+transformQqXYZ :: Num a => ReadNum a -> CharParser () [[a]]+transformQqXYZ = components xyz++-- | Converter of 3 kind of number (int,float,ratio) string to rational+--+-- Use it for equivalentPositions or something parseer+ratio :: Integral a => Value -> Either String (Ratio a)+ratio (I s) = Right $ getRatio . read $ s+ratio (R s) = Right $ getRatio . read $ s+ratio (F s) = Right $ readFloatingPoint s++-- | Converter of integral number description to integral+--+-- Use it for equivalentPositions or something parseer+integral :: Integral a => Value -> Either String a+integral (I s) = Right $ fromIntegral (read s :: Integer)+integral (R s) = Left $ "cannot convert to integer from " ++ s ++ "."+integral (F s) = Left $ "cannot convert to integer from " ++ s ++ "."++-- | Converter of 3 kind of number description to floating point+--+-- Use it for equivalentPositions or something parseer+floating :: Floating a => Value -> Either String a+floating v = fromRational <$> ratio v++-- 数値の型情報+data Val a+ -- 整数+ = I a+ -- 浮動小数+ | F a+ -- 分数+ | R a+ deriving Show++instance Functor Val where+ fmap f (I a) = I (f a)+ fmap f (F a) = F (f a)+ fmap f (R a) = R (f a)++-- | Type of numeric type information generated in the middle+type Value = Val String++data Var a+ = X a+ | Y a+ | Z a+ | W a+ deriving (Show,Eq)++instance Functor Var where+ fmap f (X a) = X (f a)+ fmap f (Y a) = Y (f a)+ fmap f (Z a) = Z (f a)+ fmap f (W a) = W (f a)++v (Just 'x') = X+v (Just 'a') = X+v (Just 'y') = Y+v (Just 'b') = Y+v (Just 'z') = Z+v (Just 'c') = Z+v Nothing = W++sign :: CharParser () Char+sign = oneOf "-+"++zero :: CharParser () String+zero = do+ char '0'+ return "0"++num :: CharParser () String+num = do+ x <- oneOf "123456789"+ xs <- many digit+ return $ x : xs++int :: CharParser () String+int = zero <|> num++integer :: CharParser () Value+integer = do+ i <- int+ return (I i)++float :: CharParser () Value+float = do+ i <- option "" int+ char '.'+ f <- many digit+ return (F $ i ++ "." ++ f )++fract :: CharParser () Value+fract = do+ n <- many1 digit+ option () spaces+ char '/'+ option () spaces+ d <- many1 digit+ return (R $ n ++ "/" ++ d)++number' :: CharParser () Value+number'+ = try fract+ <|> try float+ <|> integer++-- | numRead関数のシグネチャの簡易表記+type ReadNum b = Value -> Either String b++number :: ReadNum b -> CharParser () b+number numRead = do+ n <- number'+ case numRead n of+ Left s -> fail s+ Right nn -> return nn++elementBody :: CharParser () Char -> ReadNum a -> CharParser () (Maybe a, Maybe Char)+elementBody var conv = do+ n <- optionMaybe (number conv)+ option () spaces+ v <- optionMaybe var+ option () spaces+ guard (isJust n || isJust v)+ return (n,v)++minus :: Num a => Maybe Char -> (a -> a)+minus (Just '-') = negate+minus (Just '+') = id+minus Nothing = id++one :: Num a => CharParser () Char -> ReadNum a -> CharParser () (Var a)+one var numRead = do+ s <- optionMaybe sign+ option () spaces+ (n,l) <- elementBody var numRead+ return $ v l . minus s . fromMaybe 1 $ n++other :: Num a => CharParser () Char -> ReadNum a -> CharParser () (Var a)+other var numRead = do+ s <- sign+ option () spaces+ (n,l) <- elementBody var numRead+ return $ v l . minus (Just s) . fromMaybe 1 $ n++overlap :: Eq a => [a] -> Bool+overlap n = (length . nub) n /= length n++constructRow :: Num a => [Var a] -> [a]+constructRow = map (fromMaybe 0 . listToMaybe . catMaybes) . transpose . map toArray+ where+ toArray (X n) = [Just n,Nothing,Nothing,Nothing]+ toArray (Y n) = [Nothing,Just n,Nothing,Nothing]+ toArray (Z n) = [Nothing,Nothing,Just n,Nothing]+ toArray (W n) = [Nothing,Nothing,Nothing,Just n]++component :: Num b => CharParser () Char -> ReadNum b -> CharParser () [b]+component var numRead = do+ option () spaces+ x <- one var numRead+ xs <- many (other var numRead)+ option () spaces+ let mm = x : xs+ if overlap (map void mm)+ then+ fail "overlaps var type"+ else+ return (constructRow mm)++components :: Num a => CharParser () Char -> ReadNum a -> CharParser () [[a]]+components var conv = do+ a <- component var conv+ char ','+ b <- component var conv+ char ','+ c <- component var conv+ return [a,b,c]++xyz :: CharParser () Char+xyz = oneOf "xyzXYZ"++abc :: CharParser () Char+abc = oneOf "abcABC"
+ src/Data/Ratio/ParseFloat.hs view
@@ -0,0 +1,117 @@+{- |+Module : Data.Ratio.ParseFloat+Copyright : (c) Jun Narumi 2018+License : BSD3+Maintainer : narumij@gmail.com+Stability : experimental+Portability : ?++Floating point parser++Temporary solution to the problem below++> ghci> realToFrac (read "1.1" :: Double) :: Rational+> 2476979795053773 % 2251799813685248++-}+module Data.Ratio.ParseFloat (+ readFloatingPoint,+ floating,+ ) where++import Data.Ratio+import Text.ParserCombinators.Parsec++-- このような一見、車輪の再発明に思えるコードをわざわざ書いたのは+-- ghci> realToFrac (read "1.1" :: Double) :: Rational+-- 2476979795053773 % 2251799813685248+-- という問題に対処するため。+-- これ以外に良い方法、良い書き方が分かれば、削除します。++-- | Obtain fractions from floating point representation string+--+-- >>> readFloatingPoint "1.1"+-- 11 % 10+-- >>> readFloatingPoint "0.5"+-- 1 % 2+-- >>> readFloatingPoint ".5"+-- 1 % 2+-- >>> readFloatingPoint "10."+-- 10 % 1+-- >>> readFloatingPoint "10"+-- 10 % 1+-- >>> readFloatingPoint "10.2"+-- 51 % 5+-- >>> readFloatingPoint "1e-1"+-- 1 % 10+-- >>> readFloatingPoint "-0.5e-1"+-- (-1) % 20+-- >>> readFloatingPoint "5e2"+-- 500 % 1+-- >>> readFloatingPoint "5e+2"+-- 500 % 1+readFloatingPoint :: Integral a => String -> Ratio a+readFloatingPoint s = case parse floating s s of+ Left e -> error $ show e+ Right r -> r++zero :: CharParser () String+zero = do+ char '0'+ return "0"++num :: CharParser () String+num = do+ x <- oneOf "123456789"+ xs <- many digit+ return $ x : xs++int :: CharParser () String+int = zero <|> num++sign :: CharParser () Char+sign = oneOf "-+"++decimal :: CharParser () String+decimal = do+ char '.'+ many digit++exponent' :: Integral a => CharParser () a+exponent' = do+ oneOf "eE"+ s <- optionMaybe sign+ e <- int+ return $ signPart s $ read' e++-- | Parser section+floating :: Integral a => CharParser () (Ratio a)+floating = do+ s <- optionMaybe sign+ i <- option "" int+ f <- option "" decimal+ e <- optionMaybe exponent'+ return $ signPart s . expPart e $ intPart i + decimalPart f++signPart :: Num a => Maybe Char -> a -> a+signPart (Just '-') = negate+signPart _ = id++intPart :: Integral a => String -> Ratio a+intPart "" = 0+intPart i = read' i % 1++decimalPart :: Integral a => String -> Ratio a+decimalPart "" = 0+decimalPart f | read f == 0 = 0+ | otherwise = read' f % (10 ^ length f)++-- 整数型のread instanceを隠蔽している+read' :: Integral a => String -> a+read' s = fromIntegral (read s :: Integer)++expPart :: Integral a => Maybe Integer -> Ratio a -> Ratio a+expPart Nothing = id+expPart (Just s) | s == 0 = id+ | s < 0 = flip (/) (10 ^ abs s)+ | otherwise = flip (*) (10 ^ s)
+ src/Data/Ratio/Slash.hs view
@@ -0,0 +1,67 @@+{- |+Module : Data.Ratio.Slash+Copyright : (c) Jun Narumi 2018+License : BSD3+Maintainer : narumij@gmail.com+Stability : experimental+Portability : ?++Handle fractions described in /, not%++-}++module Data.Ratio.Slash (+ Slash(..),+ ) where++import Control.Monad (guard)+import Control.Applicative ((<|>))+import Data.Ratio+import Numeric++-- | Type of read and show slash form rational+--+-- >>> getRatio . read $ "1/2"+-- 1 % 2+--+-- >>> map getRatio . read $ "[1/2,3/4,5/6]"+-- [1 % 2,3 % 4,5 % 6]+--+-- >>> Slash (1 % 2)+-- 1/2+--+-- >>> map Slash [1%2,3%4,5%6]+-- [1/2,3/4,5/6]+--+newtype Slash a+ = Slash {+ getRatio :: Ratio a+ } deriving (Eq,Ord)++instance (Integral a) => Show (Slash a) where+ showsPrec _ (Slash n)+ | denominator n == 1+ = showSigned showInt 0 (numerator n)+ | otherwise+ = showSigned showInt 0 (numerator n) . showString "/" . showInt (denominator n)++instance (Integral a) => Read (Slash a) where+ readsPrec _ n = do+ ( ( n, d ), st ) <- slashOrInteger n+ guard $ d /= 0+ return ( Slash $ n % d , st )++integer :: (Integral a) => ReadS (a,a)+integer n = do+ ( n, st ) <- readSigned readDec n+ return ( ( n, 1 ), st )++slash :: (Integral a) => ReadS (a,a)+slash n = do+ ( numer, st ) <- readSigned readDec n+ ( "/" , st1 ) <- lex st+ ( denom, st2 ) <- readDec st1+ return ( ( numer, denom ), st2)++slashOrInteger :: (Integral a) => ReadS (a,a)+slashOrInteger n = take 1 $ slash n <|> integer n
+ test/AsXYZSpec.hs view
@@ -0,0 +1,54 @@+module AsXYZSpec where++import Control.Exception (evaluate)++import Test.Hspec+import Data.Ratio+import Data.Matrix+import Data.Matrix.AsXYZ++spec :: Spec+spec = do++ describe "Data.Matrix.AsXYZ.fromXYZ" $ do++ it "read empty throws exception" $ do+ evaluate (fromXYZ "") `shouldThrow` anyException++ it "read x,y,z" $ do+ fromXYZ "x,y,z" `shouldBe` (identity 4)+++ describe "Data.Matrix.AsXYZ.prettyXYZ" $ do++ it "show 0 (3x3)" $ do+ prettyXYZ (zero 3 3) `shouldBe` "0,0,0"++ it "show 0 (3x4)" $ do+ prettyXYZ (zero 3 4) `shouldBe` "0,0,0"++ it "show 0 (4x4)" $ do+ prettyXYZ (zero 4 4) `shouldBe` "0,0,0"++ it "show 1 (4x4)" $ do+ prettyXYZ (identity 4) `shouldBe` "x,y,z"++ it "show 1 (3x4)" $ do+ prettyXYZ (submatrix 1 3 1 4 $ identity 4) `shouldBe` "x,y,z"++ it "show 1 (3x3)" $ do+ prettyXYZ (submatrix 1 3 1 3 $ identity 4) `shouldBe` "x,y,z"++ it "positive first" $ do+ prettyXYZ (fromLists [[1,-1,-1],[-1,1,-1],[-1,-1,1]]) `shouldBe` "x-y-z,y-x-z,z-x-y"++ it "number last" $ do+ prettyXYZ (fromLists [[-1,-1,-1,-1],[-1,-1,-1,0],[-1,-1,-1,1]]) `shouldBe` "-x-y-z-1,-x-y-z,-x-y-z+1"++ describe "Data.Matrix.AsXYZ.prettyABC" $ do++ it "show 0" $ do+ prettyABC (zero 4 4) `shouldBe` "0,0,0"++ it "show 1" $ do+ prettyABC (identity 4) `shouldBe` "a,b,c"
+ test/SlashSpec.hs view
@@ -0,0 +1,30 @@+module SlashSpec where++import Test.Hspec+import Test.Hspec.QuickCheck+import Test.QuickCheck hiding ((.&.))++import Control.Monad+import Data.Ratio+import Data.Ratio.Slash++spec :: Spec+spec = do+ describe "rational" $ do++ prop "read" $+ \n d -> d /= 0 && n /= 0 && d > 1 && denominator ( n % d ) > 1 ==>+ ( (read $ join [show n,"/",show d] ) :: Slash Integer ) `shouldBe` ( Slash $ n % d )++ prop "both ways" $+ \n d -> d /= 0 && n /= 0 && d > 1 && denominator ( n % d ) > 1 ==>+ ( read . show $ Slash ( n % d ) :: Slash Integer ) `shouldBe` ( Slash $ n % d )++ describe "integer" $ do+ prop "read" $+ \n -> True ==>+ ( (read $ show n ) :: Slash Integer ) `shouldBe` ( Slash $ n % 1 )++ prop "both ways" $+ \n -> True ==>+ ( read . show $ Slash ( n % 1 ) :: Slash Integer ) `shouldBe` ( Slash $ n % 1 )
+ test/Spec.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
+ test/doctests.hs view
@@ -0,0 +1,7 @@+import Test.DocTest++main = doctest [+ "src/Data/Ratio/Slash.hs",+ "src/Data/Ratio/ParseFloat.hs",+ "src/Data/Matrix/AsXYZ.hs"+ ]