mirror of
https://github.com/Jaxan/ons-hs.git
synced 2025-04-27 14:47:45 +02:00
Adds units tests + benchmarking. Abstracted Support to its own modules. Performance improvements
This commit is contained in:
parent
fa2061ac43
commit
8487919a7c
7 changed files with 236 additions and 34 deletions
13
ons-hs.cabal
13
ons-hs.cabal
|
@ -18,8 +18,10 @@ library
|
||||||
exposed-modules: EquivariantMap
|
exposed-modules: EquivariantMap
|
||||||
, EquivariantSet
|
, EquivariantSet
|
||||||
, Orbit
|
, Orbit
|
||||||
|
, Support
|
||||||
build-depends: base >= 4.7 && < 5
|
build-depends: base >= 4.7 && < 5
|
||||||
, containers
|
, containers
|
||||||
|
, data-ordlist
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
|
|
||||||
executable ons-hs-exe
|
executable ons-hs-exe
|
||||||
|
@ -30,6 +32,17 @@ executable ons-hs-exe
|
||||||
, ons-hs
|
, ons-hs
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
|
|
||||||
|
benchmark ons-hs-bench
|
||||||
|
type: exitcode-stdio-1.0
|
||||||
|
hs-source-dirs: test
|
||||||
|
main-is: Bench.hs
|
||||||
|
build-depends: base
|
||||||
|
, criterion
|
||||||
|
, deepseq
|
||||||
|
, ons-hs
|
||||||
|
ghc-options: -threaded -rtsopts -with-rtsopts=-N -O2
|
||||||
|
default-language: Haskell2010
|
||||||
|
|
||||||
test-suite ons-hs-test
|
test-suite ons-hs-test
|
||||||
type: exitcode-stdio-1.0
|
type: exitcode-stdio-1.0
|
||||||
hs-source-dirs: test
|
hs-source-dirs: test
|
||||||
|
|
|
@ -13,6 +13,7 @@ import qualified Data.Map as Map
|
||||||
|
|
||||||
import EquivariantSet (EquivariantSet(EqSet))
|
import EquivariantSet (EquivariantSet(EqSet))
|
||||||
import Orbit
|
import Orbit
|
||||||
|
import Support
|
||||||
|
|
||||||
-- TODO: foldable / traversable
|
-- TODO: foldable / traversable
|
||||||
-- TODO: adjust / alter / update
|
-- TODO: adjust / alter / update
|
||||||
|
@ -39,7 +40,7 @@ deriving instance Ord (Orb k) => Semigroup (EquivariantMap k v)
|
||||||
-- Helper functions
|
-- Helper functions
|
||||||
|
|
||||||
mapel :: (Orbit k, Orbit v) => k -> v -> (Orb v, [Bool])
|
mapel :: (Orbit k, Orbit v) => k -> v -> (Orb v, [Bool])
|
||||||
mapel k v = (toOrbit v, bv (Set.toAscList (support k)) (Set.toAscList (support v)))
|
mapel k v = (toOrbit v, bv (Support.toList (support k)) (Support.toList (support v)))
|
||||||
|
|
||||||
bv :: [Rat] -> [Rat] -> [Bool]
|
bv :: [Rat] -> [Rat] -> [Bool]
|
||||||
bv l [] = replicate (length l) False
|
bv l [] = replicate (length l) False
|
||||||
|
@ -50,7 +51,7 @@ bv (x:xs) (y:ys) = case compare x y of
|
||||||
GT -> error "Non-equivariant function"
|
GT -> error "Non-equivariant function"
|
||||||
|
|
||||||
mapelInv :: (Orbit k, Orbit v) => k -> (Orb v, [Bool]) -> v
|
mapelInv :: (Orbit k, Orbit v) => k -> (Orb v, [Bool]) -> v
|
||||||
mapelInv x (oy, bv) = getElement oy (Set.fromAscList . fmap fst . Prelude.filter snd $ zip (Set.toAscList (support x)) bv)
|
mapelInv x (oy, bv) = getElement oy (Support.fromDistinctAscList . fmap fst . Prelude.filter snd $ zip (Support.toList (support x)) bv)
|
||||||
|
|
||||||
|
|
||||||
-- Query
|
-- Query
|
||||||
|
|
|
@ -12,6 +12,7 @@ import qualified Data.Set as Set
|
||||||
import Data.Semigroup (Semigroup)
|
import Data.Semigroup (Semigroup)
|
||||||
|
|
||||||
import Orbit
|
import Orbit
|
||||||
|
import Support
|
||||||
|
|
||||||
-- TODO: think about folds (the monoids should be nominal?)
|
-- TODO: think about folds (the monoids should be nominal?)
|
||||||
-- TODO: partition / fromList / ...
|
-- TODO: partition / fromList / ...
|
||||||
|
@ -39,7 +40,7 @@ deriving instance Ord (Orb a) => Semigroup (EquivariantSet a)
|
||||||
instance Orbit (EquivariantSet a) where
|
instance Orbit (EquivariantSet a) where
|
||||||
newtype Orb (EquivariantSet a) = OrbEqSet (EquivariantSet a)
|
newtype Orb (EquivariantSet a) = OrbEqSet (EquivariantSet a)
|
||||||
toOrbit = OrbEqSet
|
toOrbit = OrbEqSet
|
||||||
support _ = Set.empty
|
support _ = Support.empty
|
||||||
getElement (OrbEqSet x) _ = x
|
getElement (OrbEqSet x) _ = x
|
||||||
index _ = 0
|
index _ = 0
|
||||||
|
|
||||||
|
@ -109,7 +110,8 @@ filter f (EqSet s) = EqSet . Set.filter (f . getElementE) $ s
|
||||||
map :: (Orbit a, Orbit b, Ord (Orb b)) => (a -> b) -> EquivariantSet a -> EquivariantSet b
|
map :: (Orbit a, Orbit b, Ord (Orb b)) => (a -> b) -> EquivariantSet a -> EquivariantSet b
|
||||||
map f = EqSet . Set.map (toOrbit . f . getElementE) . unEqSet
|
map f = EqSet . Set.map (toOrbit . f . getElementE) . unEqSet
|
||||||
|
|
||||||
-- f should also preserve order!
|
-- f should also preserve order on the orbit types!
|
||||||
|
-- This means you should know the representation to use it well
|
||||||
mapMonotonic :: (Orbit a, Orbit b) => (a -> b) -> EquivariantSet a -> EquivariantSet b
|
mapMonotonic :: (Orbit a, Orbit b) => (a -> b) -> EquivariantSet a -> EquivariantSet b
|
||||||
mapMonotonic f = EqSet . Set.mapMonotonic (toOrbit . f . getElementE) . unEqSet
|
mapMonotonic f = EqSet . Set.mapMonotonic (toOrbit . f . getElementE) . unEqSet
|
||||||
|
|
||||||
|
|
43
src/Orbit.hs
43
src/Orbit.hs
|
@ -5,28 +5,14 @@
|
||||||
|
|
||||||
module Orbit where
|
module Orbit where
|
||||||
|
|
||||||
import Data.Set (Set)
|
import Support (Support, Rat(..))
|
||||||
import qualified Data.Set as Set
|
import qualified Support
|
||||||
|
|
||||||
-- TODO: Make generic instances (we already have sums and products)
|
-- TODO: Make generic instances (we already have sums and products)
|
||||||
-- TODO: For products: replace [Ordering] with Vec Ordering if better
|
-- TODO: For products: replace [Ordering] with Vec Ordering if better
|
||||||
-- TODO: replace Support by an ordered vector / list for speed?
|
-- TODO: replace Support by an ordered vector / list for speed?
|
||||||
|
|
||||||
|
|
||||||
-- We take some model of the dense linear order. The rationals are a natural
|
|
||||||
-- choice. (Note that every countable model is order-isomorphic, so it doesn't
|
|
||||||
-- matter so much in the end.) I wrap it in a newtype, so we will only use the
|
|
||||||
-- Ord instances, and because it's not very nice to work with type synonyms.
|
|
||||||
-- Show instance included for debugging.
|
|
||||||
newtype Rat = Rat { unRat :: Rational }
|
|
||||||
deriving (Eq, Ord, Show)
|
|
||||||
|
|
||||||
|
|
||||||
-- A support is a set of rational numbers, which can always be ordered. Can
|
|
||||||
-- also be represented as sorted list/vector. Maybe I should also make it into
|
|
||||||
-- a newtype.
|
|
||||||
type Support = Set Rat
|
|
||||||
|
|
||||||
-- This is the main meat of the package. The Orbit typeclass, it gives us ways
|
-- This is the main meat of the package. The Orbit typeclass, it gives us ways
|
||||||
-- to manipulate nominal elements in sets and maps. The type class has
|
-- to manipulate nominal elements in sets and maps. The type class has
|
||||||
-- associated data to represent an orbit of type a. This is often much easier
|
-- associated data to represent an orbit of type a. This is often much easier
|
||||||
|
@ -48,7 +34,7 @@ class Orbit a where
|
||||||
|
|
||||||
-- We can get 'default' values, if we don't care about the support.
|
-- We can get 'default' values, if we don't care about the support.
|
||||||
getElementE :: Orbit a => Orb a -> a
|
getElementE :: Orbit a => Orb a -> a
|
||||||
getElementE orb = getElement orb (Set.fromAscList . fmap (Rat . toRational) $ [1 .. index orb])
|
getElementE orb = getElement orb (Support.def (index orb))
|
||||||
|
|
||||||
|
|
||||||
-- We can construct orbits from rational numbers. There is exactly one orbit,
|
-- We can construct orbits from rational numbers. There is exactly one orbit,
|
||||||
|
@ -56,10 +42,8 @@ getElementE orb = getElement orb (Set.fromAscList . fmap (Rat . toRational) $ [1
|
||||||
instance Orbit Rat where
|
instance Orbit Rat where
|
||||||
data Orb Rat = OrbRational
|
data Orb Rat = OrbRational
|
||||||
toOrbit _ = OrbRational
|
toOrbit _ = OrbRational
|
||||||
support r = Set.singleton r
|
support r = Support.singleton r
|
||||||
getElement _ s
|
getElement _ s = Support.min s
|
||||||
| Set.null s = undefined
|
|
||||||
| otherwise = Set.findMin s
|
|
||||||
index _ = 1
|
index _ = 1
|
||||||
|
|
||||||
deriving instance Show (Orb Rat)
|
deriving instance Show (Orb Rat)
|
||||||
|
@ -74,7 +58,7 @@ deriving instance Ord (Orb Rat)
|
||||||
-- completely specified by an integer.
|
-- completely specified by an integer.
|
||||||
instance Orbit Support where
|
instance Orbit Support where
|
||||||
newtype Orb Support = OrbSupport Int
|
newtype Orb Support = OrbSupport Int
|
||||||
toOrbit s = OrbSupport (Set.size s)
|
toOrbit s = OrbSupport (Support.size s)
|
||||||
support s = s
|
support s = s
|
||||||
getElement _ s = s
|
getElement _ s = s
|
||||||
index (OrbSupport n) = n
|
index (OrbSupport n) = n
|
||||||
|
@ -109,19 +93,19 @@ instance (Orbit a, Orbit b) => Orbit (a, b) where
|
||||||
data Orb (a,b) = OrbPair !(Orb a) !(Orb b) ![Ordering]
|
data Orb (a,b) = OrbPair !(Orb a) !(Orb b) ![Ordering]
|
||||||
toOrbit (a, b) = OrbPair (toOrbit a) (toOrbit b) (bla sa sb)
|
toOrbit (a, b) = OrbPair (toOrbit a) (toOrbit b) (bla sa sb)
|
||||||
where
|
where
|
||||||
sa = Set.toAscList $ support a
|
sa = Support.toList $ support a
|
||||||
sb = Set.toAscList $ support b
|
sb = Support.toList $ support b
|
||||||
bla [] ys = fmap (const GT) ys
|
bla [] ys = fmap (const GT) ys
|
||||||
bla xs [] = fmap (const LT) xs
|
bla xs [] = fmap (const LT) xs
|
||||||
bla (x:xs) (y:ys) = case compare x y of
|
bla (x:xs) (y:ys) = case compare x y of
|
||||||
LT -> LT : (bla xs (y:ys))
|
LT -> LT : (bla xs (y:ys))
|
||||||
EQ -> EQ : (bla xs ys)
|
EQ -> EQ : (bla xs ys)
|
||||||
GT -> GT : (bla (x:xs) ys)
|
GT -> GT : (bla (x:xs) ys)
|
||||||
support (a, b) = Set.union (support a) (support b)
|
support (a, b) = Support.union (support a) (support b)
|
||||||
getElement (OrbPair oa ob l) s = (getElement oa $ toSet ls, getElement ob $ toSet rs)
|
getElement (OrbPair oa ob l) s = (getElement oa $ toSet ls, getElement ob $ toSet rs)
|
||||||
where
|
where
|
||||||
(ls, rs) = partitionOrd fst . zip l . Set.toAscList $ s
|
(ls, rs) = partitionOrd fst . zip l . Support.toList $ s
|
||||||
toSet = Set.fromAscList . fmap snd
|
toSet = Support.fromDistinctAscList . fmap snd
|
||||||
index (OrbPair _ _ l) = length l
|
index (OrbPair _ _ l) = length l
|
||||||
|
|
||||||
deriving instance (Show (Orb a), Show (Orb b)) => Show (Orb (a, b))
|
deriving instance (Show (Orb a), Show (Orb b)) => Show (Orb (a, b))
|
||||||
|
@ -143,6 +127,7 @@ selectOrd f x ~(ls, rs) = case f x of
|
||||||
product :: (Orbit a, Orbit b) => Orb a -> Orb b -> [Orb (a, b)]
|
product :: (Orbit a, Orbit b) => Orb a -> Orb b -> [Orb (a, b)]
|
||||||
product oa ob = OrbPair oa ob <$> prodStrings (index oa) (index ob)
|
product oa ob = OrbPair oa ob <$> prodStrings (index oa) (index ob)
|
||||||
|
|
||||||
|
-- I tried Seq [Ordering], it was slower
|
||||||
prodStrings :: Int -> Int -> [[Ordering]]
|
prodStrings :: Int -> Int -> [[Ordering]]
|
||||||
prodStrings 0 0 = [[]]
|
prodStrings 0 0 = [[]]
|
||||||
prodStrings 0 n = [replicate n GT]
|
prodStrings 0 n = [replicate n GT]
|
||||||
|
@ -161,7 +146,7 @@ newtype Trivial a = Trivial { unTrivial :: a }
|
||||||
instance Orbit (Trivial a) where
|
instance Orbit (Trivial a) where
|
||||||
newtype Orb (Trivial a) = OrbTrivial a
|
newtype Orb (Trivial a) = OrbTrivial a
|
||||||
toOrbit (Trivial a) = OrbTrivial a
|
toOrbit (Trivial a) = OrbTrivial a
|
||||||
support _ = Set.empty
|
support _ = Support.empty
|
||||||
getElement (OrbTrivial a) _ = Trivial a
|
getElement (OrbTrivial a) _ = Trivial a
|
||||||
index _ = 0
|
index _ = 0
|
||||||
|
|
||||||
|
@ -174,7 +159,7 @@ deriving instance Ord a => Ord (Orb (Trivial a))
|
||||||
instance Orbit a => Orbit (Orb a) where
|
instance Orbit a => Orbit (Orb a) where
|
||||||
newtype Orb (Orb a) = OrbOrb (Orb a)
|
newtype Orb (Orb a) = OrbOrb (Orb a)
|
||||||
toOrbit a = OrbOrb a
|
toOrbit a = OrbOrb a
|
||||||
support _ = Set.empty
|
support _ = Support.empty
|
||||||
getElement (OrbOrb oa) _ = oa
|
getElement (OrbOrb oa) _ = oa
|
||||||
index _ = 0
|
index _ = 0
|
||||||
|
|
||||||
|
|
85
src/Support.hs
Normal file
85
src/Support.hs
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
{-# LANGUAGE DeriveGeneric #-}
|
||||||
|
|
||||||
|
module Support where
|
||||||
|
|
||||||
|
import qualified Data.List as List
|
||||||
|
import qualified Data.List.Ordered as OrdList
|
||||||
|
import GHC.Generics (Generic)
|
||||||
|
|
||||||
|
|
||||||
|
-- We take some model of the dense linear order. The rationals are a natural
|
||||||
|
-- choice. (Note that every countable model is order-isomorphic, so it doesn't
|
||||||
|
-- matter so much in the end.) I wrap it in a newtype, so we will only use the
|
||||||
|
-- Ord instances, and because it's not very nice to work with type synonyms.
|
||||||
|
-- Show instance included for debugging.
|
||||||
|
newtype Rat = Rat { unRat :: Rational }
|
||||||
|
deriving (Eq, Ord, Show, Generic)
|
||||||
|
|
||||||
|
-- A support is a set of rational numbers, which can always be ordered. I tried
|
||||||
|
-- an implementation using Data.Set, it was slower. We could also use Vectors?
|
||||||
|
-- Note that a sorted list makes sense in many cases, since we do not really
|
||||||
|
-- need membership queries on this type. Maybe make this into a newtype.
|
||||||
|
type Support = [Rat] -- always sorted
|
||||||
|
|
||||||
|
size :: Support -> Int
|
||||||
|
size = List.length
|
||||||
|
|
||||||
|
null :: Support -> Bool
|
||||||
|
null = List.null
|
||||||
|
|
||||||
|
min :: Support -> Rat
|
||||||
|
min = List.head
|
||||||
|
|
||||||
|
empty :: Support
|
||||||
|
empty = []
|
||||||
|
|
||||||
|
union :: Support -> Support -> Support
|
||||||
|
union = OrdList.union
|
||||||
|
|
||||||
|
singleton :: Rat -> Support
|
||||||
|
singleton r = [r]
|
||||||
|
|
||||||
|
toList :: Support -> Support
|
||||||
|
toList = id
|
||||||
|
|
||||||
|
fromList, fromAscList, fromDistinctAscList :: [Rat] -> Support
|
||||||
|
fromList = OrdList.nubSort
|
||||||
|
fromAscList = OrdList.nub
|
||||||
|
fromDistinctAscList = id
|
||||||
|
|
||||||
|
def :: Int -> Support
|
||||||
|
def n = fromDistinctAscList . fmap (Rat . toRational) $ [1..n]
|
||||||
|
|
||||||
|
{-
|
||||||
|
-- The Data.Set implementation
|
||||||
|
import Data.Set (Set)
|
||||||
|
import qualified Data.Set as Set
|
||||||
|
|
||||||
|
type Support = Set Rat
|
||||||
|
|
||||||
|
size :: Support -> Int
|
||||||
|
size = Set.size
|
||||||
|
|
||||||
|
null :: Support -> Bool
|
||||||
|
null = Set.null
|
||||||
|
|
||||||
|
min :: Support -> Rat
|
||||||
|
min = Set.findMin
|
||||||
|
|
||||||
|
empty :: Support
|
||||||
|
empty = Set.empty
|
||||||
|
|
||||||
|
union :: Support -> Support -> Support
|
||||||
|
union = Set.union
|
||||||
|
|
||||||
|
singleton :: Rat -> Support
|
||||||
|
singleton = Set.singleton
|
||||||
|
|
||||||
|
toList :: Support -> [Rat]
|
||||||
|
toList = Set.toAscList
|
||||||
|
|
||||||
|
fromList, fromAscList, fromDistinctAscList :: [Rat] -> Support
|
||||||
|
fromList = Set.fromList
|
||||||
|
fromAscList = Set.fromAscList
|
||||||
|
fromDistinctAscList = Set.fromDistinctAscList
|
||||||
|
-}
|
50
test/Bench.hs
Normal file
50
test/Bench.hs
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
{-# LANGUAGE PartialTypeSignatures #-}
|
||||||
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
|
{-# OPTIONS_GHC -Wno-partial-type-signatures #-}
|
||||||
|
|
||||||
|
import Control.DeepSeq
|
||||||
|
import Criterion.Main
|
||||||
|
|
||||||
|
import Orbit
|
||||||
|
import Support
|
||||||
|
import EquivariantSet
|
||||||
|
import EquivariantMap
|
||||||
|
|
||||||
|
instance NFData Rat
|
||||||
|
|
||||||
|
(\/) :: Ord (Orb a) => EquivariantSet a -> EquivariantSet a -> EquivariantSet a
|
||||||
|
(\/) = EquivariantSet.union
|
||||||
|
|
||||||
|
bigset :: (Rat, Rat, Rat, _) -> Bool
|
||||||
|
bigset (p, q, r, t) = EquivariantSet.member t s where
|
||||||
|
s1 = singleOrbit ((p, p), p) \/ singleOrbit ((p, p), q) \/ singleOrbit ((p, q), r)
|
||||||
|
s2 = singleOrbit (p, q) \/ singleOrbit (q, r) \/ singleOrbit (r, p)
|
||||||
|
s = EquivariantSet.product s1 s2
|
||||||
|
|
||||||
|
bigmap :: (Rat, Rat, _) -> Maybe (Rat, (Rat, Rat))
|
||||||
|
bigmap (p, q, t) = EquivariantMap.lookup t m3 where
|
||||||
|
s = EquivariantSet.product (EquivariantSet.singleOrbit (p, q)) (EquivariantSet.singleOrbit (q, p))
|
||||||
|
s2 = EquivariantSet.product s s
|
||||||
|
s3 = EquivariantSet.map (\((a, b), (c, d)) -> ((b, a), (d, c))) s2
|
||||||
|
m1 = EquivariantMap.fromSet (\(((a, b), (c, d)), ((e, f), (g, h))) -> (b,(d,h))) s2
|
||||||
|
m2 = EquivariantMap.fromSet (\(((a, b), (c, d)), ((e, f), (g, h))) -> (b,(d,h))) s3
|
||||||
|
m3 = EquivariantMap.unionWith const m1 m2
|
||||||
|
|
||||||
|
main :: IO ()
|
||||||
|
main = defaultMain
|
||||||
|
-- ~ 300 ms
|
||||||
|
[ bgroup "bigmap"
|
||||||
|
[ bench "1 y" $ nf bigmap (Rat 1, Rat 2, (((Rat 1, Rat 23), (Rat 5, Rat 4)), ((Rat 2, Rat 3), (Rat 54, Rat 43)))) -- found
|
||||||
|
, bench "2 n" $ nf bigmap (Rat 1, Rat 2, (((Rat 1, Rat 23), (Rat 5, Rat 4)), ((Rat 2, Rat 3), (Rat 54, Rat 65)))) -- not found
|
||||||
|
, bench "3 y" $ nf bigmap (Rat 1, Rat 2, (((Rat 1, Rat 100), (Rat 90, Rat 20)), ((Rat 30, Rat 80), (Rat 70, Rat 65)))) -- found
|
||||||
|
, bench "4 y" $ nf bigmap (Rat 1, Rat 2, (((Rat 1, Rat 100), (Rat 100, Rat 1)), ((Rat 1, Rat 100), (Rat 100, Rat 1)))) -- found
|
||||||
|
, bench "5 y" $ nf bigmap (Rat 1, Rat 2, (((Rat 100, Rat 1), (Rat 1, Rat 100)), ((Rat 200, Rat 2), (Rat 2, Rat 200)))) -- found
|
||||||
|
]
|
||||||
|
-- ~ 13 us
|
||||||
|
, bgroup "bigset"
|
||||||
|
[ bench "1 y" $ nf bigset (Rat 1, Rat 2, Rat 3, ( ((Rat 1, Rat 1), Rat 1), (Rat 1, Rat 2) )) -- found
|
||||||
|
, bench "2 y" $ nf bigset (Rat 1, Rat 2, Rat 3, ( ((Rat 37, Rat 37), Rat 42), (Rat 1, Rat 2) )) -- found
|
||||||
|
, bench "3 n" $ nf bigset (Rat 1, Rat 2, Rat 3, ( ((Rat 37, Rat 31), Rat 42), (Rat 1, Rat 2) )) -- not found
|
||||||
|
, bench "4 y" $ nf bigset (Rat 1, Rat 2, Rat 3, ( ((Rat 1, Rat 2), Rat 3), (Rat 5, Rat 4) )) -- found
|
||||||
|
]
|
||||||
|
]
|
68
test/Spec.hs
68
test/Spec.hs
|
@ -1,2 +1,68 @@
|
||||||
|
{-# LANGUAGE PartialTypeSignatures #-}
|
||||||
|
{-# OPTIONS_GHC -Wno-partial-type-signatures #-}
|
||||||
|
|
||||||
|
-- TODO: QuickCheck instead of these unit tests
|
||||||
|
|
||||||
|
import GHC.Stack
|
||||||
|
|
||||||
|
import Data.Maybe (isJust, isNothing)
|
||||||
|
import Prelude (id, const, not, ($), error, return, Bool(..), IO(..), print, (>>=))
|
||||||
|
import qualified Prelude as P -- hide stuff
|
||||||
|
|
||||||
|
import Support (Rat(..))
|
||||||
|
import EquivariantSet (product, member, singleOrbit, union, map, isSubsetOf)
|
||||||
|
import EquivariantMap (unionWith, lookup, fromSet)
|
||||||
|
|
||||||
|
assert :: (a -> Bool) -> a -> IO ()
|
||||||
|
assert f x = case f x of
|
||||||
|
True -> return ()
|
||||||
|
False -> whoCreated x >>= print
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = putStrLn "Test suite not yet implemented"
|
main = do
|
||||||
|
let p = Rat 1
|
||||||
|
let q = Rat 2
|
||||||
|
let s = product (singleOrbit (p, q)) (singleOrbit (q, p))
|
||||||
|
assert id $ member ((Rat 1, Rat 2), (Rat 5, Rat 4)) s
|
||||||
|
assert not $ member ((Rat 5, Rat 2), (Rat 5, Rat 4)) s
|
||||||
|
assert id $ member ((Rat 1, Rat 2), (Rat 2, Rat 1)) s
|
||||||
|
assert id $ member ((Rat 3, Rat 4), (Rat 2, Rat 1)) s
|
||||||
|
|
||||||
|
let s2 = product s s
|
||||||
|
assert id $ member (((Rat 1, Rat 2), (Rat 5, Rat 4)), ((Rat 1, Rat 2), (Rat 5, Rat 4))) s2
|
||||||
|
assert id $ member (((Rat 1, Rat 2), (Rat 5, Rat 4)), ((Rat 1, Rat 2), (Rat 5, Rat 1))) s2
|
||||||
|
assert id $ member (((Rat 1, Rat 2), (Rat 5, Rat 4)), ((Rat 1, Rat 200), (Rat 5, Rat 1))) s2
|
||||||
|
assert id $ member (((Rat 0, Rat 27), (Rat 5, Rat 4)), ((Rat 1, Rat 200), (Rat 5, Rat 1))) s2
|
||||||
|
assert not $ member (((Rat 0, Rat 27), (Rat 5, Rat 4)), ((Rat 1, Rat 200), (Rat 5, Rat 5))) s2
|
||||||
|
|
||||||
|
let s3 = map (\((a, b), (c, d)) -> ((b, a), (d, c))) s2
|
||||||
|
assert id $ member (((Rat 5, Rat 4), (Rat 1, Rat 2)), ((Rat 5, Rat 4), (Rat 1, Rat 2))) s3
|
||||||
|
assert id $ member (((Rat 2, Rat 1), (Rat 4, Rat 5)), ((Rat 2, Rat 1), (Rat 4, Rat 5))) s3
|
||||||
|
|
||||||
|
let m1 = fromSet (\(((a, b), (c, d)), ((e, f), (g, h))) -> (b,(d,h))) s2
|
||||||
|
assert isJust $ lookup (((Rat 1, Rat 2), (Rat 2, Rat 1)), ((Rat 1, Rat 2), (Rat 3, Rat 2))) m1
|
||||||
|
assert isNothing $ lookup (((Rat 1, Rat 2), (Rat 2, Rat 1)), ((Rat 1, Rat 2), (Rat 1, Rat 2))) m1
|
||||||
|
|
||||||
|
let m2 = fromSet (\(((a, b), (c, d)), ((e, f), (g, h))) -> (b,(d,h))) s3
|
||||||
|
assert isJust $ lookup (((Rat 6, Rat 1), (Rat 1, Rat 5)), ((Rat 4, Rat 1), (Rat 1, Rat 3))) m2
|
||||||
|
assert isNothing $ lookup (((Rat 1, Rat 2), (Rat 2, Rat 1)), ((Rat 1, Rat 2), (Rat 4, Rat 2))) m2
|
||||||
|
|
||||||
|
let m3 = unionWith const m1 m2
|
||||||
|
assert isJust $ lookup (((Rat 1, Rat 23), (Rat 5, Rat 4)), ((Rat 2, Rat 3), (Rat 54, Rat 43))) m3
|
||||||
|
assert isNothing $ lookup (((Rat 1, Rat 23), (Rat 5, Rat 4)), ((Rat 2, Rat 3), (Rat 54, Rat 65))) m3
|
||||||
|
assert isJust $ lookup (((Rat 1, Rat 100), (Rat 90, Rat 20)), ((Rat 30, Rat 80), (Rat 70, Rat 65))) m3
|
||||||
|
assert isJust $ lookup (((Rat 1, Rat 100), (Rat 100, Rat 1)), ((Rat 1, Rat 100), (Rat 100, Rat 1))) m3
|
||||||
|
assert isJust $ lookup (((Rat 100, Rat 1), (Rat 1, Rat 100)), ((Rat 200, Rat 2), (Rat 2, Rat 200))) m3
|
||||||
|
|
||||||
|
let r = Rat 3
|
||||||
|
let s1 = singleOrbit ((p, p), p) `union` singleOrbit ((p, p), q) `union` singleOrbit ((p, q), r)
|
||||||
|
let s2 = singleOrbit (p, q) `union` singleOrbit (q, r) `union` singleOrbit (r, p)
|
||||||
|
assert id $ s2 `isSubsetOf` product (singleOrbit p) (singleOrbit p)
|
||||||
|
assert not $ product (singleOrbit p) (singleOrbit p) `isSubsetOf` s2
|
||||||
|
|
||||||
|
let s = product s1 s2
|
||||||
|
assert id $ member ( ((Rat 1, Rat 1), Rat 1), (Rat 1, Rat 2) ) s
|
||||||
|
assert id $ member ( ((Rat 37, Rat 37), Rat 42), (Rat 1, Rat 2) ) s
|
||||||
|
assert not $ member ( ((Rat 37, Rat 31), Rat 42), (Rat 1, Rat 2) ) s
|
||||||
|
assert id $ member ( ((Rat 1, Rat 2), Rat 3), (Rat 5, Rat 4) ) s
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue