File: Instances.hs

package info (click to toggle)
haskell-diagrams-lib 1.4.6.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,256 kB
  • sloc: haskell: 8,263; makefile: 2
file content (157 lines) | stat: -rw-r--r-- 5,898 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
{-# LANGUAGE FlexibleContexts     #-}
{-# LANGUAGE FlexibleInstances    #-}
{-# LANGUAGE GADTs                #-}
{-# LANGUAGE ScopedTypeVariables  #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE ViewPatterns         #-}

{-# OPTIONS_GHC -fno-warn-orphans #-}

-- | instances for QuickCheck Arbitrary and approximate equality

module Instances where

import           Diagrams.Prelude
import           Numeric.Extras
import           Test.Tasty.QuickCheck (Arbitrary (..), Gen)
import qualified Test.Tasty.QuickCheck as QC

------------------------------------------------------------
    -- Approximate Comparison for Doubles, Points

epsilon :: Double
epsilon = 0.001

class Approx a where
  (=~) :: a -> a -> Bool

infix 4 =~

--instance (Fractional a, Ord a) => Approx a where
instance Approx Double where
  (=~) a b = abs (a - b) < epsilon

instance Approx Float where
    (=~) a b = abs (a - b) < 0.001

instance Approx n => Approx (V2 n) where
    z1 =~ z2 = (z1^._x) =~ (z2^._x) && (z1^._y) =~ (z2^._y)

instance Approx n => Approx (V3 n) where
    z1 =~ z2 = (z1^._x) =~ (z2^._x) && (z1^._y) =~ (z2^._y) && (z1^._z) =~ (z2^._z)

instance Approx (v n) => Approx (Point v n) where
    p =~ q = view _Point p =~ view _Point q

instance (Approx n, RealExtras n) => Approx (Angle n) where
    a =~ b = normA (a^.rad) =~ normA (b^.rad) where
      normA ang = let ang' = ang `fmod` pi in if ang' >= 0 then ang' else ang'+pi

instance Approx n => Approx (Offset Closed V2 n) where
    OffsetClosed v0 =~ OffsetClosed v1 = v0 =~ v1

instance Approx n => Approx (Segment Closed V2 n) where
    Linear o0 =~ Linear o1 = o0 =~ o1
    Cubic c0 d0 o0 =~ Cubic c1 d1 o1 = c0 =~ c1 && d0 =~ d1 && o0 =~ o1
    _ =~ _ = False
    -- The above is conservative:
    -- Cubic never equals Linear even if they describe the same points

instance Approx n => Approx (FixedSegment V2 n) where
    FLinear a0 b0 =~ FLinear a1 b1 = a0 =~ a1 && b0 =~ b1
    FCubic a0 b0 c0 d0 =~ FCubic a1 b1 c1 d1 = a0 =~ a1 && b0 =~ b1 && c0 =~ c1 && d0 =~ d1
    _ =~ _ = False

instance Approx n => Approx (Trail' Line V2 n) where
    l0 =~ l1 = and $ zipWith (=~) (lineSegments l0) (lineSegments l1)

instance Approx n => Approx (Trail' Loop V2 n) where
    l0 =~ l1 = fst (loopSegments l0) =~ fst (loopSegments l1)

instance (Approx n, Floating n, Ord n) => Approx (Trail V2 n) where
    t0 =~ t1 = and $ zipWith (=~) (trailSegments t0) (trailSegments t1)

instance (Approx a, Approx (Vn a), Num (N a), Additive (V a)) =>
         Approx (Located a) where
           a0 =~ a1 = (loc a0 .-. origin) =~ (loc a1 .-. origin) && unLoc a0 =~ unLoc a1

instance Approx a => Approx (Maybe a) where
    Nothing =~ Nothing = True
    Nothing =~ Just _ = False
    Just _ =~ Nothing = False
    Just l =~ Just r = l =~ r

-- These may be too general
instance Approx a => Approx [a] where
    a =~ b = and $ zipWith (=~) a b

instance (Approx a, Approx b) => Approx (a, b) where
    (a0, b0) =~ (a1,b1) = (a0 =~ a1) && (b0 =~ b1)

------------------------------------------------------------
-- Arbitrary instances for Points, Paths

instance Arbitrary n => Arbitrary (V2 n) where
    arbitrary = (^&) <$> arbitrary <*> arbitrary
    shrink (coords -> x :& y) = (^&) <$> shrink x <*> shrink y

instance Arbitrary n => Arbitrary (V3 n) where
    arbitrary = V3 <$> arbitrary <*> arbitrary <*> arbitrary
    shrink (coords -> x :& y :& z) = V3 <$> shrink x <*> shrink y <*> shrink z

instance Arbitrary (v n) => Arbitrary (Point v n) where
    arbitrary = P <$> arbitrary
    shrink (P v) = P <$> shrink v

instance (Arbitrary n, Floating n, Ord n) => Arbitrary (Transformation V2 n) where
    arbitrary = QC.sized arbT
      where
        arbT 0 = return mempty
        arbT n = QC.oneof
          [ rotation    <$> arbitrary
          , scaling     <$> arbitrary
          , translation <$> arbitrary
          , reflectionAbout <$> arbitrary <*> arbitrary
          , (<>) <$> arbT (n `div` 2) <*> arbT (n `div` 2)
          ]

instance Arbitrary n => Arbitrary (Angle n) where
    arbitrary = review rad <$> arbitrary

instance (Arbitrary n, Floating n) => Arbitrary (Direction V2 n) where
    arbitrary = rotate <$> arbitrary <*> pure xDir

-- -- | Not a valid Show instance because not valid Haskell input
-- instance (Show n, RealFloat n) => Show (Direction V2 n) where
--     show d = "Dir" <> ( show $ d ^. _theta . turn )

-- NOTE on shrinks: Adding definitions of 'shrink' below seems to work
--   in simple tests, but test case failures hang for a very long time
--   (presumably trying lots and lots of expensive shrinks).  Not sure
--   how to make shrinking more tractable.

instance (Arbitrary a, Arbitrary (Vn a)) => Arbitrary (Located a) where
    arbitrary = at <$> arbitrary <*> arbitrary
--    shrink (viewLoc -> (p,a)) = uncurry at <$> shrink (a,p)

instance Arbitrary n => Arbitrary (Offset Closed V2 n) where
    arbitrary = OffsetClosed <$> arbitrary
--    shrink (OffsetClosed x) = OffsetClosed <$> shrink x

instance Arbitrary n =>  Arbitrary (Segment Closed V2 n) where
    arbitrary = QC.oneof [Linear <$> arbitrary, Cubic <$> arbitrary <*> arbitrary <*> arbitrary]
    -- shrink (Linear x) = Linear <$> shrink x
    -- shrink (Cubic x y z) = Linear z
    --                      : [Cubic x' y' z' | (x',y',z') <- shrink (x,y,z)]

instance (Arbitrary n, Floating n, Ord n) => Arbitrary (Trail' Line V2 n) where
    arbitrary = lineFromSegments <$> arbitrary
--    shrink (lineSegments -> segs) = lineFromSegments <$> shrink segs

instance (Arbitrary n, Floating n, Ord n) => Arbitrary (Trail' Loop V2 n) where
    arbitrary = closeLine <$> arbitrary
--    shrink (cutLoop -> l) = closeLine <$> shrink l

instance (Arbitrary n, Floating n, Ord n) => Arbitrary (Trail V2 n) where
    arbitrary = QC.oneof [Trail <$> (arbitrary :: Gen (Trail' Loop V2 n)), Trail <$> (arbitrary :: Gen (Trail' Line V2 n))]