mirror of
https://github.com/Jaxan/ons-hs.git
synced 2025-04-27 14:47:45 +02:00
Cleaned up project a little bit
This commit is contained in:
parent
b39ba8b5d5
commit
83f6025acf
27 changed files with 252 additions and 262 deletions
|
@ -114,6 +114,11 @@ values, that can be much faster.
|
||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
|
version 0.4 (2024-11-11):
|
||||||
|
* Changed from rational number to integers (for performance).
|
||||||
|
* Cleaned up module structure and API.
|
||||||
|
* Started writing some haddock.
|
||||||
|
|
||||||
version 0.3.1.0 (2024-11-06):
|
version 0.3.1.0 (2024-11-06):
|
||||||
* More types of products
|
* More types of products
|
||||||
* Stuff to do permutations (not only monotone ones)
|
* Stuff to do permutations (not only monotone ones)
|
||||||
|
|
|
@ -17,9 +17,9 @@ import Text.Megaparsec.Char as P
|
||||||
import qualified Text.Megaparsec.Char.Lexer as L
|
import qualified Text.Megaparsec.Char.Lexer as L
|
||||||
|
|
||||||
import OrbitList
|
import OrbitList
|
||||||
import Nominal (Atom)
|
import Nominal
|
||||||
import Nominal.Class
|
import Nominal.Class
|
||||||
import Support (Support, def)
|
import Nominal.Support (def)
|
||||||
import Automata
|
import Automata
|
||||||
import qualified EquivariantSet as Set
|
import qualified EquivariantSet as Set
|
||||||
import qualified EquivariantMap as Map
|
import qualified EquivariantMap as Map
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{-# LANGUAGE PatternSynonyms #-}
|
{-# LANGUAGE PatternSynonyms #-}
|
||||||
|
|
||||||
import OrbitList hiding (head)
|
import OrbitList hiding (head)
|
||||||
import Support (Rat)
|
import Nominal
|
||||||
|
|
||||||
import Prelude (Show, Ord, Eq, Int, IO, print, otherwise, (.), ($), (!!), (+), (-), Bool, head, tail)
|
import Prelude (Show, Ord, Eq, Int, IO, print, otherwise, (.), ($), (!!), (+), (-), Bool, head, tail)
|
||||||
import qualified Prelude as P
|
import qualified Prelude as P
|
||||||
|
@ -81,7 +81,7 @@ forAll p = not (exists (not p))
|
||||||
|
|
||||||
-- Here is the solver. It keeps track of a nominal set.
|
-- Here is the solver. It keeps track of a nominal set.
|
||||||
-- If that sets is empty in the end, the formula does not hold.
|
-- If that sets is empty in the end, the formula does not hold.
|
||||||
type Context = SortedOrbitList [Rat]
|
type Context = SortedOrbitList [Atom]
|
||||||
|
|
||||||
extend, drop :: Context -> Context
|
extend, drop :: Context -> Context
|
||||||
extend ctx = productWith (:) rationals ctx
|
extend ctx = productWith (:) rationals ctx
|
||||||
|
|
18
app/IO.hs
18
app/IO.hs
|
@ -6,11 +6,11 @@ import Data.Char (isSpace)
|
||||||
import Data.Ratio
|
import Data.Ratio
|
||||||
import Data.List (intersperse)
|
import Data.List (intersperse)
|
||||||
|
|
||||||
import Nominal
|
|
||||||
import Automata
|
import Automata
|
||||||
import Support (Rat(..), Support(..))
|
|
||||||
import OrbitList as L (toList)
|
|
||||||
import EquivariantMap as M (toList)
|
import EquivariantMap as M (toList)
|
||||||
|
import Nominal
|
||||||
|
import Nominal.Support as Support
|
||||||
|
import OrbitList as L (toList)
|
||||||
|
|
||||||
|
|
||||||
-- I do not want to give weird Show instances for basic types, so I create my
|
-- I do not want to give weird Show instances for basic types, so I create my
|
||||||
|
@ -20,13 +20,11 @@ class FromStr a where fromStr :: String -> (a, String)
|
||||||
|
|
||||||
-- Should always print integers, this is not a problem for the things we build
|
-- Should always print integers, this is not a problem for the things we build
|
||||||
-- from getElementE (since it returns elements with support from 1 to n).
|
-- from getElementE (since it returns elements with support from 1 to n).
|
||||||
instance ToStr Rat where
|
instance ToStr Atom where
|
||||||
toStr (Rat r) = case denominator r of
|
toStr = show
|
||||||
1 -> show (numerator r)
|
|
||||||
_ -> error "Can only show integers"
|
|
||||||
|
|
||||||
instance ToStr Support where
|
instance ToStr Support where
|
||||||
toStr (Support s) = "{" ++ toStr s ++ "}"
|
toStr s = "{" ++ toStr (Support.toList s) ++ "}"
|
||||||
|
|
||||||
instance ToStr Bool where toStr b = show b
|
instance ToStr Bool where toStr b = show b
|
||||||
instance ToStr Int where toStr i = show i
|
instance ToStr Int where toStr i = show i
|
||||||
|
@ -46,8 +44,8 @@ instance (Nominal q, Nominal a, ToStr q, ToStr a) => ToStr (Automaton q a) where
|
||||||
", acceptance = " ++ toStr (M.toList acceptance) ++
|
", acceptance = " ++ toStr (M.toList acceptance) ++
|
||||||
", transition = " ++ toStr (M.toList transition) ++ " }"
|
", transition = " ++ toStr (M.toList transition) ++ " }"
|
||||||
|
|
||||||
instance FromStr Rat where
|
instance FromStr Atom where
|
||||||
fromStr str = (Rat (read l % 1), r)
|
fromStr str = (atom (read l), r)
|
||||||
where (l, r) = break isSpace str
|
where (l, r) = break isSpace str
|
||||||
|
|
||||||
instance FromStr a => FromStr [a] where
|
instance FromStr a => FromStr [a] where
|
||||||
|
|
|
@ -6,20 +6,19 @@
|
||||||
{-# language UndecidableInstances #-}
|
{-# language UndecidableInstances #-}
|
||||||
{-# OPTIONS_GHC -Wno-partial-type-signatures #-}
|
{-# OPTIONS_GHC -Wno-partial-type-signatures #-}
|
||||||
|
|
||||||
|
import EquivariantMap ((!))
|
||||||
import ExampleAutomata
|
import ExampleAutomata
|
||||||
import FileAutomata
|
import FileAutomata
|
||||||
import IO
|
import IO
|
||||||
import Quotient
|
|
||||||
import OrbitList
|
import OrbitList
|
||||||
import EquivariantMap ((!))
|
import Quotient
|
||||||
import qualified EquivariantMap as Map
|
import qualified EquivariantMap as Map
|
||||||
import qualified EquivariantSet as Set
|
import qualified EquivariantSet as Set
|
||||||
|
|
||||||
|
import Prelude as P hiding (map, product, words, filter, foldr)
|
||||||
import System.Environment
|
import System.Environment
|
||||||
import System.IO
|
import System.IO
|
||||||
|
|
||||||
import Prelude as P hiding (map, product, words, filter, foldr)
|
|
||||||
|
|
||||||
|
|
||||||
-- Version A: works on equivalence relations
|
-- Version A: works on equivalence relations
|
||||||
minimiseA :: _ => OrbitList a -> Automaton q a -> Automaton _ a
|
minimiseA :: _ => OrbitList a -> Automaton q a -> Automaton _ a
|
||||||
|
|
|
@ -11,7 +11,6 @@ import ExampleAutomata
|
||||||
import IO
|
import IO
|
||||||
import Nominal (Atom)
|
import Nominal (Atom)
|
||||||
import OrbitList qualified
|
import OrbitList qualified
|
||||||
import Support (Rat (..))
|
|
||||||
|
|
||||||
data Example
|
data Example
|
||||||
= Fifo Int
|
= Fifo Int
|
||||||
|
@ -19,7 +18,7 @@ data Example
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main =
|
main =
|
||||||
let ex = Fifo 2
|
let ex = DoubleWord 2
|
||||||
in case ex of
|
in case ex of
|
||||||
Fifo n -> teach "FIFO" (fifoFun n) (fifoCex n)
|
Fifo n -> teach "FIFO" (fifoFun n) (fifoCex n)
|
||||||
DoubleWord n -> teach "ATOMS" (doubleFun n) (doubleCex n)
|
DoubleWord n -> teach "ATOMS" (doubleFun n) (doubleCex n)
|
||||||
|
|
10
ons-hs.cabal
10
ons-hs.cabal
|
@ -1,6 +1,6 @@
|
||||||
cabal-version: 2.2
|
cabal-version: 2.2
|
||||||
name: ons-hs
|
name: ons-hs
|
||||||
version: 0.3.1.0
|
version: 0.4.0.0-dev
|
||||||
synopsis: Implementation of the ONS (Ordered Nominal Sets) library in Haskell
|
synopsis: Implementation of the ONS (Ordered Nominal Sets) library in Haskell
|
||||||
description: Nominal sets are structured infinite sets. They have symmetries which make them finitely representable. This library provides basic manipulation of them for the total order symmetry. It includes: products, sums, maps and sets. Can work with custom data types.
|
description: Nominal sets are structured infinite sets. They have symmetries which make them finitely representable. This library provides basic manipulation of them for the total order symmetry. It includes: products, sums, maps and sets. Can work with custom data types.
|
||||||
homepage: https://github.com/Jaxan/ons-hs
|
homepage: https://github.com/Jaxan/ons-hs
|
||||||
|
@ -26,15 +26,13 @@ library
|
||||||
EquivariantMap,
|
EquivariantMap,
|
||||||
EquivariantSet,
|
EquivariantSet,
|
||||||
Nominal,
|
Nominal,
|
||||||
|
Nominal.Atom,
|
||||||
Nominal.Class,
|
Nominal.Class,
|
||||||
Nominal.Products,
|
Nominal.Products,
|
||||||
|
Nominal.Support,
|
||||||
OrbitList,
|
OrbitList,
|
||||||
Permutable,
|
Permutable,
|
||||||
Quotient,
|
Quotient
|
||||||
Support,
|
|
||||||
Support.OrdList,
|
|
||||||
Support.Rat,
|
|
||||||
Support.Set
|
|
||||||
build-depends:
|
build-depends:
|
||||||
data-ordlist,
|
data-ordlist,
|
||||||
MemoTrie
|
MemoTrie
|
||||||
|
|
|
@ -1,20 +1,21 @@
|
||||||
{-# LANGUAGE DerivingVia #-}
|
{-# LANGUAGE DerivingVia #-}
|
||||||
{-# LANGUAGE FlexibleContexts #-}
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
|
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
|
||||||
|
{-# LANGUAGE ImportQualifiedPost #-}
|
||||||
{-# LANGUAGE ScopedTypeVariables #-}
|
{-# LANGUAGE ScopedTypeVariables #-}
|
||||||
{-# LANGUAGE StandaloneDeriving #-}
|
{-# LANGUAGE StandaloneDeriving #-}
|
||||||
{-# LANGUAGE UndecidableInstances #-}
|
{-# LANGUAGE UndecidableInstances #-}
|
||||||
|
|
||||||
module EquivariantMap where
|
module EquivariantMap where
|
||||||
|
|
||||||
import Data.Semigroup (Semigroup)
|
|
||||||
import Data.Map (Map)
|
import Data.Map (Map)
|
||||||
import qualified Data.Map as Map
|
import Data.Map qualified as Map
|
||||||
import Data.Maybe (fromMaybe)
|
import Data.Maybe (fromMaybe)
|
||||||
|
import Data.Semigroup (Semigroup)
|
||||||
|
|
||||||
import EquivariantSet (EquivariantSet(..))
|
import EquivariantSet (EquivariantSet(..))
|
||||||
import Nominal
|
import Nominal
|
||||||
import Support
|
import Nominal.Support as Support
|
||||||
|
|
||||||
|
|
||||||
-- TODO: foldable / traversable
|
-- TODO: foldable / traversable
|
||||||
|
@ -135,7 +136,7 @@ filter p (EqMap m) = EqMap (Map.filterWithKey p2 m)
|
||||||
mapel :: (Nominal k, Nominal v) => k -> v -> (Orbit v, [Bool])
|
mapel :: (Nominal k, Nominal v) => k -> v -> (Orbit v, [Bool])
|
||||||
mapel k v = (toOrbit v, bv (Support.toList (support k)) (Support.toList (support v)))
|
mapel k v = (toOrbit v, bv (Support.toList (support k)) (Support.toList (support v)))
|
||||||
|
|
||||||
bv :: [Rat] -> [Rat] -> [Bool]
|
bv :: [Atom] -> [Atom] -> [Bool]
|
||||||
bv l [] = replicate (length l) False
|
bv l [] = replicate (length l) False
|
||||||
bv [] _ = error "Non-equivariant function"
|
bv [] _ = error "Non-equivariant function"
|
||||||
bv (x:xs) (y:ys) = case compare x y of
|
bv (x:xs) (y:ys) = case compare x y of
|
||||||
|
@ -144,5 +145,5 @@ bv (x:xs) (y:ys) = case compare x y of
|
||||||
GT -> error "Non-equivariant function"
|
GT -> error "Non-equivariant function"
|
||||||
|
|
||||||
mapelInv :: (Nominal k, Nominal v) => k -> (Orbit v, [Bool]) -> v
|
mapelInv :: (Nominal k, Nominal v) => k -> (Orbit v, [Bool]) -> v
|
||||||
mapelInv x (oy, bs) = getElement oy (Support.fromDistinctAscList . fmap fst . Prelude.filter snd $ zip (Support.toList (support x)) bs)
|
mapelInv x (oy, bs) = getElement oy (fromDistinctAscList . fmap fst . Prelude.filter snd $ zip (Support.toList (support x)) bs)
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ import qualified Data.Set as Set
|
||||||
import Prelude hiding (map, product)
|
import Prelude hiding (map, product)
|
||||||
|
|
||||||
import Nominal
|
import Nominal
|
||||||
|
import Nominal.Products as Nominal
|
||||||
import OrbitList (OrbitList(..))
|
import OrbitList (OrbitList(..))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,54 +1,33 @@
|
||||||
{-# LANGUAGE ScopedTypeVariables #-}
|
{-# LANGUAGE ScopedTypeVariables #-}
|
||||||
|
|
||||||
module Nominal
|
module Nominal (
|
||||||
( module Nominal
|
-- * Atoms
|
||||||
, module Nominal.Class
|
-- | Re-exports from "Nominal.Atom".
|
||||||
) where
|
Atom,
|
||||||
|
atom,
|
||||||
|
-- * Support
|
||||||
|
-- | Re-exports from "Nominal.Support".
|
||||||
|
Support,
|
||||||
|
-- * The Nominal type class
|
||||||
|
Nominal (..),
|
||||||
|
Trivially (..),
|
||||||
|
Generically (..),
|
||||||
|
-- * Helper functions
|
||||||
|
module Nominal,
|
||||||
|
) where
|
||||||
|
|
||||||
import Data.Proxy
|
import Data.Proxy
|
||||||
|
|
||||||
import Nominal.Products
|
import Nominal.Atom
|
||||||
import Nominal.Class
|
import Nominal.Class
|
||||||
import Support (Rat, def)
|
import Nominal.Products
|
||||||
|
import Nominal.Support
|
||||||
|
|
||||||
type Atom = Rat
|
-- | We can construct a "default" element from an orbit. In this case, the
|
||||||
|
-- support is chosen arbitrarily.
|
||||||
-- We can get 'default' values, if we don't care about the support.
|
|
||||||
getElementE :: forall a. Nominal a => Orbit a -> a
|
getElementE :: forall a. Nominal a => Orbit a -> a
|
||||||
getElementE orb = getElement orb (def (index (Proxy :: Proxy a) orb))
|
getElementE orb = getElement orb (def (index (Proxy :: Proxy a) orb))
|
||||||
|
|
||||||
-- We can `map` orbits to orbits for equivariant functions
|
-- | We can `map` orbits to orbits for equivariant functions.
|
||||||
omap :: (Nominal a, Nominal b) => (a -> b) -> Orbit a -> Orbit b
|
omap :: (Nominal a, Nominal b) => (a -> b) -> Orbit a -> Orbit b
|
||||||
omap f = toOrbit . f . getElementE
|
omap f = toOrbit . f . getElementE
|
||||||
|
|
||||||
-- General combinator
|
|
||||||
productG :: (Nominal a, Nominal b) => (Int -> Int -> [[Ordering]]) -> Proxy a -> Proxy b -> Orbit a -> Orbit b -> [Orbit (a,b)]
|
|
||||||
productG strs pa pb oa ob = OrbPair (OrbRec oa) (OrbRec ob) <$> strs (index pa oa) (index pb ob)
|
|
||||||
|
|
||||||
-- Enumerate all orbits in a product A x B.
|
|
||||||
product :: (Nominal a, Nominal b) => Proxy a -> Proxy b -> Orbit a -> Orbit b -> [Orbit (a,b)]
|
|
||||||
product = productG prodStrings
|
|
||||||
|
|
||||||
-- Separated product: A * B = { (a,b) | Exist C1, C2 disjoint supporting a, b resp.}
|
|
||||||
separatedProduct :: (Nominal a, Nominal b) => Proxy a -> Proxy b -> Orbit a -> Orbit b -> [Orbit (a,b)]
|
|
||||||
separatedProduct = productG sepProdStrings
|
|
||||||
|
|
||||||
-- "Left product": A ⫂ B = { (a,b) | C supports a => C supports b }
|
|
||||||
leftProduct :: (Nominal a, Nominal b) => Proxy a -> Proxy b -> Orbit a -> Orbit b -> [Orbit (a,b)]
|
|
||||||
leftProduct = productG lsupprProdStrings
|
|
||||||
|
|
||||||
-- "Right product": A ⫁ B = { (a,b) | C supports a <= C supports b }
|
|
||||||
rightProduct :: (Nominal a, Nominal b) => Proxy a -> Proxy b -> Orbit a -> Orbit b -> [Orbit (a,b)]
|
|
||||||
rightProduct = productG rsupplProdStrings
|
|
||||||
|
|
||||||
-- Strictly increasing product = { (a,b) | all elements in a < all elements in b }
|
|
||||||
increasingProduct :: (Nominal a, Nominal b) => Proxy a -> Proxy b -> Orbit a -> Orbit b -> [Orbit (a,b)]
|
|
||||||
increasingProduct = productG incrSepProdStrings
|
|
||||||
|
|
||||||
-- Strictly decreasing product = { (a,b) | all elements in a > elements in b }
|
|
||||||
decreasingProduct :: (Nominal a, Nominal b) => Proxy a -> Proxy b -> Orbit a -> Orbit b -> [Orbit (a,b)]
|
|
||||||
decreasingProduct = productG decrSepProdStrings
|
|
||||||
|
|
||||||
-- Strictly decreasing product = { (a,b) | all elements in a > elements in b }
|
|
||||||
testProduct :: (Nominal a, Nominal b) => Proxy a -> Proxy b -> Orbit a -> Orbit b -> [Orbit (a,b)]
|
|
||||||
testProduct = productG testProdStrings
|
|
||||||
|
|
25
src/Nominal/Atom.hs
Normal file
25
src/Nominal/Atom.hs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
{-# LANGUAGE DerivingVia #-}
|
||||||
|
|
||||||
|
module Nominal.Atom where
|
||||||
|
|
||||||
|
-- * Atoms
|
||||||
|
|
||||||
|
-- $Atoms
|
||||||
|
-- Module with the 'Atom' type. This is re-exported from the "Nominal" module,
|
||||||
|
-- and it often suffices to only import "Nominal".
|
||||||
|
|
||||||
|
-- | This is the type of atoms of our "ordered nominal sets" library.
|
||||||
|
-- Theoretically, you should think of atoms these as rational numbers, forming
|
||||||
|
-- a dense linear order. They can be compared for equality and order.
|
||||||
|
-- In the implementation, however, we represent them as integers, because in
|
||||||
|
-- any given situation only a finite number of atoms occur and we can choose
|
||||||
|
-- integral points. The library will always do this automatically, and I
|
||||||
|
-- noticed that in all applications, integers also suffice from the user
|
||||||
|
-- perspective.
|
||||||
|
newtype Atom = Atom {unAtom :: Int}
|
||||||
|
deriving (Eq, Ord)
|
||||||
|
deriving Show via Int
|
||||||
|
|
||||||
|
-- | Creates an atom with the value specified by the integer.
|
||||||
|
atom :: Int -> Atom
|
||||||
|
atom = Atom
|
|
@ -20,7 +20,8 @@ import Data.Proxy (Proxy(..))
|
||||||
import Data.Void
|
import Data.Void
|
||||||
import GHC.Generics
|
import GHC.Generics
|
||||||
|
|
||||||
import Support
|
import Nominal.Atom
|
||||||
|
import Nominal.Support as Support
|
||||||
|
|
||||||
|
|
||||||
-- This is the main meat of the package. The Nominal typeclass, it gives us ways
|
-- This is the main meat of the package. The Nominal typeclass, it gives us ways
|
||||||
|
@ -45,8 +46,8 @@ class Nominal a where
|
||||||
|
|
||||||
-- We can construct orbits from rational numbers. There is exactly one orbit,
|
-- We can construct orbits from rational numbers. There is exactly one orbit,
|
||||||
-- so this can be represented by the unit type.
|
-- so this can be represented by the unit type.
|
||||||
instance Nominal Rat where
|
instance Nominal Atom where
|
||||||
type Orbit Rat = ()
|
type Orbit Atom = ()
|
||||||
toOrbit _ = ()
|
toOrbit _ = ()
|
||||||
support r = Support.singleton r
|
support r = Support.singleton r
|
||||||
getElement _ s = Support.min s
|
getElement _ s = Support.min s
|
||||||
|
|
|
@ -2,6 +2,9 @@ module Nominal.Products where
|
||||||
|
|
||||||
import Control.Applicative
|
import Control.Applicative
|
||||||
import Data.MemoTrie
|
import Data.MemoTrie
|
||||||
|
import Data.Proxy
|
||||||
|
|
||||||
|
import Nominal.Class
|
||||||
|
|
||||||
-- Enumerates strings to compute all possible combinations. Here `LT` means the
|
-- Enumerates strings to compute all possible combinations. Here `LT` means the
|
||||||
-- "current" element goes to the left, `EQ` goes to both, and `GT` goes to the
|
-- "current" element goes to the left, `EQ` goes to both, and `GT` goes to the
|
||||||
|
@ -68,6 +71,38 @@ testProdStrings = mgen (0 :: Int) where
|
||||||
<|> (GT :) <$> mgen (k-1) n (m-1)
|
<|> (GT :) <$> mgen (k-1) n (m-1)
|
||||||
|
|
||||||
|
|
||||||
|
-- General combinator
|
||||||
|
productG :: (Nominal a, Nominal b) => (Int -> Int -> [[Ordering]]) -> Proxy a -> Proxy b -> Orbit a -> Orbit b -> [Orbit (a, b)]
|
||||||
|
productG strs pa pb oa ob = OrbPair (OrbRec oa) (OrbRec ob) <$> strs (index pa oa) (index pb ob)
|
||||||
|
|
||||||
|
-- Enumerate all orbits in a product A x B.
|
||||||
|
product :: (Nominal a, Nominal b) => Proxy a -> Proxy b -> Orbit a -> Orbit b -> [Orbit (a, b)]
|
||||||
|
product = productG prodStrings
|
||||||
|
|
||||||
|
-- Separated product: A * B = { (a,b) | Exist C1, C2 disjoint supporting a, b resp.}
|
||||||
|
separatedProduct :: (Nominal a, Nominal b) => Proxy a -> Proxy b -> Orbit a -> Orbit b -> [Orbit (a, b)]
|
||||||
|
separatedProduct = productG sepProdStrings
|
||||||
|
|
||||||
|
-- "Left product": A ⫂ B = { (a,b) | C supports a => C supports b }
|
||||||
|
leftProduct :: (Nominal a, Nominal b) => Proxy a -> Proxy b -> Orbit a -> Orbit b -> [Orbit (a, b)]
|
||||||
|
leftProduct = productG lsupprProdStrings
|
||||||
|
|
||||||
|
-- "Right product": A ⫁ B = { (a,b) | C supports a <= C supports b }
|
||||||
|
rightProduct :: (Nominal a, Nominal b) => Proxy a -> Proxy b -> Orbit a -> Orbit b -> [Orbit (a, b)]
|
||||||
|
rightProduct = productG rsupplProdStrings
|
||||||
|
|
||||||
|
-- Strictly increasing product = { (a,b) | all elements in a < all elements in b }
|
||||||
|
increasingProduct :: (Nominal a, Nominal b) => Proxy a -> Proxy b -> Orbit a -> Orbit b -> [Orbit (a, b)]
|
||||||
|
increasingProduct = productG incrSepProdStrings
|
||||||
|
|
||||||
|
-- Strictly decreasing product = { (a,b) | all elements in a > elements in b }
|
||||||
|
decreasingProduct :: (Nominal a, Nominal b) => Proxy a -> Proxy b -> Orbit a -> Orbit b -> [Orbit (a, b)]
|
||||||
|
decreasingProduct = productG decrSepProdStrings
|
||||||
|
|
||||||
|
-- Strictly decreasing product = { (a,b) | all elements in a > elements in b }
|
||||||
|
testProduct :: (Nominal a, Nominal b) => Proxy a -> Proxy b -> Orbit a -> Orbit b -> [Orbit (a, b)]
|
||||||
|
testProduct = productG testProdStrings
|
||||||
|
|
||||||
{- NOTE on performance:
|
{- NOTE on performance:
|
||||||
Previously, I had INLINABLE and SPECIALIZE pragmas for all above definitions.
|
Previously, I had INLINABLE and SPECIALIZE pragmas for all above definitions.
|
||||||
But with benchmarking, I concluded that they do not make any difference. So
|
But with benchmarking, I concluded that they do not make any difference. So
|
||||||
|
|
62
src/Nominal/Support.hs
Normal file
62
src/Nominal/Support.hs
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
{-# LANGUAGE DerivingVia #-}
|
||||||
|
|
||||||
|
module Nominal.Support where
|
||||||
|
|
||||||
|
import qualified Data.List as List
|
||||||
|
import qualified Data.List.Ordered as OrdList
|
||||||
|
|
||||||
|
import Nominal.Atom
|
||||||
|
|
||||||
|
-- * Support
|
||||||
|
|
||||||
|
-- | A support is a finite set of 'Atom's. In the implementation, it is
|
||||||
|
-- represented by a sorted list.
|
||||||
|
newtype Support = Support {unSupport :: [Atom]}
|
||||||
|
deriving (Eq, Ord)
|
||||||
|
deriving Show via [Atom]
|
||||||
|
|
||||||
|
-- ** Queries
|
||||||
|
|
||||||
|
size :: Support -> Int
|
||||||
|
size = List.length . unSupport
|
||||||
|
|
||||||
|
null :: Support -> Bool
|
||||||
|
null = List.null . unSupport
|
||||||
|
|
||||||
|
min :: Support -> Atom
|
||||||
|
min = List.head . unSupport
|
||||||
|
|
||||||
|
-- ** Construction
|
||||||
|
|
||||||
|
empty :: Support
|
||||||
|
empty = Support []
|
||||||
|
|
||||||
|
singleton :: Atom -> Support
|
||||||
|
singleton r = Support [r]
|
||||||
|
|
||||||
|
-- | Returns a "default" support with n elements.
|
||||||
|
def :: Int -> Support
|
||||||
|
def n = fromDistinctAscList . fmap (Atom . fromIntegral) $ [1 .. n]
|
||||||
|
|
||||||
|
-- ** Set operations
|
||||||
|
|
||||||
|
union :: Support -> Support -> Support
|
||||||
|
union (Support x) (Support y) = Support (OrdList.union x y)
|
||||||
|
|
||||||
|
intersect :: Support -> Support -> Support
|
||||||
|
intersect (Support x) (Support y) = Support (OrdList.isect x y)
|
||||||
|
|
||||||
|
toList :: Support -> [Atom]
|
||||||
|
toList = unSupport
|
||||||
|
|
||||||
|
-- ** Conversion to/from lists
|
||||||
|
|
||||||
|
fromList, fromAscList, fromDistinctAscList :: [Atom] -> Support
|
||||||
|
fromList = Support . OrdList.nubSort
|
||||||
|
fromAscList = Support . OrdList.nub
|
||||||
|
fromDistinctAscList = Support
|
||||||
|
|
||||||
|
{- NOTE: I have tried using a `Data.Set` data structure for supports, but it
|
||||||
|
was slower. Using lists is fast enough, perhaps other data structures like
|
||||||
|
vectors could be considered at some point.
|
||||||
|
-}
|
|
@ -13,7 +13,8 @@ import Data.Proxy
|
||||||
import Prelude hiding (map, product)
|
import Prelude hiding (map, product)
|
||||||
|
|
||||||
import Nominal
|
import Nominal
|
||||||
import Support (Rat(..))
|
import Nominal.Products as Nominal
|
||||||
|
import Nominal.Class
|
||||||
|
|
||||||
-- Similar to EquivariantSet, but merely a list structure. It is an
|
-- Similar to EquivariantSet, but merely a list structure. It is an
|
||||||
-- equivariant data type, so the Nominal instance is trivial.
|
-- equivariant data type, so the Nominal instance is trivial.
|
||||||
|
@ -53,26 +54,26 @@ empty = OrbitList []
|
||||||
singleOrbit :: Nominal a => a -> OrbitList a
|
singleOrbit :: Nominal a => a -> OrbitList a
|
||||||
singleOrbit a = OrbitList [toOrbit a]
|
singleOrbit a = OrbitList [toOrbit a]
|
||||||
|
|
||||||
rationals :: OrbitList Rat
|
rationals :: OrbitList Atom
|
||||||
rationals = singleOrbit (Rat 0)
|
rationals = singleOrbit (atom 0)
|
||||||
|
|
||||||
cons :: Nominal a => a -> OrbitList a -> OrbitList a
|
cons :: Nominal a => a -> OrbitList a -> OrbitList a
|
||||||
cons a (OrbitList l) = OrbitList (toOrbit a : l)
|
cons a (OrbitList l) = OrbitList (toOrbit a : l)
|
||||||
|
|
||||||
repeatRationals :: Int -> OrbitList [Rat]
|
repeatRationals :: Int -> OrbitList [Atom]
|
||||||
repeatRationals 0 = singleOrbit []
|
repeatRationals 0 = singleOrbit []
|
||||||
repeatRationals n = productWith (:) rationals (repeatRationals (n-1))
|
repeatRationals n = productWith (:) rationals (repeatRationals (n-1))
|
||||||
|
|
||||||
distinctRationals :: Int -> OrbitList [Rat]
|
distinctRationals :: Int -> OrbitList [Atom]
|
||||||
distinctRationals 0 = singleOrbit []
|
distinctRationals 0 = singleOrbit []
|
||||||
distinctRationals n = map (uncurry (:)) . OrbitList.separatedProduct rationals $ (distinctRationals (n-1))
|
distinctRationals n = map (uncurry (:)) . OrbitList.separatedProduct rationals $ (distinctRationals (n-1))
|
||||||
|
|
||||||
increasingRationals :: Int -> OrbitList [Rat]
|
increasingRationals :: Int -> OrbitList [Atom]
|
||||||
increasingRationals 0 = singleOrbit []
|
increasingRationals 0 = singleOrbit []
|
||||||
increasingRationals n = map (uncurry (:)) . OrbitList.increasingProduct rationals $ (increasingRationals (n-1))
|
increasingRationals n = map (uncurry (:)) . OrbitList.increasingProduct rationals $ (increasingRationals (n-1))
|
||||||
|
|
||||||
-- Bell numbers
|
-- Bell numbers
|
||||||
repeatRationalUpToPerm :: Int -> OrbitList [Rat]
|
repeatRationalUpToPerm :: Int -> OrbitList [Atom]
|
||||||
repeatRationalUpToPerm 0 = singleOrbit []
|
repeatRationalUpToPerm 0 = singleOrbit []
|
||||||
repeatRationalUpToPerm 1 = map pure rationals
|
repeatRationalUpToPerm 1 = map pure rationals
|
||||||
repeatRationalUpToPerm n = OrbitList.map (uncurry (:)) (OrbitList.increasingProduct rationals (repeatRationalUpToPerm (n-1))) <> OrbitList.map (uncurry (:)) (OrbitList.rightProduct rationals (repeatRationalUpToPerm (n-1)))
|
repeatRationalUpToPerm n = OrbitList.map (uncurry (:)) (OrbitList.increasingProduct rationals (repeatRationalUpToPerm (n-1))) <> OrbitList.map (uncurry (:)) (OrbitList.rightProduct rationals (repeatRationalUpToPerm (n-1)))
|
||||||
|
|
|
@ -6,13 +6,13 @@ import Data.List (permutations)
|
||||||
import Data.Map.Strict qualified as Map
|
import Data.Map.Strict qualified as Map
|
||||||
|
|
||||||
import Nominal
|
import Nominal
|
||||||
import Support
|
import Nominal.Support (toList)
|
||||||
|
|
||||||
---------------------------------
|
---------------------------------
|
||||||
---------------------------------
|
---------------------------------
|
||||||
|
|
||||||
-- Invariant: No element occurs more than once
|
-- Invariant: No element occurs more than once
|
||||||
newtype Perm = Perm (Map.Map Rat Rat)
|
newtype Perm = Perm (Map.Map Atom Atom)
|
||||||
deriving (Eq, Ord, Show)
|
deriving (Eq, Ord, Show)
|
||||||
|
|
||||||
identity :: Perm
|
identity :: Perm
|
||||||
|
@ -56,7 +56,7 @@ bind comp (Permuted f a) = case comp a of
|
||||||
Permuted g b -> shrink $ Permuted (compose g f) b
|
Permuted g b -> shrink $ Permuted (compose g f) b
|
||||||
|
|
||||||
allPermutations :: Support -> [Perm]
|
allPermutations :: Support -> [Perm]
|
||||||
allPermutations (Support xs) = fmap (reduce . Perm . Map.fromList . zip xs) . permutations $ xs
|
allPermutations xs = fmap (reduce . Perm . Map.fromList . zip (toList xs)) . permutations $ toList xs
|
||||||
|
|
||||||
-- Returns a lazy list
|
-- Returns a lazy list
|
||||||
allPermuted :: Nominal a => a -> [Permuted a]
|
allPermuted :: Nominal a => a -> [Permuted a]
|
||||||
|
@ -75,7 +75,7 @@ class Permutable a where
|
||||||
instance Permutable (Permuted a) where
|
instance Permutable (Permuted a) where
|
||||||
act = join
|
act = join
|
||||||
|
|
||||||
instance Permutable Rat where
|
instance Permutable Atom where
|
||||||
act (Permuted (Perm m) p) = Map.findWithDefault p p m
|
act (Permuted (Perm m) p) = Map.findWithDefault p p m
|
||||||
|
|
||||||
-- TODO: make all this generic
|
-- TODO: make all this generic
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
{-# language FlexibleContexts #-}
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
|
{-# LANGUAGE ImportQualifiedPost #-}
|
||||||
module Quotient where
|
module Quotient where
|
||||||
|
|
||||||
import Nominal (Nominal(..))
|
|
||||||
import Support (Support, intersect)
|
|
||||||
import OrbitList
|
|
||||||
import EquivariantMap (EquivariantMap)
|
import EquivariantMap (EquivariantMap)
|
||||||
import qualified EquivariantMap as Map
|
import EquivariantMap qualified as Map
|
||||||
import EquivariantSet (EquivariantSet)
|
import EquivariantSet (EquivariantSet)
|
||||||
import qualified EquivariantSet as Set
|
import EquivariantSet qualified as Set
|
||||||
|
import Nominal hiding (product)
|
||||||
|
import Nominal.Support (intersect)
|
||||||
|
import OrbitList
|
||||||
|
|
||||||
import Prelude (Bool, Int, Ord, (.), (<>), (+), ($), fst, snd, fmap, uncurry)
|
import Prelude (Bool, Int, Ord, (.), (<>), (+), ($), fst, snd, fmap, uncurry)
|
||||||
|
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
module Support
|
|
||||||
( module Support
|
|
||||||
, module Support.OrdList
|
|
||||||
, module Support.Rat
|
|
||||||
) where
|
|
||||||
|
|
||||||
import Support.OrdList
|
|
||||||
import Support.Rat
|
|
||||||
|
|
||||||
-- A support is a set of rational numbers, which can always be ordered. There
|
|
||||||
-- are several implementations: Ordered Lists, Sets, ...? This module chooses
|
|
||||||
-- the implementation. Change the import and export to experiment.
|
|
||||||
|
|
||||||
def :: Int -> Support
|
|
||||||
def n = fromDistinctAscList . fmap (Rat . toRational) $ [1..n]
|
|
|
@ -1,42 +0,0 @@
|
||||||
module Support.OrdList where
|
|
||||||
|
|
||||||
import qualified Data.List as List
|
|
||||||
import qualified Data.List.Ordered as OrdList
|
|
||||||
|
|
||||||
import Support.Rat
|
|
||||||
|
|
||||||
-- always sorted
|
|
||||||
newtype Support = Support { unSupport :: [Rat] }
|
|
||||||
deriving (Eq, Ord)
|
|
||||||
|
|
||||||
instance Show Support where
|
|
||||||
show = show . unSupport
|
|
||||||
|
|
||||||
size :: Support -> Int
|
|
||||||
size = List.length . unSupport
|
|
||||||
|
|
||||||
null :: Support -> Bool
|
|
||||||
null = List.null . unSupport
|
|
||||||
|
|
||||||
min :: Support -> Rat
|
|
||||||
min = List.head . unSupport
|
|
||||||
|
|
||||||
empty :: Support
|
|
||||||
empty = Support []
|
|
||||||
|
|
||||||
union :: Support -> Support -> Support
|
|
||||||
union (Support x) (Support y) = Support (OrdList.union x y)
|
|
||||||
|
|
||||||
intersect :: Support -> Support -> Support
|
|
||||||
intersect (Support x) (Support y) = Support (OrdList.isect x y)
|
|
||||||
|
|
||||||
singleton :: Rat -> Support
|
|
||||||
singleton r = Support [r]
|
|
||||||
|
|
||||||
toList :: Support -> [Rat]
|
|
||||||
toList = unSupport
|
|
||||||
|
|
||||||
fromList, fromAscList, fromDistinctAscList :: [Rat] -> Support
|
|
||||||
fromList = Support . OrdList.nubSort
|
|
||||||
fromAscList = Support . OrdList.nub
|
|
||||||
fromDistinctAscList = Support
|
|
|
@ -1,16 +0,0 @@
|
||||||
{-# LANGUAGE DeriveGeneric #-}
|
|
||||||
|
|
||||||
module Support.Rat where
|
|
||||||
|
|
||||||
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, Generic)
|
|
||||||
|
|
||||||
instance Show Rat where
|
|
||||||
show (Rat x) = show x
|
|
|
@ -1,37 +0,0 @@
|
||||||
module Support.Set where
|
|
||||||
|
|
||||||
import Data.Set (Set)
|
|
||||||
import qualified Data.Set as Set
|
|
||||||
|
|
||||||
import Support.Rat
|
|
||||||
|
|
||||||
-- Tree-based ordered set
|
|
||||||
newtype Support = Support { unSupport :: Set Rat }
|
|
||||||
|
|
||||||
size :: Support -> Int
|
|
||||||
size = Set.size . unSupport
|
|
||||||
|
|
||||||
null :: Support -> Bool
|
|
||||||
null = Set.null . unSupport
|
|
||||||
|
|
||||||
min :: Support -> Rat
|
|
||||||
min = Set.findMin . unSupport
|
|
||||||
|
|
||||||
empty :: Support
|
|
||||||
empty = Support Set.empty
|
|
||||||
|
|
||||||
union :: Support -> Support -> Support
|
|
||||||
union (Support x) (Support y) = Support (Set.union x y)
|
|
||||||
|
|
||||||
singleton :: Rat -> Support
|
|
||||||
singleton = Support . Set.singleton
|
|
||||||
|
|
||||||
toList :: Support -> [Rat]
|
|
||||||
toList = Set.toAscList . unSupport
|
|
||||||
|
|
||||||
fromList, fromAscList, fromDistinctAscList :: [Rat] -> Support
|
|
||||||
fromList = Support . Set.fromList
|
|
||||||
fromAscList = Support . Set.fromAscList
|
|
||||||
fromDistinctAscList = Support . Set.fromDistinctAscList
|
|
||||||
|
|
||||||
|
|
|
@ -8,22 +8,23 @@ import Test.Tasty.Bench
|
||||||
import EquivariantMap
|
import EquivariantMap
|
||||||
import EquivariantSet
|
import EquivariantSet
|
||||||
import Nominal
|
import Nominal
|
||||||
|
import Nominal.Atom
|
||||||
import OrbitList (repeatRationals, size)
|
import OrbitList (repeatRationals, size)
|
||||||
import Support
|
|
||||||
|
|
||||||
instance NFData Rat
|
instance NFData Atom where
|
||||||
|
rnf = rwhnf . unAtom
|
||||||
|
|
||||||
(\/) :: Ord (Orbit a) => EquivariantSet a -> EquivariantSet a -> EquivariantSet a
|
(\/) :: Ord (Orbit a) => EquivariantSet a -> EquivariantSet a -> EquivariantSet a
|
||||||
(\/) = EquivariantSet.union
|
(\/) = EquivariantSet.union
|
||||||
|
|
||||||
bigset :: (Rat, Rat, Rat, _) -> Bool
|
bigset :: (Atom, Atom, Atom, _) -> Bool
|
||||||
bigset (p, q, r, t) = EquivariantSet.member t s
|
bigset (p, q, r, t) = EquivariantSet.member t s
|
||||||
where
|
where
|
||||||
s1 = singleOrbit ((p, p), p) \/ singleOrbit ((p, p), q) \/ singleOrbit ((p, q), r)
|
s1 = singleOrbit ((p, p), p) \/ singleOrbit ((p, p), q) \/ singleOrbit ((p, q), r)
|
||||||
s2 = singleOrbit (p, q) \/ singleOrbit (q, r) \/ singleOrbit (r, p)
|
s2 = singleOrbit (p, q) \/ singleOrbit (q, r) \/ singleOrbit (r, p)
|
||||||
s = EquivariantSet.product s1 s2
|
s = EquivariantSet.product s1 s2
|
||||||
|
|
||||||
bigmap :: (Rat, Rat, _) -> Maybe (Rat, (Rat, Rat))
|
bigmap :: (Atom, Atom, _) -> Maybe (Atom, (Atom, Atom))
|
||||||
bigmap (p, q, t) = EquivariantMap.lookup t m3
|
bigmap (p, q, t) = EquivariantMap.lookup t m3
|
||||||
where
|
where
|
||||||
s = EquivariantSet.product (EquivariantSet.singleOrbit (p, q)) (EquivariantSet.singleOrbit (q, p))
|
s = EquivariantSet.product (EquivariantSet.singleOrbit (p, q)) (EquivariantSet.singleOrbit (q, p))
|
||||||
|
@ -38,18 +39,18 @@ main =
|
||||||
defaultMain
|
defaultMain
|
||||||
[ bgroup
|
[ bgroup
|
||||||
"bigmap"
|
"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 "1 y" $ nf bigmap (atom 1, atom 2, (((atom 1, atom 23), (atom 5, atom 4)), ((atom 2, atom 3), (atom 54, atom 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 "2 n" $ nf bigmap (atom 1, atom 2, (((atom 1, atom 23), (atom 5, atom 4)), ((atom 2, atom 3), (atom 54, atom 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 "3 y" $ nf bigmap (atom 1, atom 2, (((atom 1, atom 100), (atom 90, atom 20)), ((atom 30, atom 80), (atom 70, atom 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 "4 y" $ nf bigmap (atom 1, atom 2, (((atom 1, atom 100), (atom 100, atom 1)), ((atom 1, atom 100), (atom 100, atom 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
|
, bench "5 y" $ nf bigmap (atom 1, atom 2, (((atom 100, atom 1), (atom 1, atom 100)), ((atom 200, atom 2), (atom 2, atom 200)))) -- found
|
||||||
]
|
]
|
||||||
, bgroup
|
, bgroup
|
||||||
"bigset"
|
"bigset"
|
||||||
[ bench "1 y" $ nf bigset (Rat 1, Rat 2, Rat 3, (((Rat 1, Rat 1), Rat 1), (Rat 1, Rat 2))) -- found
|
[ bench "1 y" $ nf bigset (atom 1, atom 2, atom 3, (((atom 1, atom 1), atom 1), (atom 1, atom 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 "2 y" $ nf bigset (atom 1, atom 2, atom 3, (((atom 37, atom 37), atom 42), (atom 1, atom 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 "3 n" $ nf bigset (atom 1, atom 2, atom 3, (((atom 37, atom 31), atom 42), (atom 1, atom 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
|
, bench "4 y" $ nf bigset (atom 1, atom 2, atom 3, (((atom 1, atom 2), atom 3), (atom 5, atom 4))) -- found
|
||||||
]
|
]
|
||||||
, bgroup
|
, bgroup
|
||||||
"counting orbits"
|
"counting orbits"
|
||||||
|
|
|
@ -5,10 +5,8 @@ import Test.Tasty.HUnit hiding (assert)
|
||||||
import Test.Tasty.QuickCheck as QC
|
import Test.Tasty.QuickCheck as QC
|
||||||
import Prelude (Eq (..), IO, Int, length, show, (!!), ($), (<>))
|
import Prelude (Eq (..), IO, Int, length, show, (!!), ($), (<>))
|
||||||
|
|
||||||
import Nominal (Nominal (..))
|
import Nominal
|
||||||
import OrbitList (repeatRationals, size)
|
import OrbitList (repeatRationals, size)
|
||||||
import Support (Rat (..))
|
|
||||||
|
|
||||||
import SpecMap
|
import SpecMap
|
||||||
import SpecPermutable
|
import SpecPermutable
|
||||||
import SpecSet
|
import SpecSet
|
||||||
|
@ -31,4 +29,4 @@ a000670 = [1, 1, 3, 13, 75, 541, 4683, 47293, 545835, 7087261, 102247563, 162263
|
||||||
|
|
||||||
-- TODO: Add more quickcheck tests
|
-- TODO: Add more quickcheck tests
|
||||||
qcTests :: TestTree
|
qcTests :: TestTree
|
||||||
qcTests = testGroup "QuickCheck" [QC.testProperty "all atoms in same orbit" $ \p q -> toOrbit (p :: Rat) == toOrbit (q :: Rat)]
|
qcTests = testGroup "QuickCheck" [QC.testProperty "all atoms in same orbit" $ \p q -> toOrbit (p :: Atom) == toOrbit (q :: Atom)]
|
||||||
|
|
|
@ -9,8 +9,7 @@ import Prelude (const, ($))
|
||||||
|
|
||||||
import EquivariantMap
|
import EquivariantMap
|
||||||
import EquivariantSet qualified as EqSet
|
import EquivariantSet qualified as EqSet
|
||||||
import Support
|
import Nominal (atom)
|
||||||
|
|
||||||
import SpecUtils
|
import SpecUtils
|
||||||
|
|
||||||
mapTests :: TestTree
|
mapTests :: TestTree
|
||||||
|
@ -19,25 +18,25 @@ mapTests = testGroup "Map" [unitTests]
|
||||||
unitTests :: TestTree
|
unitTests :: TestTree
|
||||||
unitTests = testCase "Examples" $ do
|
unitTests = testCase "Examples" $ do
|
||||||
let
|
let
|
||||||
p = Rat 1
|
p = atom 1
|
||||||
q = Rat 2
|
q = atom 2
|
||||||
s = EqSet.product (EqSet.singleOrbit (p, q)) (EqSet.singleOrbit (q, p))
|
s = EqSet.product (EqSet.singleOrbit (p, q)) (EqSet.singleOrbit (q, p))
|
||||||
s2 = EqSet.product s s
|
s2 = EqSet.product s s
|
||||||
m1 = fromSet (\(((_, b), (_, d)), (_, (_, h))) -> (b, (d, h))) s2
|
m1 = fromSet (\(((_, b), (_, d)), (_, (_, 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 isJust $ lookup (((atom 1, atom 2), (atom 2, atom 1)), ((atom 1, atom 2), (atom 3, atom 2))) m1
|
||||||
assert isNothing $ lookup (((Rat 1, Rat 2), (Rat 2, Rat 1)), ((Rat 1, Rat 2), (Rat 1, Rat 2))) m1
|
assert isNothing $ lookup (((atom 1, atom 2), (atom 2, atom 1)), ((atom 1, atom 2), (atom 1, atom 2))) m1
|
||||||
|
|
||||||
let
|
let
|
||||||
s3 = EqSet.map (\((a, b), (c, d)) -> ((b, a), (d, c))) s2
|
s3 = EqSet.map (\((a, b), (c, d)) -> ((b, a), (d, c))) s2
|
||||||
m2 = fromSet (\(((_, b), (_, d)), (_, (_, h))) -> (b, (d, h))) s3
|
m2 = fromSet (\(((_, b), (_, d)), (_, (_, 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 isJust $ lookup (((atom 6, atom 1), (atom 1, atom 5)), ((atom 4, atom 1), (atom 1, atom 3))) m2
|
||||||
assert isNothing $ lookup (((Rat 1, Rat 2), (Rat 2, Rat 1)), ((Rat 1, Rat 2), (Rat 4, Rat 2))) m2
|
assert isNothing $ lookup (((atom 1, atom 2), (atom 2, atom 1)), ((atom 1, atom 2), (atom 4, atom 2))) m2
|
||||||
|
|
||||||
let m3 = unionWith const m1 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 isJust $ lookup (((atom 1, atom 23), (atom 5, atom 4)), ((atom 2, atom 3), (atom 54, atom 43))) m3
|
||||||
assert isNothing $ lookup (((Rat 1, Rat 23), (Rat 5, Rat 4)), ((Rat 2, Rat 3), (Rat 54, Rat 65))) m3
|
assert isNothing $ lookup (((atom 1, atom 23), (atom 5, atom 4)), ((atom 2, atom 3), (atom 54, atom 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 (((atom 1, atom 100), (atom 90, atom 20)), ((atom 30, atom 80), (atom 70, atom 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 (((atom 1, atom 100), (atom 100, atom 1)), ((atom 1, atom 100), (atom 100, atom 1))) m3
|
||||||
assert isJust $ lookup (((Rat 100, Rat 1), (Rat 1, Rat 100)), ((Rat 200, Rat 2), (Rat 2, Rat 200))) m3
|
assert isJust $ lookup (((atom 100, atom 1), (atom 1, atom 100)), ((atom 200, atom 2), (atom 2, atom 200))) m3
|
||||||
|
|
|
@ -7,8 +7,6 @@ import Test.Tasty.HUnit hiding (assert)
|
||||||
|
|
||||||
import Nominal
|
import Nominal
|
||||||
import Permutable
|
import Permutable
|
||||||
import Support (Rat (..))
|
|
||||||
|
|
||||||
import SpecUtils
|
import SpecUtils
|
||||||
|
|
||||||
permutableTests :: TestTree
|
permutableTests :: TestTree
|
||||||
|
@ -21,7 +19,7 @@ assocTest n =
|
||||||
assert and $
|
assert and $
|
||||||
[lhs f g == rhs f g | f <- perms, g <- perms]
|
[lhs f g == rhs f g | f <- perms, g <- perms]
|
||||||
where
|
where
|
||||||
element = fmap (Rat . toRational) $ [1 .. n]
|
element = fmap atom $ [1 .. n]
|
||||||
supp = support element
|
supp = support element
|
||||||
perms = allPermutations supp
|
perms = allPermutations supp
|
||||||
lhs f g = act (Permuted (compose f g) element)
|
lhs f g = act (Permuted (compose f g) element)
|
||||||
|
|
|
@ -5,8 +5,7 @@ import Test.Tasty.HUnit hiding (assert)
|
||||||
import Prelude (id, not, ($))
|
import Prelude (id, not, ($))
|
||||||
|
|
||||||
import EquivariantSet
|
import EquivariantSet
|
||||||
import Support (Rat (..))
|
import Nominal (atom)
|
||||||
|
|
||||||
import SpecUtils
|
import SpecUtils
|
||||||
|
|
||||||
setTests :: TestTree
|
setTests :: TestTree
|
||||||
|
@ -15,28 +14,28 @@ setTests = testGroup "Set" [unitTests]
|
||||||
unitTests :: TestTree
|
unitTests :: TestTree
|
||||||
unitTests = testCase "Examples" $ do
|
unitTests = testCase "Examples" $ do
|
||||||
let
|
let
|
||||||
p = Rat 1
|
p = atom 1
|
||||||
q = Rat 2
|
q = atom 2
|
||||||
s = product (singleOrbit (p, q)) (singleOrbit (q, p))
|
s = product (singleOrbit (p, q)) (singleOrbit (q, p))
|
||||||
|
|
||||||
assert id $ member ((Rat 1, Rat 2), (Rat 5, Rat 4)) s
|
assert id $ member ((atom 1, atom 2), (atom 5, atom 4)) s
|
||||||
assert not $ member ((Rat 5, Rat 2), (Rat 5, Rat 4)) s
|
assert not $ member ((atom 5, atom 2), (atom 5, atom 4)) s
|
||||||
assert id $ member ((Rat 1, Rat 2), (Rat 2, Rat 1)) s
|
assert id $ member ((atom 1, atom 2), (atom 2, atom 1)) s
|
||||||
assert id $ member ((Rat 3, Rat 4), (Rat 2, Rat 1)) s
|
assert id $ member ((atom 3, atom 4), (atom 2, atom 1)) s
|
||||||
|
|
||||||
let s2 = product s 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 (((atom 1, atom 2), (atom 5, atom 4)), ((atom 1, atom 2), (atom 5, atom 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 (((atom 1, atom 2), (atom 5, atom 4)), ((atom 1, atom 2), (atom 5, atom 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 (((atom 1, atom 2), (atom 5, atom 4)), ((atom 1, atom 200), (atom 5, atom 1))) s2
|
||||||
assert id $ member (((Rat 0, Rat 27), (Rat 5, Rat 4)), ((Rat 1, Rat 200), (Rat 5, Rat 1))) s2
|
assert id $ member (((atom 0, atom 27), (atom 5, atom 4)), ((atom 1, atom 200), (atom 5, atom 1))) s2
|
||||||
assert not $ member (((Rat 0, Rat 27), (Rat 5, Rat 4)), ((Rat 1, Rat 200), (Rat 5, Rat 5))) s2
|
assert not $ member (((atom 0, atom 27), (atom 5, atom 4)), ((atom 1, atom 200), (atom 5, atom 5))) s2
|
||||||
|
|
||||||
let s3 = map (\((a, b), (c, d)) -> ((b, a), (d, c))) 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 (((atom 5, atom 4), (atom 1, atom 2)), ((atom 5, atom 4), (atom 1, atom 2))) s3
|
||||||
assert id $ member (((Rat 2, Rat 1), (Rat 4, Rat 5)), ((Rat 2, Rat 1), (Rat 4, Rat 5))) s3
|
assert id $ member (((atom 2, atom 1), (atom 4, atom 5)), ((atom 2, atom 1), (atom 4, atom 5))) s3
|
||||||
|
|
||||||
let
|
let
|
||||||
r = Rat 3
|
r = atom 3
|
||||||
s4 = singleOrbit ((p, p), p) `union` singleOrbit ((p, p), q) `union` singleOrbit ((p, q), r)
|
s4 = singleOrbit ((p, p), p) `union` singleOrbit ((p, p), q) `union` singleOrbit ((p, q), r)
|
||||||
s5 = singleOrbit (p, q) `union` singleOrbit (q, r) `union` singleOrbit (r, p)
|
s5 = singleOrbit (p, q) `union` singleOrbit (q, r) `union` singleOrbit (r, p)
|
||||||
|
|
||||||
|
@ -44,7 +43,7 @@ unitTests = testCase "Examples" $ do
|
||||||
assert not $ product (singleOrbit p) (singleOrbit p) `isSubsetOf` s5
|
assert not $ product (singleOrbit p) (singleOrbit p) `isSubsetOf` s5
|
||||||
|
|
||||||
let s6 = product s4 s5
|
let s6 = product s4 s5
|
||||||
assert id $ member (((Rat 1, Rat 1), Rat 1), (Rat 1, Rat 2)) s6
|
assert id $ member (((atom 1, atom 1), atom 1), (atom 1, atom 2)) s6
|
||||||
assert id $ member (((Rat 37, Rat 37), Rat 42), (Rat 1, Rat 2)) s6
|
assert id $ member (((atom 37, atom 37), atom 42), (atom 1, atom 2)) s6
|
||||||
assert not $ member (((Rat 37, Rat 31), Rat 42), (Rat 1, Rat 2)) s6
|
assert not $ member (((atom 37, atom 31), atom 42), (atom 1, atom 2)) s6
|
||||||
assert id $ member (((Rat 1, Rat 2), Rat 3), (Rat 5, Rat 4)) s6
|
assert id $ member (((atom 1, atom 2), atom 3), (atom 5, atom 4)) s6
|
||||||
|
|
|
@ -5,11 +5,11 @@ module SpecUtils where
|
||||||
import Test.Tasty.HUnit hiding (assert)
|
import Test.Tasty.HUnit hiding (assert)
|
||||||
import Test.Tasty.QuickCheck as QC
|
import Test.Tasty.QuickCheck as QC
|
||||||
|
|
||||||
import Support (Rat (..))
|
import Nominal.Atom
|
||||||
|
|
||||||
assert :: HasCallStack => (a -> Bool) -> a -> IO ()
|
assert :: HasCallStack => (a -> Bool) -> a -> IO ()
|
||||||
assert f x = assertBool "" (f x)
|
assert f x = assertBool "" (f x)
|
||||||
|
|
||||||
instance Arbitrary Rat where
|
instance Arbitrary Atom where
|
||||||
arbitrary = Rat <$> arbitrary
|
arbitrary = atom <$> arbitrary
|
||||||
shrink (Rat p) = Rat <$> shrink p
|
shrink (Atom p) = atom <$> shrink p
|
||||||
|
|
Loading…
Add table
Reference in a new issue