-- | Z-/n/ functions
module Music.Theory.Z where

import Data.Char {- base -}
import Data.List {- base -}

import qualified Music.Theory.List as T {- hmt -}

-- | Z type.
--
-- > map z_modulus [z7,z12] == [7,12]
newtype Z i = Z {forall i. Z i -> i
z_modulus :: i}

-- | 'mod' of 'Z'.
--
-- > map (z_mod z12) [-1,0,1,11,12,13] == [11,0,1,11,0,1]
z_mod :: Integral i => Z i -> i -> i
z_mod :: forall i. Integral i => Z i -> i -> i
z_mod (Z i
i) i
n = forall a. Integral a => a -> a -> a
mod i
n i
i

-- | Common moduli in music theory.
z5,z7,z12,z16 :: Num i => Z i
z5 :: forall i. Num i => Z i
z5 = forall i. i -> Z i
Z i
5
z7 :: forall i. Num i => Z i
z7 = forall i. i -> Z i
Z i
7
z12 :: forall i. Num i => Z i
z12 = forall i. i -> Z i
Z i
12
z16 :: forall i. Num i => Z i
z16 = forall i. i -> Z i
Z i
16

-- | Is /n/ in (0,/m/-1).
is_z_n :: (Num a, Ord a) => a -> a -> Bool
is_z_n :: forall a. (Num a, Ord a) => a -> a -> Bool
is_z_n a
m a
n = a
n forall a. Ord a => a -> a -> Bool
>= a
0 Bool -> Bool -> Bool
&& a
n forall a. Ord a => a -> a -> Bool
< a
m

lift_unary_Z :: Integral i => Z i -> (t -> i) -> t -> i
lift_unary_Z :: forall i t. Integral i => Z i -> (t -> i) -> t -> i
lift_unary_Z Z i
z t -> i
f = forall i. Integral i => Z i -> i -> i
z_mod Z i
z forall b c a. (b -> c) -> (a -> b) -> a -> c
. t -> i
f

lift_binary_Z :: Integral i => Z i -> (s -> t -> i) -> s -> t -> i
lift_binary_Z :: forall i s t. Integral i => Z i -> (s -> t -> i) -> s -> t -> i
lift_binary_Z Z i
z s -> t -> i
f s
n1 = forall i. Integral i => Z i -> i -> i
z_mod Z i
z forall b c a. (b -> c) -> (a -> b) -> a -> c
. s -> t -> i
f s
n1

-- | Add two Z.
--
-- > map (z_add z12 4) [1,5,6,11] == [5,9,10,3]
z_add :: Integral i => Z i -> i -> i -> i
z_add :: forall i. Integral i => Z i -> i -> i -> i
z_add Z i
z = forall i s t. Integral i => Z i -> (s -> t -> i) -> s -> t -> i
lift_binary_Z Z i
z forall a. Num a => a -> a -> a
(+)

-- | The underlying type /i/ is presumed to be signed...
--
-- > z_sub z12 0 8 == 4
--
-- > import Data.Word {- base -}
-- > z_sub z12 (0::Word8) 8 == 8
-- > ((0 - 8) :: Word8) == 248
-- > 248 `mod` 12 == 8
z_sub :: Integral i => Z i -> i -> i -> i
z_sub :: forall i. Integral i => Z i -> i -> i -> i
z_sub Z i
z = forall i s t. Integral i => Z i -> (s -> t -> i) -> s -> t -> i
lift_binary_Z Z i
z (-)

-- | Allowing unsigned /i/ is rather inefficient...
--
-- > z_sub_unsigned z12 (0::Word8) 8 == 4
z_sub_unsigned :: (Integral i,Ord i) => Z i -> i -> i -> i
z_sub_unsigned :: forall i. (Integral i, Ord i) => Z i -> i -> i -> i
z_sub_unsigned Z i
z i
p i
q =
    if i
p forall a. Ord a => a -> a -> Bool
> i
q
    then forall i. Integral i => Z i -> i -> i
z_mod Z i
z (i
p forall a. Num a => a -> a -> a
- i
q)
    else forall i. Integral i => Z i -> i -> i
z_mod Z i
z (i
p forall a. Num a => a -> a -> a
+ forall i. Z i -> i
z_modulus Z i
z forall a. Num a => a -> a -> a
- i
q)

z_mul :: Integral i => Z i -> i -> i -> i
z_mul :: forall i. Integral i => Z i -> i -> i -> i
z_mul Z i
z = forall i s t. Integral i => Z i -> (s -> t -> i) -> s -> t -> i
lift_binary_Z Z i
z forall a. Num a => a -> a -> a
(*)

-- > z_negate z12 7 == 5
z_negate :: Integral i => Z i -> i -> i
z_negate :: forall i. Integral i => Z i -> i -> i
z_negate Z i
z = forall i. Integral i => Z i -> i -> i -> i
z_sub Z i
z i
0 -- error "Z numbers are not signed"

z_fromInteger :: Integral i => Z i -> Integer -> i
z_fromInteger :: forall i. Integral i => Z i -> Integer -> i
z_fromInteger Z i
z Integer
i = forall i. Integral i => Z i -> i -> i
z_mod Z i
z (forall a. Num a => Integer -> a
fromInteger Integer
i)

z_signum :: t -> u -> v
z_signum :: forall t u v. t -> u -> v
z_signum t
_ u
_ = forall a. HasCallStack => [Char] -> a
error [Char]
"Z numbers are not signed"

z_abs :: t -> u -> v
z_abs :: forall t u v. t -> u -> v
z_abs t
_ u
_ = forall a. HasCallStack => [Char] -> a
error [Char]
"Z numbers are not signed"

