poly-0.3.1.0: test/Quaternion.hs
-- |
-- Module: Quaternion
-- Copyright: (c) 2019 Andrew Lelechenko
-- Licence: BSD3
-- Maintainer: Andrew Lelechenko <andrew.lelechenko@gmail.com>
--
-- This is a toy implementtion of quaternions,
-- serving solely to test polynomials
-- over non-commutative rings.
--
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}
module Quaternion
( Quaternion(..)
) where
import Prelude hiding (negate)
import Control.Monad
import Data.Semiring (Semiring(..), Ring(..), minus)
import GHC.Generics
import Test.Tasty.QuickCheck hiding (scale)
import Data.Vector.Unboxed (Vector)
import qualified Data.Vector.Generic as G
import Data.Vector.Unboxed.Mutable (MVector)
import qualified Data.Vector.Generic.Mutable as M
import Data.Vector.Unboxed (Unbox)
data Quaternion a = Quaternion a a a a
deriving (Eq, Ord, Show, Generic)
instance Ring a => Semiring (Quaternion a) where
zero = Quaternion zero zero zero zero
one = Quaternion one zero zero zero
plus (Quaternion a1 b1 c1 d1) (Quaternion a2 b2 c2 d2) =
Quaternion (a1 `plus` a2) (b1 `plus` b2) (c1 `plus` c2) (d1 `plus` d2)
times (Quaternion a1 b1 c1 d1) (Quaternion a2 b2 c2 d2) =
Quaternion
(a1 `times` a2 `minus` b1 `times` b2 `minus` c1 `times` c2 `minus` d1 `times` d2)
(a1 `times` b2 `plus` b1 `times` a2 `plus` c1 `times` d2 `minus` d1 `times` c2)
(a1 `times` c2 `minus` b1 `times` d2 `plus` c1 `times` a2 `plus` d1 `times` b2)
(a1 `times` d2 `plus` b1 `times` c2 `minus` c1 `times` b2 `plus` d1 `times` a2)
instance Ring a => Ring (Quaternion a) where
negate (Quaternion a b c d) =
Quaternion (negate a) (negate b) (negate c) (negate d)
instance (Ring a, Num a) => Num (Quaternion a) where
(+) = plus
(-) = minus
(*) = times
abs = id
signum = const one
fromInteger n = Quaternion (fromInteger n) zero zero zero
instance Arbitrary a => Arbitrary (Quaternion a) where
arbitrary = Quaternion <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary
shrink = genericShrink
newtype instance MVector s (Quaternion a) = MV_Quaternion (MVector s (a, a, a, a))
newtype instance Vector (Quaternion a) = V_Quaternion (Vector (a, a, a, a))
instance (Unbox a) => Unbox (Quaternion a)
instance (Unbox a) => M.MVector MVector (Quaternion a) where
{-# INLINE basicLength #-}
{-# INLINE basicUnsafeSlice #-}
{-# INLINE basicOverlaps #-}
{-# INLINE basicUnsafeNew #-}
{-# INLINE basicInitialize #-}
{-# INLINE basicUnsafeReplicate #-}
{-# INLINE basicUnsafeRead #-}
{-# INLINE basicUnsafeWrite #-}
{-# INLINE basicClear #-}
{-# INLINE basicSet #-}
{-# INLINE basicUnsafeCopy #-}
{-# INLINE basicUnsafeGrow #-}
basicLength (MV_Quaternion v) = M.basicLength v
basicUnsafeSlice i n (MV_Quaternion v) = MV_Quaternion $ M.basicUnsafeSlice i n v
basicOverlaps (MV_Quaternion v1) (MV_Quaternion v2) = M.basicOverlaps v1 v2
basicUnsafeNew n = MV_Quaternion `liftM` M.basicUnsafeNew n
basicInitialize (MV_Quaternion v) = M.basicInitialize v
basicUnsafeReplicate n (Quaternion a b c d) = MV_Quaternion `liftM` M.basicUnsafeReplicate n (a, b, c, d)
basicUnsafeRead (MV_Quaternion v) i = (\(a, b, c, d) -> Quaternion a b c d) `liftM` M.basicUnsafeRead v i
basicUnsafeWrite (MV_Quaternion v) i (Quaternion a b c d) = M.basicUnsafeWrite v i (a, b, c, d)
basicClear (MV_Quaternion v) = M.basicClear v
basicSet (MV_Quaternion v) (Quaternion a b c d) = M.basicSet v (a, b, c, d)
basicUnsafeCopy (MV_Quaternion v1) (MV_Quaternion v2) = M.basicUnsafeCopy v1 v2
basicUnsafeMove (MV_Quaternion v1) (MV_Quaternion v2) = M.basicUnsafeMove v1 v2
basicUnsafeGrow (MV_Quaternion v) n = MV_Quaternion `liftM` M.basicUnsafeGrow v n
instance (Unbox a) => G.Vector Vector (Quaternion a) where
{-# INLINE basicUnsafeFreeze #-}
{-# INLINE basicUnsafeThaw #-}
{-# INLINE basicLength #-}
{-# INLINE basicUnsafeSlice #-}
{-# INLINE basicUnsafeIndexM #-}
{-# INLINE elemseq #-}
basicUnsafeFreeze (MV_Quaternion v) = V_Quaternion `liftM` G.basicUnsafeFreeze v
basicUnsafeThaw (V_Quaternion v) = MV_Quaternion `liftM` G.basicUnsafeThaw v
basicLength (V_Quaternion v) = G.basicLength v
basicUnsafeSlice i n (V_Quaternion v) = V_Quaternion $ G.basicUnsafeSlice i n v
basicUnsafeIndexM (V_Quaternion v) i
= (\(a, b, c, d) -> Quaternion a b c d) `liftM` G.basicUnsafeIndexM v i
basicUnsafeCopy (MV_Quaternion mv) (V_Quaternion v)
= G.basicUnsafeCopy mv v
elemseq _ (Quaternion a b c d) z = G.elemseq (undefined :: Vector a) a
$ G.elemseq (undefined :: Vector a) b
$ G.elemseq (undefined :: Vector a) c
$ G.elemseq (undefined :: Vector a) d z