{-# LANGUAGE NoImplicitPrelude #-} {- | Abstract Physical Units -} module Number.Physical.Unit where import MathObj.DiscreteMap (strip) import qualified Data.Map as Map import Data.Map (Map) import Data.Maybe(fromJust,fromMaybe) import qualified Number.Ratio as Ratio import Data.Maybe.HT(toMaybe) import NumericPrelude.Base import NumericPrelude.Numeric {- | A Unit.T is a sparse vector with integer entries Each map n->m means that the unit of the n-th dimension is given m times. Example: Let the quantity of length (meter, m) be the zeroth dimension and let the quantity of time (second, s) be the first dimension, then the composed unit @m/s^2@ corresponds to the Map @[(0,1),(1,-2)]@. In future I want to have more abstraction here, e.g. a type class from the Edison project that abstracts from the underlying implementation. Then one can easily switch between Arrays, Binary trees (like Map) and what know I. -} type T i = Map i Int -- | The neutral Unit.T scalar :: T i scalar = Map.empty -- | Test for the neutral Unit.T isScalar :: T i -> Bool isScalar = Map.null -- | Convert a List to sparse Map representation -- Example: [-1,0,-2] -> [(0,-1),(2,-2)] fromVector :: (Enum i, Ord i) => [Int] -> T i fromVector x = strip (Map.fromList (zip [toEnum 0 .. toEnum ((length x)-1)] x)) -- | Convert Map to a List toVector :: (Enum i, Ord i) => T i -> [Int] toVector x = map (flip (Map.findWithDefault 0) x) [(toEnum 0)..(maximum (Map.keys x))] ratScale :: Ratio.T Int -> T i -> T i ratScale expo = fmap (fromMaybe (error "Physics.Quantity.Unit.ratScale: fractional result")) . ratScaleMaybe2 expo ratScaleMaybe :: Ratio.T Int -> T i -> Maybe (T i) ratScaleMaybe expo u = let fmMaybe = ratScaleMaybe2 expo u in toMaybe (not (Nothing `elem` Map.elems fmMaybe)) (fmap fromJust fmMaybe) -- helper function for ratScale and ratScaleMaybe ratScaleMaybe2 :: Ratio.T Int -> T i -> Map i (Maybe Int) ratScaleMaybe2 expo = fmap (\c -> let y = Ratio.scale c expo in toMaybe (denominator y == 1) (numerator y)) {- impossible because Unit.T is a type synonym but not a data type instance Show (Unit.T i) where show = show.toVector -}