-- > map (to_Z z12) [-9,-3,0] == [3,9,0]
to_Z :: Integral i => Z i -> i -> i
to_Z :: forall i. Integral i => Z i -> i -> i
to_Z Z i
z = forall i. Integral i => Z i -> Integer -> i
z_fromInteger Z i
z forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (Integral a, Num b) => a -> b
fromIntegral

from_Z :: (Integral i,Num n) => i -> n
from_Z :: forall a b. (Integral a, Num b) => a -> b
from_Z = forall a b. (Integral a, Num b) => a -> b
fromIntegral

-- | Universe of 'Z'.
--
-- > z_univ z12 == [0..11]
z_univ :: Integral i => Z i -> [i]
z_univ :: forall i. Integral i => Z i -> [i]
z_univ (Z i
z) = [i
0 .. i
z forall a. Num a => a -> a -> a
- i
1]

-- | Z of 'z_univ' not in given set.
--
-- > z_complement z5 [0,2,3] == [1,4]
-- > z_complement z12 [0,2,4,5,7,9,11] == [1,3,6,8,10]
z_complement :: Integral i => Z i -> [i] -> [i]
z_complement :: forall i. Integral i => Z i -> [i] -> [i]
z_complement Z i
z = forall a. Eq a => [a] -> [a] -> [a]
(\\) (forall i. Integral i => Z i -> [i]
z_univ Z i
z)

z_quot :: Integral i => Z i -> i -> i -> i
z_quot :: forall i. Integral i => Z i -> i -> i -> i
z_quot Z i
z i
p = forall i. Integral i => Z i -> i -> i
to_Z Z i
z forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Integral a => a -> a -> a
quot i
p

z_rem :: Integral i => Z i -> i -> i -> i
z_rem :: forall i. Integral i => Z i -> i -> i -> i
z_rem Z i
z i
p = forall i. Integral i => Z i -> i -> i
to_Z Z i
z forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Integral a => a -> a -> a
rem i
p

div_err :: Integral i => String -> i -> i -> i
div_err :: forall i. Integral i => [Char] -> i -> i -> i
div_err [Char]
s i
p i
q = if i
q forall a. Eq a => a -> a -> Bool
== i
0 then forall a. HasCallStack => [Char] -> a
error ([Char]
"div_err: zero" forall a. [a] -> [a] -> [a]
++ [Char]
s) else i
p forall a. Integral a => a -> a -> a
`div` i
q

z_div :: Integral i => Z i -> i -> i -> i
z_div :: forall i. Integral i => Z i -> i -> i -> i
z_div Z i
z i
p = forall i. Integral i => Z i -> i -> i
to_Z Z i
z forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall i. Integral i => [Char] -> i -> i -> i
div_err [Char]
"z_div" i
p

z_quotRem :: Integral i => Z i -> i -> i -> (i,i)
z_quotRem :: forall i. Integral i => Z i -> i -> i -> (i, i)
z_quotRem Z i
z i
p i
q = (forall i. Integral i => Z i -> i -> i -> i
z_quot Z i
z i
p i
q,forall i. Integral i => Z i -> i -> i -> i
z_quot Z i
z i
p i
q)

z_divMod :: Integral i => Z i -> i -> i -> (i,i)
z_divMod :: forall i. Integral i => Z i -> i -> i -> (i, i)
z_divMod Z i
z i
p i
q = (forall i. Integral i => Z i -> i -> i -> i
z_div Z i
z i
p i
q,forall i. Integral i => Z i -> i -> i
z_mod Z i
z (forall a. Integral a => a -> a -> a
mod i
p i
q))

z_toInteger :: Integral i => Z i -> i -> i
z_toInteger :: forall i. Integral i => Z i -> i -> i
z_toInteger = forall i. Integral i => Z i -> i -> i
to_Z

-- * Z16

-- | Type generalised 'intToDigit'.
--
-- > map integral_to_digit [0 .. 15] == "0123456789abcdef"
integral_to_digit :: Integral t => t -> Char
integral_to_digit :: forall t. Integral t => t -> Char
integral_to_digit = Int -> Char
intToDigit forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (Integral a, Num b) => a -> b
fromIntegral

-- | 'is_z_n' 16.
is_z16 :: Integral t => t -> Bool
is_z16 :: forall t. Integral t => t -> Bool
is_z16 = forall a. (Num a, Ord a) => a -> a -> Bool
is_z_n t
16

-- | Alias for 'integral_to_digit'.
z16_to_char :: Integral t => t -> Char
z16_to_char :: forall t. Integral t => t -> Char
z16_to_char = forall t. Integral t => t -> Char
integral_to_digit

-- | 'z16_to_char' in braces, {1,2,3}.
z16_set_pp :: Integral t => [t] -> String
z16_set_pp :: forall t. Integral t => [t] -> [Char]
z16_set_pp = forall a. (a, a) -> [a] -> [a]
T.bracket (Char
'{',Char
'}') forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map forall t. Integral t => t -> Char
z16_to_char

-- | 'z16_to_char' in arrows, <1,2,3>.
z16_seq_pp :: Integral t => [t] -> String
z16_seq_pp :: forall t. Integral t => [t] -> [Char]
z16_seq_pp = forall a. (a, a) -> [a] -> [a]
T.bracket (Char
'<',Char
'>') forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map forall t. Integral t => t -> Char
z16_to_char

-- | 'z16_to_char' in brackets, [1,2,3].
z16_vec_pp :: Integral t => [t] -> String
z16_vec_pp :: forall t. Integral t => [t] -> [Char]
z16_vec_pp = forall a. (a, a) -> [a] -> [a]
T.bracket (Char
'[',Char
']') forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map forall t. Integral t => t -> Char
z16_to_char