Compare commits

..

19 Commits

Author SHA1 Message Date
Johannes Merl
17b64f263b LamdaCalculusV2 2024-05-07 14:58:00 +02:00
Johannes Merl
d5fe65ab8c WIP: rewrite... too much... 2024-04-30 07:42:10 +02:00
Johannes Merl
4744920468 clean up 2024-04-29 10:41:01 +02:00
Johannes Merl
17ba14882c Nurery big 2024-04-23 09:01:54 +02:00
Johannes Merl
ea687a2fbb clean up, organize and document 2024-04-22 14:33:40 +02:00
Johannes Merl
5945016607 reduce iterations to speed up and fix estimation 2024-04-21 20:45:16 +02:00
Johannes Merl
16189ef988 tweak params 2024-04-21 19:28:34 +02:00
Johannes Merl
e4c8e3f79f add run 2024-04-21 14:54:11 +02:00
Johannes Merl
a91f55284d fix 2024-04-21 14:43:23 +02:00
Johannes Merl
4658fff80e fix 2024-04-21 14:23:11 +02:00
Johannes Merl
698cfb37bb fix 2024-04-21 13:54:29 +02:00
Johannes Merl
156e2ab9d7 fix 2024-04-21 13:50:23 +02:00
Johannes Merl
ec2d5ad668 fix 2024-04-21 13:41:25 +02:00
Johannes Merl
564c2c915a fix 2024-04-21 13:31:42 +02:00
Johannes Merl
baf0808c36 fix 2024-04-21 13:28:25 +02:00
Johannes Merl
dcc02c8a57 fix 2024-04-21 13:27:23 +02:00
Johannes Merl
f42ab3c00f add missing 2024-04-21 13:24:39 +02:00
Johannes Merl
0862943ebc sbatch 2024-04-21 13:22:14 +02:00
Johannes Merl
8432103a18 finish German 2024-04-16 11:47:22 +02:00
29 changed files with 2557 additions and 457 deletions

9
build.sbatch Executable file
View File

@@ -0,0 +1,9 @@
#!/usr/bin/env bash
#SBATCH --time=00:10:00
#SBATCH --partition=cpu
#SBATCH --output=./output/output_build.txt
#SBATCH --error=./output/error_build.txt
#SBATCH --nodelist=oc-compute02
#SBATCH --mem=4G
#SBATCH -c16
srun nix develop --command stack --no-nix --system-ghc --no-install-ghc build

8
flake.lock generated
View File

@@ -2,17 +2,17 @@
"nodes": { "nodes": {
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1655624069, "lastModified": 1713145326,
"narHash": "sha256-7g1zwTdp35GMTERnSzZMWJ7PG3QdDE8VOX3WsnOkAtM=", "narHash": "sha256-m7+IWM6mkWOg22EC5kRUFCycXsXLSU7hWmHdmBfmC3s=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "0d68d7c857fe301d49cdcd56130e0beea4ecd5aa", "rev": "53a2c32bc66f5ae41a28d7a9a49d321172af621e",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "0d68d7c857fe301d49cdcd56130e0beea4ecd5aa", "rev": "53a2c32bc66f5ae41a28d7a9a49d321172af621e",
"type": "github" "type": "github"
} }
}, },

View File

@@ -2,8 +2,7 @@
description = "Flake for haga"; description = "Flake for haga";
inputs = { inputs = {
nixpkgs.url = nixpkgs.url =
# 2022-06-22 "github:NixOS/nixpkgs/53a2c32bc66f5ae41a28d7a9a49d321172af621e";
"github:NixOS/nixpkgs/0d68d7c857fe301d49cdcd56130e0beea4ecd5aa";
}; };
@@ -14,10 +13,12 @@
# defaultPackage.${system} = haskellPackages.callPackage ./default.nix { }; # defaultPackage.${system} = haskellPackages.callPackage ./default.nix { };
devShell.${system} = mkShell { devShell.${system} = mkShell {
buildInputs = [ buildInputs = [
haskell.compiler.ghc981
git
gcc
gmp
feedgnuplot feedgnuplot
haskellPackages.cabal-install stack
haskellPackages.ormolu
haskell.compiler.ghc8107
]; ];
}; };
}; };

View File

@@ -1,4 +1,4 @@
cabal-version: 2.2 cabal-version: 3.4
name: haga name: haga
version: 0.1.0.0 version: 0.1.0.0
synopsis: Simplistic genetic algorithms library synopsis: Simplistic genetic algorithms library
@@ -30,6 +30,7 @@ library
, MonadRandom , MonadRandom
, mwc-random , mwc-random
, optparse-applicative , optparse-applicative
, parallel
, path , path
, pipes , pipes
, primitive , primitive
@@ -39,30 +40,35 @@ library
, random , random
, random-fu , random-fu
, random-shuffle , random-shuffle
, semirings
, text , text
, wl-pprint-text , wl-pprint-text
default-language: Haskell2010 default-language: Haskell2010
ghc-options: -Wall -Wno-name-shadowing -Wno-orphans -threaded -rtsopts -O2 ghc-options: -Wall -Wno-name-shadowing -Wno-orphans -O2
hs-source-dirs: src hs-source-dirs: lib, lambda/lib
other-modules: CommonDefinition
exposed-modules: GA exposed-modules: GA
, Seminar
, Pretty
, Szenario191
, LambdaCalculus , LambdaCalculus
, IrisDataset , LambdaCalculusV2
, IrisData , Pretty
, Utils
, LambdaDatasets.NurseryDefinition
, LambdaDatasets.GermanDefinition
, LambdaDatasets.IrisDefinition
executable haga executable haga-lambda
build-depends: base build-depends: base
, bytestring , bytestring
, cassava , cassava
, containers , containers
, extra , extra
, hint , hint
, haga
, monad-loops , monad-loops
, MonadRandom , MonadRandom
, mwc-random , mwc-random
, optparse-applicative , optparse-applicative
, parallel
, path , path
, pipes , pipes
, primitive , primitive
@@ -76,15 +82,32 @@ executable haga
, wl-pprint-text , wl-pprint-text
default-language: Haskell2010 default-language: Haskell2010
ghc-options: -Wall -Wno-name-shadowing -Wno-orphans -threaded -rtsopts -O2 ghc-options: -Wall -Wno-name-shadowing -Wno-orphans -threaded -rtsopts -O2
hs-source-dirs: src hs-source-dirs: lambda/src
main-is: Main.hs main-is: Main.hs
other-modules: GA other-modules: LambdaDatasets.NurseryDataset
, Seminar , LambdaDatasets.NurseryData
, Pretty , LambdaDatasets.GermanDataset
, LambdaDatasets.GermanData
, LambdaDatasets.IrisDataset
, LambdaDatasets.IrisData
executable haga-students
build-depends: base
, extra
, haga
, optparse-applicative
, protolude
, pipes
, QuickCheck
, quickcheck-instances
, random-fu
, text
default-language: Haskell2010
ghc-options: -Wall -Wno-name-shadowing -Wno-orphans -threaded -rtsopts -O2
hs-source-dirs: src-students
main-is: Main.hs
other-modules: Seminar
, Szenario191 , Szenario191
, LambdaCalculus
, IrisDataset
, IrisData
executable haga-test executable haga-test
build-depends: base build-depends: base
@@ -93,11 +116,13 @@ executable haga-test
, cassava , cassava
, containers , containers
, extra , extra
, haga
, hint , hint
, monad-loops , monad-loops
, MonadRandom , MonadRandom
, mwc-random , mwc-random
, optparse-applicative , optparse-applicative
, parallel
, path , path
, pipes , pipes
, primitive , primitive
@@ -111,12 +136,5 @@ executable haga-test
, wl-pprint-text , wl-pprint-text
default-language: Haskell2010 default-language: Haskell2010
ghc-options: -Wall -Wno-name-shadowing -Wno-orphans -threaded -rtsopts -O2 ghc-options: -Wall -Wno-name-shadowing -Wno-orphans -threaded -rtsopts -O2
hs-source-dirs: src hs-source-dirs: lib
main-is: Test.hs main-is: Test.hs
other-modules: GA
, Seminar
, Pretty
, Szenario191
, LambdaCalculus
, IrisDataset
, IrisData

17
lambda/README.md Normal file
View File

@@ -0,0 +1,17 @@
# Why this split:
The Module(s) used when evaluating individuals has to be in an external library to make Hint work. so we split the lamda-calculus command program in a library we need to expose in the main library and the implementation.
Sadly, ghc / ghci / cabal can not properly make a public, internal library available to ghci (and, with that, Hint). Should this ever change:
```
library haga-lambda-lib
visibility: public
build-depends: base
, protolude
default-language: Haskell2010
ghc-options: -Wall -Wno-orphans -O2
hs-source-dirs: lambda/lib
other-modules: CommonDefinition
exposed-modules: LambdaDatasets.NurseryDefinition
```

View File

@@ -0,0 +1,9 @@
{-# LANGUAGE NoImplicitPrelude #-}
module CommonDefinition where
import Protolude
if' :: Bool -> a -> a -> a
if' True e _ = e
if' False _ e = e

View File

@@ -0,0 +1,38 @@
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE NoImplicitPrelude #-}
module LambdaDatasets.GermanDefinition
( module LambdaDatasets.GermanDefinition,
module CommonDefinition,
) where
import Protolude
import CommonDefinition
data GermanClass = Accept | Deny deriving (Eq, Generic, Show, Enum, Bounded)
data AccountStatus = AccountInDebt | NoAccount | LowAccountBalance | HighAccountBalanceOrRegular deriving (Eq, Generic, Show, Enum, Bounded, Ord)
data CreditHistory = HistoryGood | HistoryGoodHere | HistoryGoodSoFar | DelaysInHistory | CreditsExist deriving (Eq, Generic, Show, Enum, Bounded, Ord)
data Purpose = OldCar | NewCar | FunitureOrEquipment | Tech | Appliances | Repairs | Education | Retraining | Business | Other deriving (Eq, Generic, Show, Enum, Bounded)
data Savings = UnknownOrNone | SmallSavings | NormalSavings | GoodSavings | GreatSavings deriving (Eq, Generic, Show, Enum, Bounded, Ord)
data EmploymentStatus = NotEmployed | ShortTermEmployed | MediumTermEmployed | LongTermEmployed | VeteranEmployed deriving (Eq, Generic, Show, Enum, Bounded, Ord)
data StatusAndSex = MaleAndSeperated | FemaleAndSeperatedOrMarried | MaleAndSingle | FemaleAndSingle | MaleAndWidowedOrMarried deriving (Eq, Generic, Show, Enum, Bounded)
data OtherDebtors = NoOtherDebtors | CoApplicant | Guarantor deriving (Eq, Generic, Show, Enum, Bounded, Ord)
data Property = UnknownOrNoProperty | RealEstate | Savings | CarOrOther deriving (Eq, Generic, Show, Enum, Bounded)
data OtherPlans = PlansAtBank | PlansAtStores | NoOtherPlans deriving (Eq, Generic, Show, Enum, Bounded)
data Housing = Renting | OwningRecidency | ResidingForFree deriving (Eq, Generic, Show, Enum, Bounded)
data Job = UnemployedOrUnskilledNonResident | UnskilledResident | Skilled | HighlySkilled deriving (Eq, Generic, Show, Enum, Bounded, Ord)

View File

@@ -0,0 +1,16 @@
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE NoImplicitPrelude #-}
module LambdaDatasets.IrisDefinition
( module LambdaDatasets.IrisDefinition,
module CommonDefinition,
) where
import Protolude
import CommonDefinition
data IrisClass = Setosa | Virginica | Versicolor deriving (Eq, Generic, Show, Enum, Bounded)

View File

@@ -0,0 +1,40 @@
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE NoImplicitPrelude #-}
module LambdaDatasets.NurseryDefinition
( module LambdaDatasets.NurseryDefinition,
module CommonDefinition,
) where
import Protolude
import CommonDefinition
data NurseryClass = NotRecommend | Recommend | VeryRecommend | Priority | SpecPriority deriving (Eq, Generic, Show, Enum, Bounded, Ord)
instance Hashable NurseryClass
data Parents = Usual | Pretentious | GreatPret deriving (Eq, Generic, Show, Enum, Bounded, Ord)
instance Hashable Parents
data HasNurs = ProperNurs | LessProperNurs | ImproperNurs | CriticalNurs | VeryCritNurs deriving (Eq, Generic, Show, Enum, Bounded, Ord)
instance Hashable HasNurs
data Form = CompleteFamilyForm | CompletedFamilyForm | IncompleteFamilyForm | FosterFamilyForm deriving (Eq, Generic, Show, Enum, Bounded, Ord)
instance Hashable Form
data Children = OneChild | TwoChilds | ThreeChilds | MoreChilds deriving (Eq, Generic, Show, Enum, Bounded, Ord)
instance Hashable Children
data Housing = ConvenientHousing | LessConvHousing | CriticalHousing deriving (Eq, Generic, Show, Enum, Bounded, Ord)
instance Hashable Housing
data Finance = ConvenientFinance | InconvFinance deriving (Eq, Generic, Show, Enum, Bounded, Ord)
instance Hashable Finance
data Social = NotProblematicSocial | SlightlyProblematicSocial | ProblematicSocial deriving (Eq, Generic, Show, Enum, Bounded, Ord)
instance Hashable Social
data Health = NotRecommendHealth |RecommendedHealth | PriorityHealth deriving (Eq, Generic, Show, Enum, Bounded, Ord)
instance Hashable Health

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,208 @@
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE NoImplicitPrelude #-}
module LambdaDatasets.GermanDataset
( module LambdaCalculus,
module LambdaDatasets.GermanDataset,
module LambdaDatasets.GermanData,
module GA,
)
where
import qualified Data.List.NonEmpty as NE
import qualified Data.Map.Strict as Map
import Data.Random
import Data.Random.Distribution.Uniform
import qualified Data.Text as T
import Data.Tuple.Extra
import GA
import LambdaDatasets.GermanData
import LambdaCalculus
import qualified Language.Haskell.Interpreter as Hint
import qualified Language.Haskell.Interpreter.Unsafe as Hint
import Protolude
import Protolude.Error
import System.Random.MWC (createSystemRandom)
import qualified Type.Reflection as Ref
import Utils
lE :: LambdaEnviroment
lE =
LambdaEnviroment
{ functions =
Map.fromList
[ -- Math
((Ref.SomeTypeRep (Ref.TypeRep @(Int -> Int -> Int))), ["(+)", "(-)", "(*)"]),
-- Logic
((Ref.SomeTypeRep (Ref.TypeRep @(Bool -> Bool -> Bool))), ["(&&)", "(||)"]),
-- Ordered Enums
((Ref.SomeTypeRep (Ref.TypeRep @(Int -> Int -> Bool))), ["(>)", "(==)", "(/=)", "(>=)"]),
((Ref.SomeTypeRep (Ref.TypeRep @(AccountStatus -> AccountStatus -> Bool))), ["(>)", "(==)", "(/=)", "(>=)"]),
((Ref.SomeTypeRep (Ref.TypeRep @(CreditHistory -> CreditHistory -> Bool))), ["(>)", "(==)", "(/=)", "(>=)"]),
((Ref.SomeTypeRep (Ref.TypeRep @(Savings -> Savings -> Bool))), ["(>)", "(==)", "(/=)", "(>=)"]),
((Ref.SomeTypeRep (Ref.TypeRep @(EmploymentStatus -> EmploymentStatus -> Bool))), ["(>)", "(==)", "(/=)", "(>=)"]),
((Ref.SomeTypeRep (Ref.TypeRep @(OtherDebtors -> OtherDebtors -> Bool))), ["(>)", "(==)", "(/=)", "(>=)"]),
((Ref.SomeTypeRep (Ref.TypeRep @(Job -> Job -> Bool))), ["(>)", "(==)", "(/=)", "(>=)"]),
-- Eq Enum
((Ref.SomeTypeRep (Ref.TypeRep @(GermanClass -> GermanClass -> Bool))), ["(==)", "(/=)"]),
((Ref.SomeTypeRep (Ref.TypeRep @(Purpose -> Purpose -> Bool))), ["(==)", "(/=)"]),
((Ref.SomeTypeRep (Ref.TypeRep @(StatusAndSex -> StatusAndSex -> Bool))), ["(==)", "(/=)"]),
((Ref.SomeTypeRep (Ref.TypeRep @(Property -> Property -> Bool))), ["(==)", "(/=)"]),
((Ref.SomeTypeRep (Ref.TypeRep @(OtherPlans -> OtherPlans -> Bool))), ["(==)", "(/=)"]),
((Ref.SomeTypeRep (Ref.TypeRep @(Housing -> Housing -> Bool))), ["(==)", "(/=)"]),
-- Any Type
((Ref.SomeTypeRep (Ref.TypeRep @(Bool -> Int -> Int -> Int))), ["if'"]),
((Ref.SomeTypeRep (Ref.TypeRep @(Bool -> GermanClass -> GermanClass -> GermanClass))), ["if'","if'","if'","if'","if'","if'","if'","if'"]),
((Ref.SomeTypeRep (Ref.TypeRep @(Bool -> AccountStatus -> AccountStatus -> AccountStatus))), ["if'"]),
((Ref.SomeTypeRep (Ref.TypeRep @(Bool -> CreditHistory -> CreditHistory -> CreditHistory))), ["if'"]),
((Ref.SomeTypeRep (Ref.TypeRep @(Bool -> Purpose -> Purpose -> Purpose))), ["if'"]),
((Ref.SomeTypeRep (Ref.TypeRep @(Bool -> Savings -> Savings -> Savings))), ["if'"]),
((Ref.SomeTypeRep (Ref.TypeRep @(Bool -> EmploymentStatus -> EmploymentStatus -> EmploymentStatus))), ["if'"]),
((Ref.SomeTypeRep (Ref.TypeRep @(Bool -> StatusAndSex -> StatusAndSex -> StatusAndSex))), ["if'"]),
((Ref.SomeTypeRep (Ref.TypeRep @(Bool -> OtherDebtors -> OtherDebtors -> OtherDebtors))), ["if'"]),
((Ref.SomeTypeRep (Ref.TypeRep @(Bool -> Property -> Property -> Property))), ["if'"]),
((Ref.SomeTypeRep (Ref.TypeRep @(Bool -> OtherPlans -> OtherPlans -> OtherPlans))), ["if'"]),
((Ref.SomeTypeRep (Ref.TypeRep @(Bool -> Housing -> Housing -> Housing))), ["if'"]),
((Ref.SomeTypeRep (Ref.TypeRep @(Bool -> Job -> Job -> Job))), ["if'"])
],
constants =
Map.fromList
[ ((Ref.SomeTypeRep (Ref.TypeRep @(Int))), [(fmap show (uniform 0 10 :: RVar Int))]),
((Ref.SomeTypeRep (Ref.TypeRep @(Bool))), [(fmap show (uniform True False :: RVar Bool))]),
((Ref.SomeTypeRep (Ref.TypeRep @(GermanClass))), [(fmap show (enumUniform Accept Deny))]),
((Ref.SomeTypeRep (Ref.TypeRep @(AccountStatus))), [(fmap show (enumUniform AccountInDebt HighAccountBalanceOrRegular))]),
((Ref.SomeTypeRep (Ref.TypeRep @(CreditHistory))), [(fmap show (enumUniform HistoryGood CreditsExist ))]),
((Ref.SomeTypeRep (Ref.TypeRep @(Purpose))), [(fmap show (enumUniform OldCar Other ))]),
((Ref.SomeTypeRep (Ref.TypeRep @(Savings))), [(fmap show (enumUniform UnknownOrNone GreatSavings ))]),
((Ref.SomeTypeRep (Ref.TypeRep @(EmploymentStatus))), [(fmap show (enumUniform NotEmployed VeteranEmployed ))]),
((Ref.SomeTypeRep (Ref.TypeRep @(StatusAndSex))), [(fmap show (enumUniform MaleAndSeperated MaleAndWidowedOrMarried ))]),
((Ref.SomeTypeRep (Ref.TypeRep @(OtherDebtors))), [(fmap show (enumUniform NoOtherDebtors Guarantor ))]),
((Ref.SomeTypeRep (Ref.TypeRep @(Property))), [(fmap show (enumUniform UnknownOrNoProperty CarOrOther ))]),
((Ref.SomeTypeRep (Ref.TypeRep @(OtherPlans))), [(fmap show (enumUniform PlansAtBank NoOtherPlans ))]),
((Ref.SomeTypeRep (Ref.TypeRep @(Housing))), [(fmap show (enumUniform Renting ResidingForFree ))]),
((Ref.SomeTypeRep (Ref.TypeRep @(Job))), [(fmap show (enumUniform UnemployedOrUnskilledNonResident HighlySkilled ))])
],
targetType = (Ref.SomeTypeRep (Ref.TypeRep @(AccountStatus -> Int -> CreditHistory -> Purpose -> Int -> Savings -> EmploymentStatus -> Int -> StatusAndSex -> OtherDebtors -> Int -> Property -> Int -> OtherPlans -> Housing -> Int -> Job -> Int -> Bool -> Bool -> GermanClass))),
maxDepth = 8,
weights =
ExpressionWeights
{ lambdaSpucker = 1,
lambdaSchlucker = 2,
symbol = 30,
variable = 10,
constant = 5
}
}
lEE :: LamdaExecutionEnv
lEE =
LamdaExecutionEnv
{ -- For now these need to define all available functions and types. Generic functions can be used.
imports = ["LambdaDatasets.GermanDefinition"],
training = True,
trainingData =
( map fst (takeFraktion 0.8 germanTrainingData),
map snd (takeFraktion 0.8 germanTrainingData)
),
testData =
( map fst (dropFraktion 0.8 germanTrainingData),
map snd (dropFraktion 0.8 germanTrainingData)
),
exTargetType = (Ref.SomeTypeRep (Ref.TypeRep @(AccountStatus -> Int -> CreditHistory -> Purpose -> Int -> Savings -> EmploymentStatus -> Int -> StatusAndSex -> OtherDebtors -> Int -> Property -> Int -> OtherPlans -> Housing -> Int -> Job -> Int -> Bool -> Bool -> GermanClass))),
results = Map.empty
}
shuffledLEE :: IO LamdaExecutionEnv
shuffledLEE = do
mwc <- liftIO createSystemRandom
let smpl = ((sampleFrom mwc) :: RVar a -> IO a)
itD <- smpl $ shuffle germanTrainingData
return
LamdaExecutionEnv
{ -- For now these need to define all available functions and types. Generic functions can be used.
imports = ["LambdaDatasets.GermanDefinition"],
training = True,
trainingData =
( map fst (takeFraktion 0.8 itD),
map snd (takeFraktion 0.8 itD)
),
testData =
( map fst (dropFraktion 0.8 itD),
map snd (dropFraktion 0.8 itD)
),
exTargetType = (Ref.SomeTypeRep (Ref.TypeRep @(AccountStatus -> Int -> CreditHistory -> Purpose -> Int -> Savings -> EmploymentStatus -> Int -> StatusAndSex -> OtherDebtors -> Int -> Property -> Int -> OtherPlans -> Housing -> Int -> Job -> Int -> Bool -> Bool -> GermanClass))),
results = Map.empty
}
data LamdaExecutionEnv = LamdaExecutionEnv
{ -- For now these need to define all available functions and types. Generic functions can be used.
imports :: [Text],
training :: Bool,
trainingData :: ([(AccountStatus, Int, CreditHistory, Purpose, Int, Savings, EmploymentStatus, Int, StatusAndSex, OtherDebtors, Int, Property, Int, OtherPlans, Housing, Int, Job, Int, Bool, Bool)], [GermanClass]),
testData :: ([(AccountStatus, Int, CreditHistory, Purpose, Int, Savings, EmploymentStatus, Int, StatusAndSex, OtherDebtors, Int, Property, Int, OtherPlans, Housing, Int, Job, Int, Bool, Bool)], [GermanClass]),
exTargetType :: TypeRep,
-- todo: kindaHacky
results :: Map TypeRequester FittnesRes
}
data FittnesRes = FittnesRes
{ total :: R,
fitnessTotal :: R,
fitnessGeoMean :: R,
fitnessMean :: R,
accuracy :: R,
biasSize :: R,
totalSize :: N
}
deriving (Show)
instance Fitness FittnesRes where
getR = total
instance Evaluator TypeRequester LamdaExecutionEnv FittnesRes where
fitness' env tr = (results env) Map.! tr
calc env pop = do
let relevantResults = Map.filterWithKey (\k _ -> contains pop k) (results env)
let toAdd = NE.filter (\k -> not (Map.member k relevantResults)) pop
toInsert <- Hint.runInterpreter (evalResults env toAdd)
let insertPair (key, val) m = Map.insert key val m
let res = foldr insertPair relevantResults (fromRight (error ("To insert is " <> show toInsert)) toInsert)
return env {results = res}
dset :: LamdaExecutionEnv -> ([(AccountStatus, Int, CreditHistory, Purpose, Int, Savings, EmploymentStatus, Int, StatusAndSex, OtherDebtors, Int, Property, Int, OtherPlans, Housing, Int, Job, Int, Bool, Bool)], [GermanClass])
dset lEE = if training lEE then trainingData lEE else testData lEE
evalResults :: LamdaExecutionEnv -> [TypeRequester] -> Hint.InterpreterT IO [(TypeRequester, FittnesRes)]
evalResults ex trs = do
Hint.setImports $ (map T.unpack (imports ex)) ++ ["Protolude"]
Hint.unsafeSetGhcOption "-O2"
let arrayOfFunctionText = map toLambdaExpressionS trs
let textOfFunctionArray = "[" <> T.intercalate "," arrayOfFunctionText <> "]"
result <- Hint.interpret (T.unpack (textOfFunctionArray)) (Hint.as :: [AccountStatus -> Int -> CreditHistory -> Purpose -> Int -> Savings -> EmploymentStatus -> Int -> StatusAndSex -> OtherDebtors -> Int -> Property -> Int -> OtherPlans -> Housing -> Int -> Job -> Int -> Bool -> Bool -> GermanClass])
return $ zipWith (evalResult ex) trs result
evalResult :: LamdaExecutionEnv -> TypeRequester -> (AccountStatus -> Int -> CreditHistory -> Purpose -> Int -> Savings -> EmploymentStatus -> Int -> StatusAndSex -> OtherDebtors -> Int -> Property -> Int -> OtherPlans -> Housing -> Int -> Job -> Int -> Bool -> Bool -> GermanClass) -> (TypeRequester, FittnesRes)
evalResult ex tr result = ( tr,
FittnesRes
{ total = score,
fitnessTotal = fitness',
fitnessMean = meanOfAccuricyPerClass resAndTarget,
fitnessGeoMean = geomeanOfDistributionAccuracy resAndTarget,
accuracy = acc,
biasSize = biasSmall,
totalSize = countTrsR tr
}
)
where
res = map (\(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t) -> result a b c d e f g h i j k l m n o p q r s t) (fst (dset ex))
resAndTarget = (zip (snd (dset ex)) res)
acc = (foldr (\ts s -> if ((fst ts) == (snd ts)) then s + 1 else s) 0 resAndTarget) / fromIntegral (length resAndTarget)
biasSmall = exp ((-(fromIntegral (countTrsR tr))) / 1000) -- 0 (schlecht) bis 1 (gut)
fitness' = meanOfAccuricyPerClass resAndTarget
score = fitness' + (biasSmall - 1)

View File

@@ -4,17 +4,15 @@
{-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeApplications #-}
{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE NoImplicitPrelude #-}
module IrisData where module LambdaDatasets.IrisData
( module LambdaDatasets.IrisDefinition,
module LambdaDatasets.IrisData,
)
where
import Data.Csv import LambdaDatasets.IrisDefinition
import Protolude import Protolude
data IrisClass = Setosa | Virginica | Versicolor deriving (Eq, Generic, Show, Enum, Bounded)
instance FromRecord IrisClass
instance ToRecord IrisClass
irisTrainingData :: [((Float, Float, Float, Float), IrisClass)] irisTrainingData :: [((Float, Float, Float, Float), IrisClass)]
irisTrainingData = irisTrainingData =
[ ((6.7, 3.1, 4.4, 1.4), Versicolor), [ ((6.7, 3.1, 4.4, 1.4), Versicolor),
@@ -136,12 +134,8 @@ irisTrainingData =
((5.7, 2.5, 5.0, 2.0), Virginica), ((5.7, 2.5, 5.0, 2.0), Virginica),
((6.8, 2.8, 4.8, 1.4), Versicolor), ((6.8, 2.8, 4.8, 1.4), Versicolor),
((6.3, 2.9, 5.6, 1.8), Virginica), ((6.3, 2.9, 5.6, 1.8), Virginica),
((6.0, 2.2, 4.0, 1.0), Versicolor) ((6.0, 2.2, 4.0, 1.0), Versicolor),
] ((5.0, 3.5, 1.6, 0.6), Setosa),
irisTestData :: [((Float, Float, Float, Float), IrisClass)]
irisTestData =
[ ((5.0, 3.5, 1.6, 0.6), Setosa),
((4.6, 3.1, 1.5, 0.2), Setosa), ((4.6, 3.1, 1.5, 0.2), Setosa),
((4.8, 3.4, 1.6, 0.2), Setosa), ((4.8, 3.4, 1.6, 0.2), Setosa),
((4.8, 3.0, 1.4, 0.3), Setosa), ((4.8, 3.0, 1.4, 0.3), Setosa),

View File

@@ -4,10 +4,10 @@
{-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeApplications #-}
{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE NoImplicitPrelude #-}
module IrisDataset module LambdaDatasets.IrisDataset
( module LambdaCalculus, ( module LambdaCalculus,
module IrisDataset, module LambdaDatasets.IrisDataset,
module IrisData, module LambdaDatasets.IrisData,
module GA, module GA,
) )
where where
@@ -15,20 +15,22 @@ where
import qualified Data.List.NonEmpty as NE import qualified Data.List.NonEmpty as NE
import qualified Data.Map.Strict as Map import qualified Data.Map.Strict as Map
import Data.Random import Data.Random
import System.Random.MWC (createSystemRandom)
import Data.Random.Distribution.Uniform import Data.Random.Distribution.Uniform
import qualified Data.Text as T import qualified Data.Text as T
import Data.Tuple.Extra import Data.Tuple.Extra
import GA import GA
import LambdaCalculus import LambdaCalculus
import IrisData import LambdaDatasets.IrisData
import qualified Language.Haskell.Interpreter as Hint import qualified Language.Haskell.Interpreter as Hint
import qualified Language.Haskell.Interpreter.Unsafe as Hint import qualified Language.Haskell.Interpreter.Unsafe as Hint
import Protolude import Protolude
import Utils
import Protolude.Error import Protolude.Error
import qualified Type.Reflection as Ref import qualified Type.Reflection as Ref
irisLE :: LambdaEnviroment lE :: LambdaEnviroment
irisLE = lE =
LambdaEnviroment LambdaEnviroment
{ functions = { functions =
Map.fromList Map.fromList
@@ -57,22 +59,42 @@ irisLE =
} }
} }
irisLEE :: LamdaExecutionEnv lEE :: LamdaExecutionEnv
irisLEE = lEE =
LamdaExecutionEnv LamdaExecutionEnv
{ -- For now these need to define all available functions and types. Generic functions can be used. { -- For now these need to define all available functions and types. Generic functions can be used.
imports = ["IrisDataset"], imports = ["LambdaDatasets.IrisDataset"],
training = True, training = True,
trainingData = trainingData =
( map fst irisTrainingData, ( map fst (takeFraktion 0.8 irisTrainingData),
map snd irisTrainingData map snd (takeFraktion 0.8 irisTrainingData)
), ),
testData = testData =
( map fst irisTestData, ( map fst (dropFraktion 0.8 irisTrainingData),
map snd irisTestData map snd (dropFraktion 0.8 irisTrainingData)
),
exTargetType = (Ref.SomeTypeRep (Ref.TypeRep @(Float -> Float -> Float -> Float -> IrisClass))),
results = Map.empty
}
shuffledLEE :: IO LamdaExecutionEnv
shuffledLEE = do
mwc <- liftIO createSystemRandom
let smpl = ((sampleFrom mwc) :: RVar a -> IO a)
itD <- smpl $ shuffle irisTrainingData
return LamdaExecutionEnv
{ -- For now these need to define all available functions and types. Generic functions can be used.
imports = ["LambdaDatasets.IrisDataset"],
training = True,
trainingData =
( map fst (takeFraktion 0.8 itD),
map snd (takeFraktion 0.8 itD)
),
testData =
( map fst (dropFraktion 0.8 itD),
map snd (dropFraktion 0.8 itD)
), ),
exTargetType = (Ref.SomeTypeRep (Ref.TypeRep @(Float -> Float -> Float -> Float -> IrisClass))), exTargetType = (Ref.SomeTypeRep (Ref.TypeRep @(Float -> Float -> Float -> Float -> IrisClass))),
-- todo: kindaHacky
results = Map.empty results = Map.empty
} }
@@ -92,8 +114,9 @@ data FittnesRes = FittnesRes
fitnessTotal :: R, fitnessTotal :: R,
fitnessGeoMean :: R, fitnessGeoMean :: R,
fitnessMean :: R, fitnessMean :: R,
accuracy :: Int, accuracy :: R,
biasSize :: R biasSize :: R,
totalSize :: N
} }
deriving (Show) deriving (Show)
@@ -104,42 +127,42 @@ instance Evaluator TypeRequester LamdaExecutionEnv FittnesRes where
fitness' env tr = (results env) Map.! tr fitness' env tr = (results env) Map.! tr
calc env pop = do calc env pop = do
let toAdd = NE.filter (\k -> not (Map.member k (results env))) pop let relevantResults = Map.filterWithKey (\k _ -> contains pop k) (results env)
let toAdd = NE.filter (\k -> not (Map.member k relevantResults)) pop
toInsert <- Hint.runInterpreter (evalResults env toAdd) toInsert <- Hint.runInterpreter (evalResults env toAdd)
let insertPair (key, val) m = Map.insert key val m let insertPair (key, val) m = Map.insert key val m
let res = foldr insertPair (results env) (fromRight (error ("To insert is " <> show toInsert)) toInsert) let res = foldr insertPair relevantResults (fromRight (error ("To insert is " <> show toInsert)) toInsert)
return env {results = res} return env {results = res}
dset :: LamdaExecutionEnv -> ([(Float, Float, Float, Float)], [IrisClass]) dset :: LamdaExecutionEnv -> ([(Float, Float, Float, Float)], [IrisClass])
dset lEE = if training lEE then trainingData lEE else testData lEE dset lEE = if training lEE then trainingData lEE else testData lEE
evalResults :: LamdaExecutionEnv -> [TypeRequester] -> Hint.InterpreterT IO [(TypeRequester, FittnesRes)] evalResults :: LamdaExecutionEnv -> [TypeRequester] -> Hint.InterpreterT IO [(TypeRequester, FittnesRes)]
evalResults ex trs = mapM (evalResult ex) trs evalResults ex trs = do
evalResult :: LamdaExecutionEnv -> TypeRequester -> Hint.InterpreterT IO (TypeRequester, FittnesRes)
evalResult ex tr = do
Hint.setImports $ (map T.unpack (imports ex)) ++ ["Protolude"] Hint.setImports $ (map T.unpack (imports ex)) ++ ["Protolude"]
Hint.unsafeSetGhcOption "-O2" Hint.unsafeSetGhcOption "-O2"
result <- Hint.interpret (T.unpack (toLambdaExpressionS tr)) (Hint.as :: Float -> Float -> Float -> Float -> IrisClass) let arrayOfFunctionText = map toLambdaExpressionS trs
let res = map (\(a, b, c, d) -> result a b c d) (fst (dset ex)) let textOfFunctionArray = "[" <> T.intercalate "," arrayOfFunctionText <> "]"
let resAndTarget = (zip (snd (dset ex)) res) result <- Hint.interpret (T.unpack (textOfFunctionArray)) (Hint.as :: [Float -> Float -> Float -> Float -> IrisClass])
let acc = (foldr (\ts s -> if ((fst ts) == (snd ts)) then s + 1 else s) 0 resAndTarget) :: Int return $ zipWith (evalResult ex) trs result
let biasSmall = exp ((-(fromIntegral (countTrsR tr)))/1000) -- 0 (schlecht) bis 1 (gut)
let fitness' = meanOfAccuricyPerClass resAndTarget
let score = fitness' + (biasSmall - 1) evalResult :: LamdaExecutionEnv -> TypeRequester -> (Float -> Float -> Float -> Float -> IrisClass) -> (TypeRequester, FittnesRes)
return evalResult ex tr result = ( tr,
( tr,
FittnesRes FittnesRes
{ total = score, { total = score,
fitnessTotal = fitness', fitnessTotal = fitness',
fitnessMean = meanOfAccuricyPerClass resAndTarget, fitnessMean = meanOfAccuricyPerClass resAndTarget,
fitnessGeoMean = geomeanOfDistributionAccuracy resAndTarget, fitnessGeoMean = geomeanOfDistributionAccuracy resAndTarget,
accuracy = acc, accuracy = acc,
biasSize = biasSmall biasSize = biasSmall,
totalSize = countTrsR tr
} }
) )
where
if' :: Bool -> a -> a -> a res = map (\(a, b, c, d) -> result a b c d) (fst (dset ex))
if' True e _ = e resAndTarget = (zip (snd (dset ex)) res)
if' False _ e = e acc = (foldr (\ts s -> if ((fst ts) == (snd ts)) then s + 1 else s) 0 resAndTarget) / fromIntegral (length resAndTarget)
biasSmall = exp ((-(fromIntegral (countTrsR tr))) / 1000) -- 0 (schlecht) bis 1 (gut)
fitness' = meanOfAccuricyPerClass resAndTarget
score = fitness' + (biasSmall - 1)

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,139 @@
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE NoImplicitPrelude #-}
module LambdaDatasets.NurseryDataset
( module LambdaCalculusV2,
module LambdaDatasets.NurseryDataset,
module LambdaDatasets.NurseryData,
module GA,
)
where
import qualified Data.List.NonEmpty as NE
import qualified Data.Map.Strict as Map
import Data.Random
import Data.Random.Distribution.Uniform
import qualified Data.Text as T
import Data.Tuple.Extra
import GA
import LambdaCalculusV2
import LambdaDatasets.NurseryData
import qualified Language.Haskell.Interpreter as Hint
import qualified Language.Haskell.Interpreter.Unsafe as Hint
import Protolude
import Protolude.Error
import System.Random.MWC (createSystemRandom)
import qualified Type.Reflection as Ref
import Utils
operators :: [BoundSymbol]
operators = [ -- Math
-- Logic
BoundSymbol (Ref.TypeRep @(Bool -> Bool -> Bool)) (&&) (Just "(&&)"),
BoundSymbol (Ref.TypeRep @(Bool -> Bool -> Bool)) (||) (Just "(||)"),
-- Ordered Enums
BoundSymbol (Ref.TypeRep @(NurseryClass -> NurseryClass -> Bool)) (>) (Just "(>)"),
BoundSymbol (Ref.TypeRep @(NurseryClass -> NurseryClass -> Bool)) (==) (Just "(==)"),
BoundSymbol (Ref.TypeRep @(NurseryClass -> NurseryClass -> Bool)) (/=) (Just "(/=)"),
BoundSymbol (Ref.TypeRep @(NurseryClass -> NurseryClass -> Bool)) (>=) (Just "(>=)"),
BoundSymbol (Ref.TypeRep @(Parents -> Parents -> Bool)) (>) (Just "(>)"),
BoundSymbol (Ref.TypeRep @(Parents -> Parents -> Bool)) (==) (Just "(==)"),
BoundSymbol (Ref.TypeRep @(Parents -> Parents -> Bool)) (/=) (Just "(/=)"),
BoundSymbol (Ref.TypeRep @(Parents -> Parents -> Bool)) (>=) (Just "(>=)"),
BoundSymbol (Ref.TypeRep @(HasNurs -> HasNurs -> Bool)) (>) (Just "(>)"),
BoundSymbol (Ref.TypeRep @(HasNurs -> HasNurs -> Bool)) (==) (Just "(==)"),
BoundSymbol (Ref.TypeRep @(HasNurs -> HasNurs -> Bool)) (/=) (Just "(/=)"),
BoundSymbol (Ref.TypeRep @(HasNurs -> HasNurs -> Bool)) (>=) (Just "(>=)"),
BoundSymbol (Ref.TypeRep @(Form -> Form -> Bool)) (>) (Just "(>)"),
BoundSymbol (Ref.TypeRep @(Form -> Form -> Bool)) (==) (Just "(==)"),
BoundSymbol (Ref.TypeRep @(Form -> Form -> Bool)) (/=) (Just "(/=)"),
BoundSymbol (Ref.TypeRep @(Form -> Form -> Bool)) (>=) (Just "(>=)"),
BoundSymbol (Ref.TypeRep @(Children -> Children -> Bool)) (>) (Just "(>)"),
BoundSymbol (Ref.TypeRep @(Children -> Children -> Bool)) (==) (Just "(==)"),
BoundSymbol (Ref.TypeRep @(Children -> Children -> Bool)) (/=) (Just "(/=)"),
BoundSymbol (Ref.TypeRep @(Children -> Children -> Bool)) (>=) (Just "(>=)"),
BoundSymbol (Ref.TypeRep @(Housing -> Housing -> Bool)) (>) (Just "(>)"),
BoundSymbol (Ref.TypeRep @(Housing -> Housing -> Bool)) (==) (Just "(==)"),
BoundSymbol (Ref.TypeRep @(Housing -> Housing -> Bool)) (/=) (Just "(/=)"),
BoundSymbol (Ref.TypeRep @(Housing -> Housing -> Bool)) (>=) (Just "(>=)"),
BoundSymbol (Ref.TypeRep @(Finance -> Finance -> Bool)) (>) (Just "(>)"),
BoundSymbol (Ref.TypeRep @(Finance -> Finance -> Bool)) (==) (Just "(==)"),
BoundSymbol (Ref.TypeRep @(Finance -> Finance -> Bool)) (/=) (Just "(/=)"),
BoundSymbol (Ref.TypeRep @(Finance -> Finance -> Bool)) (>=) (Just "(>=)"),
BoundSymbol (Ref.TypeRep @(Social -> Social -> Bool)) (>) (Just "(>)"),
BoundSymbol (Ref.TypeRep @(Social -> Social -> Bool)) (==) (Just "(==)"),
BoundSymbol (Ref.TypeRep @(Social -> Social -> Bool)) (/=) (Just "(/=)"),
BoundSymbol (Ref.TypeRep @(Social -> Social -> Bool)) (>=) (Just "(>=)"),
BoundSymbol (Ref.TypeRep @(Health -> Health -> Bool)) (>) (Just "(>)"),
BoundSymbol (Ref.TypeRep @(Health -> Health -> Bool)) (==) (Just "(==)"),
BoundSymbol (Ref.TypeRep @(Health -> Health -> Bool)) (/=) (Just "(/=)"),
BoundSymbol (Ref.TypeRep @(Health -> Health -> Bool)) (>=) (Just "(>=)"),
-- Eq Enum
-- Any Type
BoundSymbol (Ref.TypeRep @(Bool -> Int -> Int -> Int)) (if') (Just "if'"),
BoundSymbol (Ref.TypeRep @(Bool -> NurseryClass -> NurseryClass -> NurseryClass)) (if') (Just "if'"),
BoundSymbol (Ref.TypeRep @(Bool -> Parents -> Parents -> Parents)) (if') (Just "if'"),
BoundSymbol (Ref.TypeRep @(Bool -> HasNurs -> HasNurs -> HasNurs)) (if') (Just "if'"),
BoundSymbol (Ref.TypeRep @(Bool -> Form -> Form -> Form)) (if') (Just "if'"),
BoundSymbol (Ref.TypeRep @(Bool -> Children -> Children -> Children)) (if') (Just "if'"),
BoundSymbol (Ref.TypeRep @(Bool -> Housing -> Housing -> Housing)) (if') (Just "if'"),
BoundSymbol (Ref.TypeRep @(Bool -> Finance -> Finance -> Finance)) (if') (Just "if'"),
BoundSymbol (Ref.TypeRep @(Bool -> Social -> Social -> Social)) (if') (Just "if'"),
BoundSymbol (Ref.TypeRep @(Bool -> Health -> Health -> Health)) (if') (Just "if'")
]
lE :: LambdaEnviroment (Parents -> HasNurs -> Form -> Children -> Housing -> Finance -> Social -> Health -> NurseryClass)
lE =
LambdaEnviroment
{ functions = operators,
constants =
[ ConstVal (Ref.TypeRep @(Bool)) (uniform True False),
ConstVal (Ref.TypeRep @(NurseryClass)) (enumUniform NotRecommend SpecPriority),
ConstVal (Ref.TypeRep @(Parents)) (enumUniform Usual GreatPret),
ConstVal (Ref.TypeRep @(HasNurs)) (enumUniform ProperNurs VeryCritNurs),
ConstVal (Ref.TypeRep @(Form)) (enumUniform CompleteFamilyForm FosterFamilyForm),
ConstVal (Ref.TypeRep @(Children)) (enumUniform OneChild MoreChilds),
ConstVal (Ref.TypeRep @(Housing)) (enumUniform ConvenientHousing CriticalHousing),
ConstVal (Ref.TypeRep @(Finance)) (enumUniform ConvenientFinance InconvFinance),
ConstVal (Ref.TypeRep @(Social)) (enumUniform NotProblematicSocial ProblematicSocial),
ConstVal (Ref.TypeRep @(Health)) (enumUniform NotRecommendHealth PriorityHealth)
],
maxDepth = 150,
weights =
ExpressionWeights
{ application = 2,
abstraction = 2,
variableReference = 300,
constant = 1,
functionBias = 100
},
mutationStrength = 10/150,
crossoverStrength = 15/150
}
trainingFraction :: R
trainingFraction = (2 / 3)
lEE :: ExecutionEnviroment (Parents -> HasNurs -> Form -> Children -> Housing -> Finance -> Social -> Health -> NurseryClass)
lEE =
ExecutionEnviroment
{ -- For now these need to define all available functions and types. Generic functions can be used.
fun = operators,
training = True,
trainingData = nurseryTrainingData,
testData = nurseryTrainingData
}
shuffledLEE :: IO (ExecutionEnviroment (Parents -> HasNurs -> Form -> Children -> Housing -> Finance -> Social -> Health -> NurseryClass))
shuffledLEE = do
return
ExecutionEnviroment
{ fun = operators,
training = True,
trainingData = nurseryTrainingData,
testData = nurseryTrainingData
}

View File

@@ -1,15 +1,15 @@
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE NoImplicitPrelude #-}
import Options.Applicative import Options.Applicative
import Pipes import Pipes
import Pretty
import Protolude hiding (for) import Protolude hiding (for)
import System.IO import System.IO
-- import Szenario212Pun -- import LambdaDatasets.IrisDataset
-- import Szenario191 import LambdaDatasets.NurseryDataset
import IrisDataset -- import LambdaDatasets.GermanDataset
import Debug.Trace as DB import Debug.Trace as DB
import qualified Data.Map.Strict as Map import qualified Data.Map.Strict as Map
@@ -26,7 +26,7 @@ options =
( long "iterations" ( long "iterations"
<> short 'i' <> short 'i'
<> metavar "N" <> metavar "N"
<> value 500 <> value 1
<> help "Number of iterations" <> help "Number of iterations"
) )
<*> option <*> option
@@ -51,18 +51,25 @@ main :: IO ()
main = main =
execParser optionsWithHelp >>= \opts -> do execParser optionsWithHelp >>= \opts -> do
hSetBuffering stdout NoBuffering hSetBuffering stdout NoBuffering
let env = irisLE lEE <- shuffledLEE
let selType = Tournament 3 let cfg = GaRunConfig {
let run' = run irisLEE env selType 40 (5 / 100) (populationSize opts) (steps (iterations opts)) enviroment = lE,
pop' <- runEffect (for run' logCsv) initialEvaluator = lEE,
irisLEE' <- calc irisLEE pop' selectionType = Tournament 3,
let (res, _) = bests irisLEE' 5 pop' termination = (steps (iterations opts)),
let irisLEE' = irisLEE {training = False} poulationSize = (populationSize opts),
irisLEE' <- calc irisLEE' res nParents = 120,
mapM_ (format irisLEE') res elitismRatio = 5/100
}
pop' <- runEffect (for (run cfg) logCsv)
lEE' <- calc lEE pop'
let (res, _) = bests lEE' 5 pop'
let lEE' = lEE {training = False}
lEE' <- calc lEE' res
mapM_ (format lEE') res
where where
format irisL s = do format l s = do
let f = fitness' irisL s let f = fitness' l s
putErrText $ show f <> "\n" <> pretty s putErrText $ show f <> "\n" <> output (lE) s
logCsv = putText . csv logCsv = putText . csv
csv (t, f) = show t <> " " <> show f csv (t, f) = show t <> " " <> show f

View File

@@ -6,7 +6,11 @@
{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TupleSections #-} {-# LANGUAGE TupleSections #-}
{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
-- | -- |
-- Module : GA -- Module : GA
-- Description : Abstract genetic algorithm -- Description : Abstract genetic algorithm
@@ -20,7 +24,7 @@
-- In order to use it for a certain problem, basically, you have to make your -- In order to use it for a certain problem, basically, you have to make your
-- solution type an instance of 'Individual' and then simply call the 'run' -- solution type an instance of 'Individual' and then simply call the 'run'
-- function. -- function.
module GA (Environment, new, population, mutate, crossover1, crossover, nX, Fitness, getR, Evaluator, fitness,fitness', calc, Individual, GA.run, Tournament (..), N, R, Population, steps, bests, runTests) where module GA (Environment (..), Fitness (..), Evaluator (..), Individual, GA.run, Tournament (..), N, R, Population, steps, bests, runTests, GaRunConfig (..)) where
import Control.Arrow hiding (first, second) import Control.Arrow hiding (first, second)
import Data.List.NonEmpty ((<|)) import Data.List.NonEmpty ((<|))
@@ -47,7 +51,9 @@ type R = Double
-- | -- |
-- An Environment that Individuals of type i can be created from -- An Environment that Individuals of type i can be created from
-- It stores all information required to create and change Individuals correctly -- It stores all information required to create and change Individuals correctly
class (Pretty e, Individual i) => Environment i e | e -> i where class (Individual i) => Environment i e | e -> i, i -> e where
output :: e -> i -> Text
-- | -- |
-- Generates a completely random individual. -- Generates a completely random individual.
new :: e -> RVar i new :: e -> RVar i
@@ -84,7 +90,7 @@ class (Pretty e, Individual i) => Environment i e | e -> i where
-- | -- |
-- An Evaluator that Individuals of type i can be evaluated by -- An Evaluator that Individuals of type i can be evaluated by
-- It stores all information required to evaluate an individuals fitness -- It stores all information required to evaluate an individuals fitness
class (Individual i, Fitness r) => Evaluator i e r | i -> e r where class (Individual i, Fitness r) => Evaluator i e r | e -> i r where
-- | -- |
-- An individual's fitness. Higher values are considered “better”. -- An individual's fitness. Higher values are considered “better”.
-- --
@@ -93,14 +99,19 @@ class (Individual i, Fitness r) => Evaluator i e r | i -> e r where
fitness :: e -> i -> R fitness :: e -> i -> R
fitness env i = getR ( fitness' env i) fitness env i = getR ( fitness' env i)
-- |
-- An more complete fitness object, used to include more info to the output of the current fitness.
-- You can e.g. track individual size with this.
fitness' :: e -> i -> r fitness' :: e -> i -> r
-- TODO kinda hacky?!? -- |
-- here, fitness values for the next generation can be calculated at once, and just once, using any monadic action, if necessary.
-- It is guaranteed that the e passed to fitness is the result of a calc function, where the individual was part of the Population passed.
-- It may be smart to reuse known results between invocations.
calc :: e -> Population i -> IO e calc :: e -> Population i -> IO e
calc eval _ = do calc eval _ = return eval
return eval
class (Pretty i, Ord i) => Individual i class (Ord i) => Individual i
class (Show i) => Fitness i where class (Show i) => Fitness i where
getR :: i -> R getR :: i -> R
@@ -206,21 +217,25 @@ selectBest eval pElite pop nPop = do
then return elitists then return elitists
else return $ elitists <> (fst $ bests eval (nPop - length elitists) (NE.fromList rest)) else return $ elitists <> (fst $ bests eval (nPop - length elitists) (NE.fromList rest))
run ::
(Individual i, Evaluator i eval r, Environment i env, SelectionType s) => -- This class encapsulates everything needed to run a generic genetic Algorithm
eval -> data GaRunConfig i r eval env t where
env -> GaRunConfig :: (Individual i, Fitness r, Evaluator i eval r, Environment i env, SelectionType t) => {
-- | Mechanism for selecting parents enviroment :: env,
s -> initialEvaluator :: eval,
-- | Number of parents @nParents@ for creating @nParents@ children selectionType :: t,
N -> termination :: (Termination i),
-- | Elitism ratio @pElite@ poulationSize :: N,
R -> stepSize :: N,
-- | Population size elitismRatio :: R
N -> } -> GaRunConfig i r eval env t
Termination i ->
Producer (Int, r) IO (Population i)
run eval env selectionType nParents pElite nPop term = do run :: GaRunConfig i r eval env t -> Producer (Int, r) IO (Population i)
run config@(GaRunConfig _ _ _ _ _ _ _) = do
let eval = initialEvaluator config
let env = enviroment config
let nPop = poulationSize config
mwc <- liftIO createSystemRandom mwc <- liftIO createSystemRandom
let smpl = ((sampleFrom mwc) :: RVar a -> IO a) let smpl = ((sampleFrom mwc) :: RVar a -> IO a)
firstPop <- liftIO $ smpl $ (population env nPop) firstPop <- liftIO $ smpl $ (population env nPop)
@@ -228,12 +243,17 @@ run eval env selectionType nParents pElite nPop term = do
return res return res
where where
runIter eval count pop smpl = ( runIter eval count pop smpl = (
if term pop count if (termination config) pop count
then do then do
return pop return pop
else do else do
let env = enviroment config
let nPop = poulationSize config
let selecType = selectionType config
let nParents = stepSize config
let pElite = elitismRatio config
eval <- liftIO $ calc eval pop eval <- liftIO $ calc eval pop
withKids <- liftIO $ smpl $ reproduce eval env selectionType nParents pop withKids <- liftIO $ smpl $ reproduce eval env selecType nParents pop
eval <- liftIO $ calc eval withKids eval <- liftIO $ calc eval withKids
resPop <- liftIO $ smpl $ selectBest eval pElite withKids nPop resPop <- liftIO $ smpl $ selectBest eval pElite withKids nPop
let fBest = fitness' eval $ NE.head $ fst $ bests eval 1 resPop let fBest = fitness' eval $ NE.head $ fst $ bests eval 1 resPop
@@ -305,18 +325,18 @@ shuffle' :: NonEmpty a -> RVar (NonEmpty a)
shuffle' xs@(_ :| []) = return xs shuffle' xs@(_ :| []) = return xs
shuffle' xs = fmap (NE.fromList) (shuffle (toList xs)) shuffle' xs = fmap (NE.fromList) (shuffle (toList xs))
instance Pretty Integer where
pretty i = "Found int: " <> show i
instance Individual Integer instance Individual Integer
newtype IntTestEnviroment = IntTestEnviroment ((Integer, Integer), Integer, N) deriving (Eq) -- IntTestEnviroment ((0,100000),10) newtype IntTestEnviroment = IntTestEnviroment ((Integer, Integer), Integer, N) deriving (Eq, Show) -- IntTestEnviroment ((0,100000),10)
instance Pretty IntTestEnviroment where instance Pretty IntTestEnviroment where
-- instance Pretty (Maybe Student) where -- instance Pretty (Maybe Student) where
pretty (IntTestEnviroment ((i, j), k, _)) = "IntTestEnviroment of Individuals between " <> (show i) <> " and " <> (show j) <> " variance when mutating is " <> (show k) pretty (IntTestEnviroment ((i, j), k, _)) = "IntTestEnviroment of Individuals between " <> (show i) <> " and " <> (show j) <> " variance when mutating is " <> (show k)
instance Environment Integer IntTestEnviroment where instance Environment Integer IntTestEnviroment where
output _ i = "Found int: " <> show i
new (IntTestEnviroment ((from, to), _, _)) = uniform from to new (IntTestEnviroment ((from, to), _, _)) = uniform from to
nX (IntTestEnviroment ((_, _), _, n)) = n nX (IntTestEnviroment ((_, _), _, n)) = n

View File

@@ -9,7 +9,7 @@
module LambdaCalculus where module LambdaCalculus where
import Data.List (foldr1, last, nub, intersect, (!!), (\\)) import Data.List (foldr1, intersect, last, nub, (!!), (\\))
import qualified Data.List.NonEmpty as NE import qualified Data.List.NonEmpty as NE
import qualified Data.Map.Strict as Map import qualified Data.Map.Strict as Map
import Data.Maybe import Data.Maybe
@@ -17,14 +17,15 @@ import Data.Random
import qualified Data.Text as T import qualified Data.Text as T
import Data.Tuple.Extra import Data.Tuple.Extra
import Data.Typeable import Data.Typeable
import Debug.Trace as DB
import GA import GA
import Pretty import Pretty
import Protolude import Protolude
import Protolude.Error import Protolude.Error
import Debug.Trace as DB
import Test.QuickCheck hiding (sample, shuffle) import Test.QuickCheck hiding (sample, shuffle)
import Test.QuickCheck.Monadic (assert, monadicIO) import Test.QuickCheck.Monadic (assert, monadicIO)
import qualified Type.Reflection as Ref import qualified Type.Reflection as Ref
import Utils
data ExpressionWeights = ExpressionWeights data ExpressionWeights = ExpressionWeights
{ lambdaSpucker :: Int, { lambdaSpucker :: Int,
@@ -73,7 +74,6 @@ exampleLE =
type BoundVars = [TypeRep] type BoundVars = [TypeRep]
-- we need a dynamic typ with a concept of equality here, should we want to interpret the result, instead of compiling it... -- we need a dynamic typ with a concept of equality here, should we want to interpret the result, instead of compiling it...
type ConVal = Text type ConVal = Text
@@ -96,7 +96,6 @@ toLambdaExpressionS (TR _ (Nothing) _) = "Invalid Lambda Epr"
-- data LambdaExpression = LambdaSpucker TypeRequester TypeRequester BoundVars | LambdaSchlucker TypeRequester BoundVars | Symbol ConVal [TypeRequester] BoundVars | Var TypeRep Int [TypeRequester] BoundVars | Constan ConVal deriving (Eq, Ord, Show) -- data LambdaExpression = LambdaSpucker TypeRequester TypeRequester BoundVars | LambdaSchlucker TypeRequester BoundVars | Symbol ConVal [TypeRequester] BoundVars | Var TypeRep Int [TypeRequester] BoundVars | Constan ConVal deriving (Eq, Ord, Show)
eToLambdaExpressionS :: LambdaExpression -> Text eToLambdaExpressionS :: LambdaExpression -> Text
eToLambdaExpressionS (LambdaSpucker typeRequester1 typeRequester2 boundVars) = "(\\l" <> showSanifid (last boundVars) <> show (count boundVars (last boundVars) - 1) <> " -> " <> toLambdaExpressionS typeRequester2 <> ") " <> toLambdaExpressionS typeRequester1 eToLambdaExpressionS (LambdaSpucker typeRequester1 typeRequester2 boundVars) = "(\\l" <> showSanifid (last boundVars) <> show (count boundVars (last boundVars) - 1) <> " -> " <> toLambdaExpressionS typeRequester2 <> ") " <> toLambdaExpressionS typeRequester1
eToLambdaExpressionS (LambdaSchlucker typeRequester boundVars) = "\\l" <> showSanifid (last boundVars) <> show (count boundVars (last boundVars) - 1) <> " -> " <> toLambdaExpressionS typeRequester eToLambdaExpressionS (LambdaSchlucker typeRequester boundVars) = "\\l" <> showSanifid (last boundVars) <> show (count boundVars (last boundVars) - 1) <> " -> " <> toLambdaExpressionS typeRequester
@@ -179,7 +178,7 @@ genLambdaSchlucker env@(LambdaEnviroment functions constants _ _ weights) depthL
let args = typeRepArgs target let args = typeRepArgs target
let lambaType = fromJust (head args) let lambaType = fromJust (head args)
let toFind = last args let toFind = last args
typeRequester <- genTypeRequester env depthLeft toFind (boundVar ++ [lambaType]) typeRequester <- genTypeRequester env (depthLeft + 1) toFind (boundVar ++ [lambaType])
return (LambdaSchlucker typeRequester (boundVar ++ [lambaType])) return (LambdaSchlucker typeRequester (boundVar ++ [lambaType]))
genLambdaConst :: LambdaEnviroment -> Int -> TypeRep -> BoundVars -> RVar LambdaExpression genLambdaConst :: LambdaEnviroment -> Int -> TypeRep -> BoundVars -> RVar LambdaExpression
@@ -234,100 +233,119 @@ instance Environment TypeRequester LambdaEnviroment where
return tr return tr
mutate env@(LambdaEnviroment _ _ _ maxDepth _) tr = do mutate env@(LambdaEnviroment _ _ _ maxDepth _) tr = do
let trCount = countTrsR (tr) selfCrossover <- uniform True False
selectedTR <- uniform 1 trCount co <- crossover1 env tr tr
let (depthAt, (TR trep _ bound)) = depthLeftAndTypeAtR tr selectedTR maxDepth if selfCrossover && isJust co
res <- genTypeRequester env depthAt trep bound then do
return $ replaceAtR selectedTR tr res let (tr1, tr2) = fromJust co
return $ minimumBy (compare `on` countTrsR) [tr1, tr2]
else do
let trCount = countTrsR (tr)
selectedTR <- uniform 1 trCount
let (depthAt, (TR trep _ bound)) = depthLeftAndTypeAtR tr selectedTR maxDepth
res <- genTypeRequester env depthAt trep bound
return $ replaceAtR selectedTR tr res
nX _ = 3 -- todo! nX _ = 3 -- todo!
crossover1 env@(LambdaEnviroment _ _ _ maxDepth _) tr1 tr2 = do crossover1 env@(LambdaEnviroment _ _ _ maxDepth _) tr1 tr2 = do
let trCount = countTrsR tr1 let trCount = countTrsR tr1
selectedIndex1 <- uniform 1 trCount selectedIndex1 <- uniform 1 trCount
let (depthAt, selectedTr1@(TR _ _ bound1)) = depthLeftAndTypeAtR tr1 selectedIndex1 maxDepth let (depthAt1, selectedTr1@(TR _ _ bound1)) = depthLeftAndTypeAtR tr1 selectedIndex1 maxDepth
let indexes = findIndicesWhere tr2 (isCompatibleTr selectedTr1) 0 let depthLeftNeeded = depthOfTR selectedTr1
if length indexes == 0 then return Nothing else (do let indexes = findIndicesWhere tr2 (isCompatibleTr selectedTr1 (maxDepth - depthAt1) depthLeftNeeded) 0 0
(selectedTr2@(TR _ _ bound2),selectedIndex2) <- randomElement indexes if length indexes == 0
selectedTr2 <- adaptBoundVars selectedTr2 bound1 then return Nothing
selectedTr1 <- adaptBoundVars selectedTr1 bound2 else
let child1 = replaceAtR selectedIndex1 tr1 selectedTr2 ( do
let child2 = replaceAtR selectedIndex2 tr2 selectedTr1 (selectedTr2@(TR _ _ bound2), selectedIndex2) <- randomElement indexes
return $ Just (child1, child2) selectedTr2 <- adaptBoundVars selectedTr2 bound1
) selectedTr1 <- adaptBoundVars selectedTr1 bound2
let child1 = replaceAtR selectedIndex1 tr1 selectedTr2
let child2 = replaceAtR selectedIndex2 tr2 selectedTr1
return $ Just (child1, child2)
)
-- helper -- helper
adaptBoundVars:: TypeRequester -> BoundVars -> RVar TypeRequester depthOfTR :: TypeRequester -> Int
depthOfTR (TR _ (Just le@(LambdaSchlucker _ _)) _) = maximum (0:(map depthOfTR (asList le)))
depthOfTR (TR _ (Just le) _) = maximum (0:(map depthOfTR (asList le))) + 1
depthOfTR _ = error "le Not Just (depthOfTR)"
adaptBoundVars :: TypeRequester -> BoundVars -> RVar TypeRequester
adaptBoundVars tr@(TR _ _ bvOld) bvNew = do adaptBoundVars tr@(TR _ _ bvOld) bvNew = do
newIndexMap <- generateConversionIndexMap bvOld bvNew newIndexMap <- generateConversionIndexMap bvOld bvNew
return $ convertTr tr bvOld bvNew newIndexMap return $ convertTr tr bvOld bvNew newIndexMap
convertTr:: TypeRequester -> BoundVars -> BoundVars -> Map TypeRep (Int -> Int) -> TypeRequester convertTr :: TypeRequester -> BoundVars -> BoundVars -> Map TypeRep (Int -> Int) -> TypeRequester
convertTr tr@(TR tRp (Just le) bvCurr) bvOld bvNew mapper = TR tRp (Just (convertLe le bvOld bvNew mapper)) (bvNew ++ (bvCurr \\ bvOld)) convertTr tr@(TR tRp (Just le) bvCurr) bvOld bvNew mapper = TR tRp (Just (convertLe le bvOld bvNew mapper)) (bvNew ++ (bvCurr \\ bvOld))
convertTr _ _ _ _ = error "le Not Just (convertTr)" convertTr _ _ _ _ = error "le Not Just (convertTr)"
-- data LambdaExpression = LambdaSpucker TypeRequester TypeRequester BoundVars | LambdaSchlucker TypeRequester BoundVars | Symbol ConVal [TypeRequester] BoundVars | Var TypeRep Int [TypeRequester] BoundVars | Constan ConVal deriving (Eq, Ord, Show) -- data LambdaExpression = LambdaSpucker TypeRequester TypeRequester BoundVars | LambdaSchlucker TypeRequester BoundVars | Symbol ConVal [TypeRequester] BoundVars | Var TypeRep Int [TypeRequester] BoundVars | Constan ConVal deriving (Eq, Ord, Show)
convertLe:: LambdaExpression -> BoundVars -> BoundVars -> Map TypeRep (Int -> Int) -> LambdaExpression convertLe :: LambdaExpression -> BoundVars -> BoundVars -> Map TypeRep (Int -> Int) -> LambdaExpression
convertLe (LambdaSpucker tr1 tr2 bvCurr) bvOld bvNew mapper = LambdaSpucker (convertTrf tr1) (convertTrf tr2) (bvNew ++ (bvCurr \\ bvOld)) convertLe (LambdaSpucker tr1 tr2 bvCurr) bvOld bvNew mapper = LambdaSpucker (convertTrf tr1) (convertTrf tr2) (bvNew ++ (bvCurr \\ bvOld))
where convertTrf tr = convertTr tr bvOld bvNew mapper where
convertTrf tr = convertTr tr bvOld bvNew mapper
convertLe (LambdaSchlucker tr bvCurr) bvOld bvNew mapper = LambdaSchlucker (convertTrf tr) (bvNew ++ (bvCurr \\ bvOld)) convertLe (LambdaSchlucker tr bvCurr) bvOld bvNew mapper = LambdaSchlucker (convertTrf tr) (bvNew ++ (bvCurr \\ bvOld))
where convertTrf tr = convertTr tr bvOld bvNew mapper where
convertTrf tr = convertTr tr bvOld bvNew mapper
convertLe (Symbol cv trs bvCurr) bvOld bvNew mapper = Symbol cv (map convertTrf trs) (bvNew ++ (bvCurr \\ bvOld)) convertLe (Symbol cv trs bvCurr) bvOld bvNew mapper = Symbol cv (map convertTrf trs) (bvNew ++ (bvCurr \\ bvOld))
where convertTrf tr = convertTr tr bvOld bvNew mapper where
convertTrf tr = convertTr tr bvOld bvNew mapper
convertLe (Var varType varNumber trs bvCurr) bvOld bvNew mapper = Var varType ((fromMaybe identity (Map.lookup varType mapper)) varNumber) (map convertTrf trs) (bvNew ++ (bvCurr \\ bvOld)) convertLe (Var varType varNumber trs bvCurr) bvOld bvNew mapper = Var varType ((fromMaybe identity (Map.lookup varType mapper)) varNumber) (map convertTrf trs) (bvNew ++ (bvCurr \\ bvOld))
where convertTrf tr = convertTr tr bvOld bvNew mapper where
convertTrf tr = convertTr tr bvOld bvNew mapper
convertLe le@(Constan _) _ _ _ = le convertLe le@(Constan _) _ _ _ = le
generateConversionIndexMap :: BoundVars -> BoundVars -> RVar (Map TypeRep (Int -> Int))
generateConversionIndexMap:: BoundVars -> BoundVars -> RVar (Map TypeRep (Int -> Int))
generateConversionIndexMap bvOld bvNew = do generateConversionIndexMap bvOld bvNew = do
funcs <- mapM (\bT -> genMapper (count bvOld bT - 1) (count bvNew bT - 1)) (nub bvOld) funcs <- mapM (\bT -> genMapper (count bvOld bT - 1) (count bvNew bT - 1)) (nub bvOld)
return $ Map.fromList $ zip (nub bvOld) funcs return $ Map.fromList $ zip (nub bvOld) funcs
genMapper:: Int -> Int -> RVar (Int -> Int) genMapper :: Int -> Int -> RVar (Int -> Int)
genMapper i j | i == j = return identity genMapper i j
| i < j = return $ \int -> if int <= i then int else int + (j-i) | i == j = return identity
| i > j = do | i < j = return $ \int -> if int <= i then int else int + (j - i)
permutationForUnbound <- genPermutation i j | i > j = do
return $ genMapperRandomAssment i j permutationForUnbound permutationForUnbound <- genPermutation i j
| otherwise = error "impossible case in genMapper" return $ genMapperRandomAssment i j permutationForUnbound
| otherwise = error "impossible case in genMapper"
genMapperRandomAssment:: Int -> Int -> [Int] -> Int -> Int genMapperRandomAssment :: Int -> Int -> [Int] -> Int -> Int
genMapperRandomAssment i j permutationForUnbound int | int <= j = int genMapperRandomAssment i j permutationForUnbound int
| int > i = int - (i-j) | int <= j = int
| otherwise = permutationForUnbound !! (int - j - 1) | int > i = int - (i - j)
| otherwise = permutationForUnbound !! (int - j - 1)
genPermutation:: Int -> Int -> RVar [Int] genPermutation :: Int -> Int -> RVar [Int]
genPermutation i j = replicateM (i - j) (uniform 0 j) genPermutation i j = replicateM (i - j) (uniform 0 j)
isCompatibleTr:: TypeRequester -> TypeRequester -> Bool isCompatibleTr :: TypeRequester -> Int -> Int -> TypeRequester -> Int -> Bool
isCompatibleTr tr1@(TR trep1 _ bound1) tr2@(TR trep2 _ bound2) | trep1 == trep2 = allUsedBound (usedVars bound1 tr1) bound2 && allUsedBound (usedVars bound2 tr2) bound1 isCompatibleTr tr1@(TR trep1 _ bound1) maxDepthOfTR2 maxDepthOfNode tr2@(TR trep2 _ bound2) depthOfNode
| otherwise = False | trep1 == trep2 = allUsedBound (usedVars bound1 tr1) bound2 && allUsedBound (usedVars bound2 tr2) bound1 && maxDepthOfTR2 >= (depthOfTR tr2) && maxDepthOfNode >= depthOfNode
| otherwise = False
allUsedBound :: BoundVars -> BoundVars -> Bool allUsedBound :: BoundVars -> BoundVars -> Bool
allUsedBound used available = all (\x -> any (== x) available) used allUsedBound used available = all (\x -> any (== x) available) used
usedVars :: BoundVars -> TypeRequester -> BoundVars usedVars :: BoundVars -> TypeRequester -> BoundVars
usedVars boundOld tr@(TR trep1 (Just (Var trp ind trs _)) _) = if any (== trp) boundOld && count boundOld trp > ind then trp : concatMap (usedVars boundOld) trs else concatMap (usedVars boundOld) trs usedVars boundOld tr@(TR trep1 (Just (Var trp ind trs _)) _) = if any (== trp) boundOld && count boundOld trp > ind then trp : concatMap (usedVars boundOld) trs else concatMap (usedVars boundOld) trs
usedVars boundOld tr@(TR trep1 (Just le) _) = concatMap (usedVars boundOld) (asList le) usedVars boundOld tr@(TR trep1 (Just le) _) = concatMap (usedVars boundOld) (asList le)
usedVars _ _ = error "Nothing in usedVars" usedVars _ _ = error "Nothing in usedVars"
boundsConvertable :: BoundVars -> BoundVars -> Bool
boundsConvertable bv1 bv2 = length (nub bv2) == length (nub bv1) && length (intersect (nub bv1) bv2) == length (nub bv1)
boundsConvertable:: BoundVars -> BoundVars -> Bool findIndicesWhere :: TypeRequester -> (TypeRequester -> Int -> Bool) -> Int -> Int -> [(TypeRequester, Int)]
boundsConvertable bv1 bv2 = length (nub bv2) == length (nub bv1) && length (intersect (nub bv1) bv2) == length (nub bv1) findIndicesWhere tr@(TR _ (Just le@(LambdaSchlucker _ _)) _) filte indx currDepth = if filte tr currDepth then (tr, indx + 1) : (findIndicesWhere' (asList le) filte (indx + 1) (currDepth)) else (findIndicesWhere' (asList le) filte (indx + 1) (currDepth))
findIndicesWhere tr@(TR _ lE _) filte indx currDepth = case lE of
Just le -> if filte tr currDepth then (tr, indx + 1) : (findIndicesWhere' (asList le) filte (indx + 1) (currDepth + 1)) else (findIndicesWhere' (asList le) filte (indx + 1) (currDepth + 1))
Nothing -> error "Nothing in findIndicesWhere"
findIndicesWhere' :: [TypeRequester] -> (TypeRequester -> Int -> Bool) -> Int -> Int -> [(TypeRequester, Int)]
findIndicesWhere:: TypeRequester -> (TypeRequester -> Bool) -> Int -> [(TypeRequester, Int)] findIndicesWhere' [] _ _ _ = []
findIndicesWhere tr@(TR t lE _) filte indx = case lE of findIndicesWhere' [tr] f indx currDepth = (findIndicesWhere tr f indx currDepth)
Just le -> if filte tr then (tr, indx+1):(findIndicesWhere' (asList le) filte (indx+1)) else (findIndicesWhere' (asList le) filte (indx+1)) findIndicesWhere' (tr : trs) f indx currDepth = (findIndicesWhere tr f indx currDepth) ++ (findIndicesWhere' trs f (indx + countTrsR tr) currDepth)
Nothing -> error "Nothing in findIndicesWhere"
findIndicesWhere':: [TypeRequester] -> (TypeRequester -> Bool) -> Int -> [(TypeRequester, Int)]
findIndicesWhere' [] _ _ = []
findIndicesWhere' [tr] f indx = (findIndicesWhere tr f indx)
findIndicesWhere' (tr:trs) f indx = (findIndicesWhere tr f indx) ++ (findIndicesWhere' trs f (indx + countTrsR tr))
replaceAtR :: Int -> TypeRequester -> TypeRequester -> TypeRequester replaceAtR :: Int -> TypeRequester -> TypeRequester -> TypeRequester
replaceAtR 1 _ with = with replaceAtR 1 _ with = with
@@ -351,6 +369,7 @@ depthLeftAndTypeAtR (TR _ (Just le) _) indexLeft depthLeft = depthLeftAndTypeAt
depthLeftAndTypeAtR (TR _ Nothing _) indexLeft depthLeft = error "Nothing in depthLeftAndTypeAtR" depthLeftAndTypeAtR (TR _ Nothing _) indexLeft depthLeft = error "Nothing in depthLeftAndTypeAtR"
depthLeftAndTypeAt :: LambdaExpression -> Int -> Int -> (Int, TypeRequester) depthLeftAndTypeAt :: LambdaExpression -> Int -> Int -> (Int, TypeRequester)
depthLeftAndTypeAt le@(LambdaSchlucker tr bv) indexLeft depthLeft = depthLeftAndTypeInSubtreeWithIndex (asList le) indexLeft (depthLeft + 1)
depthLeftAndTypeAt le indexLeft depthLeft = depthLeftAndTypeInSubtreeWithIndex (asList le) indexLeft depthLeft depthLeftAndTypeAt le indexLeft depthLeft = depthLeftAndTypeInSubtreeWithIndex (asList le) indexLeft depthLeft
depthLeftAndTypeInSubtreeWithIndex :: [TypeRequester] -> Int -> Int -> (Int, TypeRequester) depthLeftAndTypeInSubtreeWithIndex :: [TypeRequester] -> Int -> Int -> (Int, TypeRequester)
@@ -365,17 +384,6 @@ countTrsR tr@(TR t lE _) = case lE of
countTrs :: LambdaExpression -> Int countTrs :: LambdaExpression -> Int
countTrs le = sum (map countTrsR (asList le)) countTrs le = sum (map countTrsR (asList le))
repeatedly :: (a -> Maybe a) -> a -> [a]
repeatedly f x = case f x of
Nothing -> []
Just y -> y : repeatedly f y
count :: (Eq a) => [a] -> a -> Int
count [] find = 0
count ys find = length xs
where
xs = [xs | xs <- ys, xs == find]
-- Test Stuff -- Test Stuff
testConstInt :: TypeRequester testConstInt :: TypeRequester
@@ -535,34 +543,3 @@ eToLambdaExpressionShort (Constan (valS)) = valS
res :: Int -> ResClass res :: Int -> ResClass
res = ((\lInt0 -> ((iteClass ((eqInt ((lInt0) :: (Int)) ((1) :: (Int))) :: (Bool)) ((Class1) :: (ResClass)) ((iteClass ((eqInt ((lInt0) :: (Int)) ((2) :: (Int))) :: (Bool)) ((Class2) :: (ResClass)) ((iteClass ((eqInt ((lInt0) :: (Int)) ((3) :: (Int))) :: (Bool)) ((Class3) :: (ResClass)) ((Class3) :: (ResClass))) :: (ResClass))) :: (ResClass))) :: (ResClass))) :: (Int -> ResClass)) res = ((\lInt0 -> ((iteClass ((eqInt ((lInt0) :: (Int)) ((1) :: (Int))) :: (Bool)) ((Class1) :: (ResClass)) ((iteClass ((eqInt ((lInt0) :: (Int)) ((2) :: (Int))) :: (Bool)) ((Class2) :: (ResClass)) ((iteClass ((eqInt ((lInt0) :: (Int)) ((3) :: (Int))) :: (Bool)) ((Class3) :: (ResClass)) ((Class3) :: (ResClass))) :: (ResClass))) :: (ResClass))) :: (ResClass))) :: (Int -> ResClass))
meanOfAccuricyPerClass :: (Enum r, Bounded r, Eq r) => [(r, r)] -> R
meanOfAccuricyPerClass results = mean $ map (accuracyInClass results) [minBound .. maxBound]
geomeanOfAccuricyPerClass :: (Enum r, Bounded r, Eq r) => [(r, r)] -> R
geomeanOfAccuricyPerClass results = geomean $ map (accuracyInClass results) [minBound .. maxBound]
geomeanOfDistributionAccuracy :: (Enum r, Bounded r, Eq r) => [(r, r)] -> R
geomeanOfDistributionAccuracy results = geomean $ map (distributionAccuracyForClass results) [minBound .. maxBound]
distributionAccuracyForClass :: (Eq r) => [(r, r)] -> r -> R
distributionAccuracyForClass results clas = (1 - (min 1 (fromIntegral (abs ((length (inResClass results clas)) - (length (inClass results clas)))) / fromIntegral (length (inClass results clas))))) * 100
mean :: (Show f, Floating f) => [f] -> f
mean values = (sum values) * (1 / (fromIntegral (length values)))
geomean :: (Show f, Floating f) => [f] -> f
geomean values = (product values) ** (1 / (fromIntegral (length values)))
accuracyInClass :: (Eq r) => [(r, r)] -> r -> R
accuracyInClass results clas = ((accuracy'(inResClass results clas)) * 100) / fromIntegral (length (inClass results clas))
inClass :: (Eq r) => [(r, r)] -> r -> [(r, r)]
inClass results clas = (filter ((clas ==) . fst) results)
inResClass :: (Eq r) => [(r, r)] -> r -> [(r, r)]
inResClass results clas = (filter ((clas ==) . snd) results)
accuracy' :: (Eq r) => [(r, r)] -> R
accuracy' results = fromIntegral $ length (filter (\(target, res) -> (res == target)) results)

578
lib/LambdaCalculusV2.hs Normal file
View File

@@ -0,0 +1,578 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeAbstractions #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedLists #-}
{-# LANGUAGE FlexibleInstances #-}
module LambdaCalculusV2 where
import Data.Dynamic
import Data.Kind
import qualified Data.Set as Set
import qualified Data.List.NonEmpty as NE
import qualified Data.Map.Strict as Map
import Data.Random
import Data.Typeable
import Debug.Trace as DB
import qualified Data.Text as T
import GA
import Protolude
import Protolude.Error
import Protolude.Partial
import qualified Type.Reflection as Ref
import Utils
data BoundSymbol where
BoundSymbol :: (Typeable a) => Ref.TypeRep a -> a -> Maybe Text -> BoundSymbol
type Bindings = Map.Map (Ref.SomeTypeRep) Int
data SomeSimplyTypedLambdaExpression where
SomeSimplyTypedLambdaExpression :: (Typeable a) => SimplyTypedLambdaExpression a -> SomeSimplyTypedLambdaExpression
-- We specify a and use GADTs to allow Haskell to guarantee full type safety over these expressions!
-- This gurantees us that a SimplyTypedLambdaExpression a describes a lambda expression of type a!
data SimplyTypedLambdaExpression t where
Application :: (Typeable a, Typeable b) => SimplyTypedLambdaExpression (a -> b) -> SimplyTypedLambdaExpression a -> SimplyTypedLambdaExpression b -- e = e1 e2
Abstraction :: (Typeable (a -> b), Typeable b) => Ref.TypeRep a -> SimplyTypedLambdaExpression (b) -> SimplyTypedLambdaExpression (a -> b) -- e = λx:a. e
VariableReference :: (Typeable a) => Ref.TypeRep a -> Int -> SimplyTypedLambdaExpression a -- e = x this Includes predefined function use!
Constant :: (Typeable a, Ord a, Hashable a, Show a) => a -> SimplyTypedLambdaExpression a -- e = c
instance Eq (SimplyTypedLambdaExpression t) where
e1 == e2 = compare e1 e2 == EQ
instance Ord (SimplyTypedLambdaExpression t) where
compare (Application (stleAtoB1 :: SimplyTypedLambdaExpression (a1 -> t)) (stleA1 :: SimplyTypedLambdaExpression a1)) (Application (stleAtoB2 :: SimplyTypedLambdaExpression (a2 -> t)) (stleA2 :: SimplyTypedLambdaExpression a2)) = case eqT @a1 @a2 of
Just Refl -> (compare stleAtoB1 stleAtoB2) `thenCmp` (compare stleA1 stleA2)
_ -> compare (Ref.SomeTypeRep (Ref.TypeRep @a1)) (Ref.SomeTypeRep (Ref.TypeRep @a2))
compare (Abstraction rep1 stle1) (Abstraction rep2 stle2) = (compare rep1 rep2) `thenCmp` (compare stle1 stle2)
compare (VariableReference repA inx1) (VariableReference repB inx2) = (compare repA repB) `thenCmp` (compare inx1 inx2)
compare (Constant res1) (Constant res2) = compare res1 res2
compare (Application _ _) _ = LT
compare _ (Application _ _) = GT
compare (Abstraction _ _) _ = LT
compare _ (Abstraction _ _) = GT
compare (VariableReference _ _) _ = LT
compare _ (VariableReference _ _) = GT
instance Hashable (SimplyTypedLambdaExpression t) where
hashWithSalt salt (Application stleAtoB stleA) = salt `hashWithSalt` (1 :: Int) `hashWithSalt` stleAtoB `hashWithSalt` stleA
hashWithSalt salt (Abstraction rep stle) = salt `hashWithSalt` (2 :: Int) `hashWithSalt` rep `hashWithSalt` stle
hashWithSalt salt (VariableReference rep inx) = salt `hashWithSalt` (3 :: Int) `hashWithSalt` rep `hashWithSalt` inx
hashWithSalt salt (Constant res) = salt `hashWithSalt` (4 :: Int) `hashWithSalt` res
thenCmp :: Ordering -> Ordering -> Ordering
thenCmp EQ o2 = o2
thenCmp o1 _ = o1
data ConstVal where
ConstVal :: (Typeable a, Ord a, Hashable a, Show a) => Ref.TypeRep a -> RVar a -> ConstVal
data ExpressionWeights = ExpressionWeights
{ application :: Int,
abstraction :: Int,
variableReference :: Int,
constant :: Int,
-- chance in percent an Application will (try to) work towards something from the boundVars becoming usable. I recommend values over 90.
functionBias :: Int
}
data LambdaEnviroment a = LambdaEnviroment
{ functions :: [BoundSymbol],
constants :: [ConstVal],
maxDepth :: Int,
weights :: ExpressionWeights,
-- likelyhood of an sub-expression to be mutated
mutationStrength :: Float,
-- likelyhood of an crossover attempt at a sub-expression
crossoverStrength :: Float
}
data FittnesRes = FittnesRes
{ total :: R,
fitnessTotal :: R,
fitnessGeoMean :: R,
fitnessMean :: R,
accuracy :: R,
biasSize :: R,
totalSize :: N
}
deriving (Show)
instance Fitness FittnesRes where
getR = total
data Dataset t where
Input :: (Typeable a, Typeable b) => [a] -> Dataset b -> Dataset (a -> b)
Result :: (Typeable a, Eq a, Enum a, Bounded a) => [a] -> Dataset a
data ExecutionEnviroment e = ExecutionEnviroment {
fun :: [BoundSymbol],
training :: Bool,
trainingData :: Dataset e,
testData :: Dataset e
}
data ResultList where
Res :: (Typeable a, Eq a, Enum a, Bounded a) => [(a,a)] -> ResultList
instance Typeable a => Evaluator (SimplyTypedLambdaExpression a) (ExecutionEnviroment a) FittnesRes where
fitness' ee@(ExecutionEnviroment {fun}) e = evalResult ee e (eval fun e)
evalResult :: ExecutionEnviroment a -> SimplyTypedLambdaExpression a -> a -> FittnesRes
evalResult (ExecutionEnviroment {training, trainingData, testData}) tr result = FittnesRes
{ total = (\(Res r) -> meanOfDistributionAccuracy r) res,
fitnessTotal = fitness',
fitnessMean = (\(Res r) -> meanOfAccuricyPerClass r) res ,
fitnessGeoMean = (\(Res r) -> meanOfDistributionAccuracy r) res,
accuracy = acc,
biasSize = biasSmall,
totalSize = expSize tr
}
where
dataS = (if training then trainingData else testData)
res = apply result dataS
acc = (\(Res r) -> (foldr (\(ts) s -> if ((fst ts) == (snd ts)) then s + 1 else s) 0 r) / fromIntegral (length r)) res
biasSmall = exp ((-(fromIntegral (expSize tr))) / 1000) -- 0 (schlecht) bis 1 (gut)
fitness' = (\(Res r) -> meanOfAccuricyPerClass r) res
score = fitness' + (biasSmall - 1)
apply :: a -> Dataset a -> ResultList
apply fun (Input b c) = applyL (map fun b) c
apply val (Result b) = Res (zip b (repeat val))
applyL :: [a] -> Dataset a -> ResultList
applyL fun (Input b c) = applyL (zipWith (\a b -> a b) fun b) c
applyL val (Result b) = Res (zip b val)
hasSymbolOfType :: forall (a :: Type). [BoundSymbol] -> Ref.TypeRep a -> Bool
hasSymbolOfType bound tr = length ((getSymbolsOfType bound tr) :: [a]) /= 0
getSymbolsOfType :: forall a. [BoundSymbol] -> Ref.TypeRep a -> [a]
getSymbolsOfType bound tr = mapMaybe (getIfType tr) bound
getBoundSymbolsOfType :: forall a. [BoundSymbol] -> Ref.TypeRep a -> [BoundSymbol]
getBoundSymbolsOfType bound tr = mapMaybe (getSymbolIfType tr) bound
getSymbolIfType :: forall a. Ref.TypeRep a -> BoundSymbol -> Maybe BoundSymbol
getSymbolIfType rep b@(BoundSymbol t _ _)
| Just Ref.HRefl <- t `Ref.eqTypeRep` rep = Just b
| otherwise = Nothing
getIfType :: forall a. Ref.TypeRep a -> BoundSymbol -> Maybe a
getIfType rep (BoundSymbol t val _)
| Just Ref.HRefl <- t `Ref.eqTypeRep` rep = Just val
| otherwise = Nothing
startingBindings :: [BoundSymbol] -> Bindings
startingBindings functions = (foldr (\(BoundSymbol tr _ _) map -> Map.insertWith (+) (Ref.SomeTypeRep tr) 1 map) Map.empty functions)
showSanifid :: (Show a) => a -> Text
showSanifid var = T.replace " -> " "To" (show var)
toDotE :: LambdaEnviroment a -> Text
toDotE (LambdaEnviroment {functions}) = foldr (<>) "" (map (\(BoundSymbol tr _ t, inx) -> "\"" <> (showSanifid tr) <> show inx <> "\" [style = invis label = " <> fromJust t <>"\"]\n") (concatMap (\(Ref.SomeTypeRep k,v) -> zip (getBoundSymbolsOfType functions k)[0 .. (v-1)]) (Map.toList (startingBindings functions))))
toDotI :: SimplyTypedLambdaExpression e -> Int -> Text
toDotI (Application e1 e2) inx = "\"app" <> show inx <> "\" -- " <> toDotI e1 (inx + 1) <> "\n" <> "\"app" <> show inx <> "\" -- " <> toDotI e2 (inx + 1 + expSize e1)
toDotI (Abstraction _ e) inx = "\"abs" <> show inx <> "\" -- " <> toDotI e (inx + 1)
toDotI (VariableReference tr i) _ = "\"" <> (showSanifid tr) <> show i <> "\""
toDotI (Constant c) _ = "\"" <> show c <> "\""
instance Eq SomeSimplyTypedLambdaExpression where
e1 == e2 = compare e1 e2 == EQ
instance Ord SomeSimplyTypedLambdaExpression where
compare (SomeSimplyTypedLambdaExpression (e1 :: SimplyTypedLambdaExpression a)) (SomeSimplyTypedLambdaExpression (e2 :: SimplyTypedLambdaExpression b))
| Just Refl <- eqT @a @b = compare e1 e2
| otherwise = compare (Ref.SomeTypeRep (Ref.TypeRep @a)) (Ref.SomeTypeRep (Ref.TypeRep @b))
instance Typeable a => Individual (SimplyTypedLambdaExpression a)
instance Typeable a => Environment (SimplyTypedLambdaExpression a) (LambdaEnviroment a) where
output env i = toDotE env <> toDotI i 0
nX _ = 3
new env = DB.trace "new !" ((generateFromEnv env) :: RVar (SimplyTypedLambdaExpression a))
mutate env le = (mutateUnwrapped env le)
crossover1 env le le2 = crossoverUnwrapper env le le2
crossoverUnwrapper :: (Typeable a) => LambdaEnviroment a -> SimplyTypedLambdaExpression a -> SimplyTypedLambdaExpression a -> RVar (Maybe (SimplyTypedLambdaExpression a, SimplyTypedLambdaExpression a))
crossoverUnwrapper env@(LambdaEnviroment {maxDepth, functions}) le1 le2 =
( do
(tree1, tree2) <- crossedover le1 le2 env maxDepth (startingBindings functions)
return $ if (tree2 == le2) then Nothing else Just (tree1, tree2)
)
crossedover :: forall a e. (Typeable a,Typeable e) => SimplyTypedLambdaExpression a -> SimplyTypedLambdaExpression e -> LambdaEnviroment e -> Int -> Bindings -> RVar (SimplyTypedLambdaExpression a, SimplyTypedLambdaExpression e)
crossedover le1 le2 env@(LambdaEnviroment {crossoverStrength, maxDepth, functions}) sizeLeft bound = do
roll <- uniform 0 1
let crossoverChild =
( case le1 of
(Application e1 e2) ->
( do
(elm1, partner1) <- crossedover e1 le2 env ((sizeLeft - 1) - expSize e2) bound
(elm2, partner2) <- crossedover e2 le2 env ((sizeLeft - 1) - expSize e1) bound
leftMutated <- uniform False True
let mutateLeft = if partner1 == le2 then False else (if partner2 == le2 then False else leftMutated)
return $ if mutateLeft then (Application elm1 e2, partner1) else (Application e1 elm2, partner2)
)
(Abstraction tr e) ->
( do
(elm2, partner2) <- crossedover e le2 env (sizeLeft - 1) (Map.insertWith (+) (Ref.SomeTypeRep tr) 1 bound)
return $ (Abstraction tr elm2, partner2)
)
_ -> return (le1, le2)
)
if (roll < crossoverStrength)
then
( do
maybeSwapped <- trySwapSubtree le1 sizeLeft bound le2 maxDepth (startingBindings functions)
case maybeSwapped of
Just (ler1, ler2) -> return (ler1, ler2)
_ -> crossoverChild
)
else crossoverChild
trySwapSubtree :: forall a e.(Typeable a,Typeable e) => SimplyTypedLambdaExpression a -> Int -> Bindings -> SimplyTypedLambdaExpression e -> Int -> Bindings -> RVar (Maybe (SimplyTypedLambdaExpression a, SimplyTypedLambdaExpression e))
trySwapSubtree le1 sizeLeft bound le2 sizeLeft2 bound2 = do
let possible = possibleSwapSubtrees le1 sizeLeft bound le2 sizeLeft2 bound2
case possible of
[] -> return Nothing
ne -> Just <$> randomElement ne
possibleSwapSubtrees :: forall a e.(Typeable a,Typeable e) => SimplyTypedLambdaExpression a -> Int -> Bindings -> SimplyTypedLambdaExpression e -> Int -> Bindings -> [(SimplyTypedLambdaExpression a, SimplyTypedLambdaExpression e)]
possibleSwapSubtrees le1 sizeLeft bound le2 sizeLeft2 bound2
| Just Refl <- eqT @a @e = if compatibleSubtree sizeLeft2 bound2 le1 && compatibleSubtree sizeLeft bound le2 then (adaptSubtree bound2 le1, adaptSubtree bound le2) : continue else continue
| otherwise = continue
where
continue = (case le2 of
Application e1 e2 -> (map (\(li1,li2) -> (li1, (Application e1 li2))) (possibleSwapSubtrees le1 sizeLeft bound e2 (sizeLeft2 - 1 - expSize e1) bound2) ) ++ (map (\(li1,li2) -> (li1, (Application li2 e2))) (possibleSwapSubtrees le1 sizeLeft bound e1 (sizeLeft2 - 1 - expSize e2) bound2) )
Abstraction t e -> (map (\(li1,li2) -> (li1, (Abstraction t li2))) (possibleSwapSubtrees le1 sizeLeft bound e (sizeLeft2 - 1) (addToBindings t bound2)))
_ -> [])
addToBindings ::Ref.TypeRep a -> Bindings -> Bindings
addToBindings t bound = (Map.insertWith (+) (Ref.SomeTypeRep t) 1 bound)
adaptSubtree :: Bindings -> SimplyTypedLambdaExpression e -> SimplyTypedLambdaExpression e
adaptSubtree bound (Application e1 e2) = (Application (adaptSubtree bound e1) (adaptSubtree bound e2))
adaptSubtree bound (Abstraction t e) = (Abstraction t (adaptSubtree (addToBindings t bound) e))
adaptSubtree bound (VariableReference tr idx) = (VariableReference tr (mod idx ( bound Map.! (Ref.SomeTypeRep tr))))
adaptSubtree _ e = e
compatibleSubtree :: Int -> Bindings -> SimplyTypedLambdaExpression e -> Bool
compatibleSubtree sizeLeft bound subtree = bound `bindingContains` (bindingReq subtree) && sizeLeft > (expSize subtree)
expSize :: SimplyTypedLambdaExpression e -> Int
expSize (Application e1 e2) = expSize e1 + expSize e2 + 1
expSize (Abstraction _ e) = expSize e + 1
expSize _ = 1
bindingReq :: SimplyTypedLambdaExpression e -> Bindings
bindingReq (Application e1 e2) = Map.unionWith (max) (bindingReq e1) (bindingReq e2)
bindingReq (Abstraction tr e) = rmFromBindings tr (bindingReq e)
bindingReq (VariableReference tr idx) = Map.singleton (Ref.SomeTypeRep tr) 1
bindingReq (Constant _) = Map.empty
rmFromBindings ::Ref.TypeRep a -> Bindings -> Bindings
rmFromBindings t bound = (Map.insertWith (\i1 i2 -> max 0 (i1 + i2)) (Ref.SomeTypeRep t) (- 1) bound)
bindingContains :: Bindings -> Bindings -> Bool
bindingContains superset subset = all (\(key,val) -> (fromMaybe 0 (Map.lookup key superset)) >= val ) (Map.toList subset)
mutateUnwrapped :: (Typeable r) => LambdaEnviroment r -> SimplyTypedLambdaExpression r -> RVar (SimplyTypedLambdaExpression r)
mutateUnwrapped env@(LambdaEnviroment {maxDepth, functions}) stle = mutated stle env maxDepth (startingBindings functions)
mutated :: forall r a. (Typeable r) => SimplyTypedLambdaExpression r -> LambdaEnviroment a -> Int -> Bindings -> RVar (SimplyTypedLambdaExpression r)
mutated (Application e1 e2) env@(LambdaEnviroment {constants, mutationStrength}) sizeLeft bound = do
roll <- uniform 0 1
if (roll < mutationStrength)
then generate env (Ref.TypeRep @r) constants sizeLeft bound
else do
sizeDistribution <- uniform 0 (sizeLeft - 1)
elm1 <- mutated e1 env sizeDistribution bound
elm2 <- mutated e2 env ((sizeLeft - 1) - sizeDistribution) bound
return $ Application elm1 elm2
mutated (Abstraction tr e) env@(LambdaEnviroment {constants, mutationStrength}) sizeLeft bound = do
roll <- uniform 0 1
if (roll < mutationStrength)
then generate env (Ref.TypeRep @r) constants sizeLeft bound
else do
elm2 <- mutated e env (sizeLeft - 1) (Map.insertWith (+) (Ref.SomeTypeRep tr) 1 bound)
return $ Abstraction tr elm2
mutated stle env@(LambdaEnviroment {constants, mutationStrength}) sizeLeft bound = do
roll <- uniform 0 1
if (roll < mutationStrength) then generate env (Ref.TypeRep @r) constants sizeLeft bound else return stle
test :: SimplyTypedLambdaExpression (Bool -> Int -> Int -> Int)
test = Abstraction (Ref.typeRep @(Bool)) (Abstraction (Ref.typeRep @(Int)) (Abstraction (Ref.typeRep @(Int)) (Constant 5)))
generateFromEnv :: forall r. (Typeable r) => LambdaEnviroment r -> RVar (SimplyTypedLambdaExpression r)
generateFromEnv env@(LambdaEnviroment {functions, constants, maxDepth}) = generate env (Ref.TypeRep @r) constants maxDepth (foldr (\(BoundSymbol tr _ _) map -> Map.insertWith (+) (Ref.SomeTypeRep tr) 1 map) Map.empty functions)
generate :: LambdaEnviroment a -> Ref.TypeRep r -> [ConstVal] -> Int -> Bindings -> RVar (SimplyTypedLambdaExpression r)
generate env tr@(Ref.Fun (Ref.TypeRep @a) (Ref.TypeRep @b)) constantTypes sizeLeft bound
| (sizeLeft > 0) && (Map.member (Ref.SomeTypeRep tr) bound) = do
let weight = weights env
let options = [(application weight, genApplication env tr constantTypes sizeLeft bound), (abstraction weight, genAbstraction env tr constantTypes sizeLeft bound), (variableReference weight, genVariableReference env tr constantTypes sizeLeft bound)]
expres <- selectWeighted options
res <- expres
return res
| (sizeLeft > 0) = do
let weight = weights env
let options = [(application weight + round (1000 * closestFractionMatch tr bndK), genApplication env tr constantTypes sizeLeft bound), (abstraction weight, genAbstraction env tr constantTypes sizeLeft bound)]
expres <- selectWeighted options
res <- expres
return res
-- Application can crate a fitting type in a smaller expression. e.g. if':: Bool -> (Int-> Int -> Bool) -> (Int-> Int -> Bool) -> (Int-> Int -> Bool) and target type (Int-> Int -> Bool) -> (Int-> Int -> Bool) -> (Int-> Int -> Bool) can be finished in one Application (if' True::(Int-> Int -> Bool) -> (Int-> Int -> Bool) -> (Int-> Int -> Bool)) and one Var or constant, but resoving it purely with Abstractions would require 5 abstractions and one constant or var
-- | (any (< typeDepth tr) (mapMaybe (sizeMising tr) bndK)) = do
-- let weight = weights env
-- let options = [(application weight + (typeDepth tr - (minimum (mapMaybe (sizeMising tr) bndK))), genApplication env tr constantTypes sizeLeft bound), (abstraction weight, genAbstraction env tr constantTypes sizeLeft bound)]
-- expres <- selectWeighted options
-- res <- expres
-- return res
| (Map.member (Ref.SomeTypeRep tr) bound) = do
let weight = weights env
let options = [(abstraction weight, genAbstraction env tr constantTypes sizeLeft bound), (variableReference weight, genVariableReference env tr constantTypes sizeLeft bound)]
expres <- selectWeighted options
res <- expres
return res
| otherwise = do
res <- genAbstraction env tr constantTypes sizeLeft bound
return res
where
bndK = Map.keys bound
generate env tr constantTypes sizeLeft bound
| (sizeLeft > 0) && (Map.member (Ref.SomeTypeRep tr) bound) = do
let weight = weights env
let options = [(application weight, genApplication env tr constantTypes sizeLeft bound), (constant weight, genConstant tr constantTypes sizeLeft bound), (variableReference weight, genVariableReference env tr constantTypes sizeLeft bound)]
expres <- selectWeighted options
res <- expres
return res
| (sizeLeft > 0) = do
let weight = weights env
let options = [(application weight + round (1000 * closestFractionMatch tr bndK), genApplication env tr constantTypes sizeLeft bound), (constant weight, genConstant tr constantTypes sizeLeft bound)]
expres <- selectWeighted options
res <- expres
return res
| (Map.member (Ref.SomeTypeRep tr) bound) = do
let weight = weights env
let options = [(constant weight, genConstant tr constantTypes sizeLeft bound), (variableReference weight, genVariableReference env tr constantTypes sizeLeft bound)]
expres <- selectWeighted options
res <- expres
return res
| otherwise = do
res <- genConstant tr constantTypes sizeLeft bound
return res
where
bndK = Map.keys bound
genVariableReference :: LambdaEnviroment a -> Ref.TypeRep r -> [ConstVal] -> Int -> Bindings -> RVar (SimplyTypedLambdaExpression r)
genVariableReference _ tr@(Ref.TypeRep) _ _ bound = do
typeIndex <- uniform 0 (((Map.!) bound (Ref.SomeTypeRep tr)) - 1)
return $ (VariableReference tr typeIndex)
genConstant :: Ref.TypeRep r -> [ConstVal] -> Int -> Bindings -> RVar (SimplyTypedLambdaExpression r)
genConstant (Ref.TypeRep @a) constantTypes _ _ = do
val <- (constantGen constantTypes) :: RVar (SimplyTypedLambdaExpression a)
return $ val
constantGen :: forall a. (Typeable a) => [ConstVal] -> RVar (SimplyTypedLambdaExpression a)
constantGen ((ConstVal tr rVal) : rest)
| Just Ref.HRefl <- Ref.typeRep @a `Ref.eqTypeRep` tr = Constant <$> rVal
| otherwise = constantGen rest
constantGen [] = error $ "unknown constant " <> show (Ref.typeRep @a)
genAbstraction :: forall r a. LambdaEnviroment a -> Ref.TypeRep r -> [ConstVal] -> Int -> Bindings -> RVar (SimplyTypedLambdaExpression r)
genAbstraction env tr@(Ref.Fun trA@(Ref.TypeRep) trB@(Ref.TypeRep)) constantTypes sizeLeft bound
| Just Ref.HRefl <- Ref.typeRep @Type `Ref.eqTypeRep` Ref.typeRepKind trA,
Just Ref.HRefl <- Ref.typeRep @Type `Ref.eqTypeRep` Ref.typeRepKind trB = do
child <- generate env trB constantTypes (sizeLeft - 1) (Map.insertWith (+) (Ref.SomeTypeRep trA) 1 bound)
return $ Abstraction trA child
genAbstraction _ tr _ _ _ = error $ "cannot generate Abstraction for " <> show tr
-- generate: e:a = e1:b->a e2:b
-- the by far most complex functions in this module! why?
-- 1. we need to sensibly limit how insane we make b, favorably without excluding anything completely!
-- 2. we need this function to heavily lean towards generating an b->a available in Bindings, so we are likely to use any predefined functions... at all
genApplication :: forall r c a. LambdaEnviroment a -> Ref.TypeRep r -> [ConstVal] -> Int -> Bindings -> RVar (SimplyTypedLambdaExpression r)
genApplication env@(LambdaEnviroment {weights}) tr constantTypes sizeLeft bound
| (sizeLeft <= 0) = genApplicationClosestToCompletion env tr constantTypes bound
| otherwise = do
i <- uniform 0 100
( if i < (functionBias weights) && any (1 >) (mapMaybe (matchedFractionS tr) (Map.keys bound))
then (genApplicationTowardsBound (maximum (filter (1 >) (mapMaybe (matchedFractionS tr) (Map.keys bound)))) env tr constantTypes sizeLeft bound)
else (genRandomApplication env tr constantTypes sizeLeft bound)
)
closestFractionMatch :: Ref.TypeRep r -> [Ref.SomeTypeRep] -> Float
closestFractionMatch tr trs | any (1 >) (mapMaybe (matchedFractionS tr) (trs)) = (maximum (filter (1 >) (mapMaybe (matchedFractionS tr) (trs))))
| otherwise = 0
genRandomApplication :: forall a r c. LambdaEnviroment a -> Ref.TypeRep r -> [ConstVal] -> Int -> Bindings -> RVar (SimplyTypedLambdaExpression r)
genRandomApplication env tr constantTypes sizeLeft bound = do
t1 <- randomType constantTypes
genApplicationWithTypeOfS t1 env tr constantTypes sizeLeft bound
randomType :: [ConstVal] -> RVar Ref.SomeTypeRep
randomType constantTypes = do
functon :: Int <- (uniform 0 100)
ret <-
if functon < 25
then
( do
tr1 <- randomType constantTypes
tr2 <- randomType constantTypes
return (mkFunTy tr1 tr2)
)
else
( do
(ConstVal _ (_ :: RVar t1)) <- randomElement constantTypes
return $ Ref.SomeTypeRep (Ref.TypeRep @t1)
)
return ret
genApplicationClosestToCompletion :: forall r a. LambdaEnviroment a -> Ref.TypeRep r -> [ConstVal] -> Bindings -> RVar (SimplyTypedLambdaExpression r)
genApplicationClosestToCompletion env tr constantTypes bound = do
(ref) <- nextTypeFromClosestBound tr bound
genApplicationWithTypeOfS ref env tr constantTypes 0 bound
nextTypeFromClosestBound :: Ref.TypeRep r -> Bindings -> RVar Ref.SomeTypeRep
nextTypeFromClosestBound trB bound = randomElement ((getMinimasByMaybe (sizeMising trB) (filter (matchingTypesS trB) (Map.keys bound))))
genApplicationTowardsBound :: forall r c a. Float -> LambdaEnviroment a -> Ref.TypeRep r -> [ConstVal] -> Int -> Bindings -> RVar (SimplyTypedLambdaExpression r)
genApplicationTowardsBound matchedFrac env tr constantTypes sizeLeft bound
| nextMatchedFrac > 0 = do
(f :: Float) <- uniform 0 1
bs <- randomElement (filter (\bs -> Just matchedFrac == matchedFractionS tr bs) (Map.keys bound))
if (f < matchedFrac + 1) then (genApplicationWithTypeOfS ((nextTypeS tr bs)) env tr constantTypes sizeLeft bound) else (genApplicationTowardsBound nextMatchedFrac env tr constantTypes sizeLeft bound)
| otherwise = do
bs <- randomElement (filter (\bs -> Just matchedFrac == matchedFractionS tr bs) (Map.keys bound))
genApplicationWithTypeOfS ((nextTypeS tr bs)) env tr constantTypes sizeLeft bound
where
nextMatchedFrac = (if (any (matchedFrac >) (mapMaybe (matchedFractionS tr) (Map.keys bound))) then (maximum (filter (matchedFrac >) (mapMaybe (matchedFractionS tr) (Map.keys bound)))) else 0) --todo nicer!
-- how many Base types will need to be generated for bound to fit onto tr. This equals the size of the subtree that needs to be generated.
sizeMising :: Ref.TypeRep r -> Ref.SomeTypeRep -> Maybe Int
sizeMising tr (Ref.SomeTypeRep trbs)
| matchingTypes tr trbs = Just $ (typeDepth tr) - (typeDepth trbs)
| otherwise = Nothing
matchedFractionS :: Ref.TypeRep r -> Ref.SomeTypeRep -> Maybe Float
matchedFractionS tr (Ref.SomeTypeRep trbs) = matchedFraction tr trbs
matchedFraction :: Ref.TypeRep r -> Ref.TypeRep a -> Maybe Float
matchedFraction tr trbs
| matchingTypes tr trbs = Just $ fromIntegral (typeDepth trbs) / fromIntegral (typeDepth tr)
| otherwise = Nothing
nextTypeS :: Ref.TypeRep r -> Ref.SomeTypeRep -> Ref.SomeTypeRep
nextTypeS tr (Ref.SomeTypeRep trbs) = nextType tr trbs
nextType :: Ref.TypeRep r -> Ref.TypeRep a -> Ref.SomeTypeRep
nextType trR@(Ref.Fun (from) (to)) avail
| Just Ref.HRefl <- (to `Ref.eqTypeRep` avail),
Just Ref.HRefl <- Ref.typeRep @Type `Ref.eqTypeRep` Ref.typeRepKind from =
Ref.SomeTypeRep from
| otherwise = nextType to avail
nextType tra trbs = error ("can't extract nextType from " <> show tra <> " and " <> show trbs)
matchingTypesS :: Ref.TypeRep r -> Ref.SomeTypeRep -> Bool
matchingTypesS tr (Ref.SomeTypeRep trbs) = matchingTypes tr trbs
matchingTypes :: Ref.TypeRep a -> Ref.TypeRep b -> Bool
matchingTypes tra trb | Ref.SomeTypeRep tra == Ref.SomeTypeRep trb = True
matchingTypes (Ref.Fun _ (traRes :: Ref.TypeRep aRes)) trb = matchingTypes (traRes :: Ref.TypeRep aRes) trb
matchingTypes _ _ = False
typeSize :: Ref.TypeRep r -> Int
typeSize (Ref.Fun _ trb) = 1 + (typeSize trb)
typeSize _ = 1
typeDepth :: Ref.TypeRep r -> Int
typeDepth (Ref.Fun _ (trb :: Ref.TypeRep b)) = 1 + (typeDepth (trb :: Ref.TypeRep b))
typeDepth _ = 1
genApplicationWithTypeOfS :: forall r a. Ref.SomeTypeRep -> LambdaEnviroment a -> Ref.TypeRep r -> [ConstVal] -> Int -> Bindings -> RVar (SimplyTypedLambdaExpression r)
genApplicationWithTypeOfS (Ref.SomeTypeRep btr@(Ref.TypeRep))
| Just Ref.HRefl <- Ref.typeRep @Type `Ref.eqTypeRep` Ref.typeRepKind btr = genApplicationWithTypeOfB btr
genApplicationWithTypeOfS (Ref.SomeTypeRep btr) = error $ "typeRepKind not Type: " <> show (Ref.typeRepKind btr)
genApplicationWithTypeOfB :: forall r a (b :: Type). Ref.TypeRep b -> LambdaEnviroment a -> Ref.TypeRep r -> [ConstVal] -> Int -> Bindings -> RVar (SimplyTypedLambdaExpression r)
genApplicationWithTypeOfB trB@(Ref.TypeRep) env trR@(Ref.TypeRep) constantTypes sizeLeft bound = do
sizeDistribution <- uniform 0 (sizeLeft - 1)
right <- generate env trB constantTypes sizeDistribution bound
left <- generate env (Ref.Fun (Ref.TypeRep @b) trR) constantTypes ((sizeLeft - 1) - sizeDistribution) bound
return $ Application left right
selectWeighted :: [(Int, a)] -> RVar a
selectWeighted x = do
let total = Protolude.sum (map fst x)
selection <- uniform 1 total
return $ selectAtWeight selection (NE.fromList x)
selectAtWeight :: Int -> NonEmpty (Int, a) -> a
selectAtWeight _ (x :| []) = snd x
selectAtWeight w (x :| xs)
| fst x >= w = snd x
| otherwise = selectAtWeight (w - fst x) (NE.fromList xs)
eval :: [BoundSymbol] -> SimplyTypedLambdaExpression ex -> ex
eval bound (Abstraction rep stle) = lam bound rep stle
eval bound (Application stleAtoB stleA) = (eval bound stleAtoB) (eval bound stleA)
eval bound (VariableReference rep inx) = (getSymbolsOfType bound rep) !! inx
eval _ (Constant res) = res
lam :: [BoundSymbol] -> Ref.TypeRep a -> SimplyTypedLambdaExpression (b) -> (a -> b)
lam bound Ref.TypeRep stle = \(aVal :: a) -> eval (appendToBoundVar bound aVal) stle
appendToBoundVar :: (Typeable a) => [BoundSymbol] -> a -> [BoundSymbol]
appendToBoundVar bv val = bv ++ [BoundSymbol (Ref.typeOf val) val Nothing]
listAppend :: (Typeable a) => a -> Maybe [Dynamic] -> Maybe [Dynamic]
listAppend val (Just dyns) = Just (dyns ++ [toDyn val])
listAppend val (Nothing) = Just [toDyn val]
getMinimasBy :: (Ord b) => (a -> b) -> [a] -> [a]
getMinimasBy fun as = filter (\a -> fun a == minOverAs) as
where
minOverAs = minimum (map fun as)
getMinimasByMaybe :: (Ord b) => (a -> Maybe b) -> [a] -> [a]
getMinimasByMaybe fun as = filter (\a -> fun a == Just minOverAs) as
where
minOverAs = minimum (mapMaybe fun as)
getMaximasBy :: (Ord b) => (a -> b) -> [a] -> [a]
getMaximasBy fun as = filter (\a -> fun a == maxOverAs) as
where
maxOverAs = maximum (map fun as)
getMaximasByMaybe :: (Ord b) => (a -> Maybe b) -> [a] -> [a]
getMaximasByMaybe fun as = filter (\a -> fun a == Just maxOverAs) as
where
maxOverAs = maximum (mapMaybe fun as)

21
lib/Test.hs Normal file
View File

@@ -0,0 +1,21 @@
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE Trustworthy #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE NoImplicitPrelude #-}
module Main where
import qualified GA
import Protolude
main :: IO ()
main = do
_ <- GA.runTests
return ()
if' :: Bool -> a -> a -> a
if' True x _ = x
if' False _ y = y

63
lib/Utils.hs Normal file
View File

@@ -0,0 +1,63 @@
{-# LANGUAGE NoImplicitPrelude #-}
module Utils where
import GA (R)
import Protolude
takeFraktion :: (RealFrac f) => f -> [a] -> [a]
takeFraktion frac list = take (floor (frac * (fromIntegral (length list)))) list
dropFraktion :: (RealFrac f) => f -> [a] -> [a]
dropFraktion frac list = drop (floor (frac * (fromIntegral (length list)))) list
meanOfAccuricyPerClass :: (Enum r, Bounded r, Eq r) => [(r, r)] -> R
meanOfAccuricyPerClass results = mean $ map (accuracyInClass results) [minBound .. maxBound]
geomeanOfAccuricyPerClass :: (Enum r, Bounded r, Eq r) => [(r, r)] -> R
geomeanOfAccuricyPerClass results = geomean $ map (accuracyInClass results) [minBound .. maxBound]
geomeanOfDistributionAccuracy :: (Enum r, Bounded r, Eq r) => [(r, r)] -> R
geomeanOfDistributionAccuracy results = geomean $ map (distributionAccuracyForClass results) [minBound .. maxBound]
meanOfDistributionAccuracy :: (Enum r, Bounded r, Eq r) => [(r, r)] -> R
meanOfDistributionAccuracy results = mean $ map (distributionAccuracyForClass results) [minBound .. maxBound]
distributionAccuracyForClass :: (Eq r) => [(r, r)] -> r -> R
distributionAccuracyForClass results clas = (1 - (min 1 (fromIntegral (abs ((length (inResClass results clas)) - (length (inClass results clas)))) / fromIntegral (length (inClass results clas))))) * 100
mean :: (Show f, RealFloat f) => [f] -> f
mean values = (sum filteredValues) * (1 / (fromIntegral (length filteredValues)))
where
filteredValues = filter (not . isNaN) values
geomean :: (Show f, RealFloat f) => [f] -> f
geomean values = (product filteredValues) ** (1 / (fromIntegral (length filteredValues)))
where
filteredValues = filter (not . isNaN) values
accuracyInClass :: (Eq r) => [(r, r)] -> r -> R
accuracyInClass results clas = ((accuracy' (inResClass results clas)) * 100) / fromIntegral (length (inClass results clas))
inClass :: (Eq r) => [(r, r)] -> r -> [(r, r)]
inClass results clas = (filter ((clas ==) . fst) results)
inResClass :: (Eq r) => [(r, r)] -> r -> [(r, r)]
inResClass results clas = (filter ((clas ==) . snd) results)
accuracy' :: (Eq r) => [(r, r)] -> R
accuracy' results = fromIntegral $ length (filter (\(target, res) -> (res == target)) results)
repeatedly :: (a -> Maybe a) -> a -> [a]
repeatedly f x = case f x of
Nothing -> []
Just y -> y : repeatedly f y
contains :: (Eq a, Foldable t) => t a -> a -> Bool
contains list val = any (== val) list
count :: (Eq a) => [a] -> a -> Int
count [] _ = 0
count ys find = length xs
where
xs = [xs | xs <- ys, xs == find]

9
run.sbatch Executable file
View File

@@ -0,0 +1,9 @@
#!/usr/bin/env bash
#SBATCH --time=18:00:00
#SBATCH --partition=cpu
#SBATCH --array=0-30
#SBATCH --output=./output/output_run_%j.txt
#SBATCH --error=./output/error_run_%j.txt
#SBATCH --nodelist=oc-compute02
#SBATCH --mem=3G
srun nix develop --command stack --no-nix --system-ghc --no-install-ghc run haga-lambda

69
src-students/Main.hs Normal file
View File

@@ -0,0 +1,69 @@
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE NoImplicitPrelude #-}
import Options.Applicative
import Pipes
import Protolude hiding (for)
import System.IO
import Seminar
import Szenario191
data Options = Options
{ iterations :: !N,
populationSize :: !N
}
options :: Parser Options
options =
Options
<$> option
auto
( long "iterations"
<> short 'i'
<> metavar "N"
<> value 1500
<> help "Number of iterations"
)
<*> option
auto
( long "population-size"
<> short 'p'
<> metavar "N"
<> value 400
<> help "Population size"
)
optionsWithHelp :: ParserInfo Options
optionsWithHelp =
info
(helper <*> options)
( fullDesc
<> progDesc "Run a GA"
<> header "haga - Haskell implementations of EAs"
)
main :: IO ()
main =
execParser optionsWithHelp >>= \opts -> do
hSetBuffering stdout NoBuffering
let cfg = GaRunConfig {
enviroment = AssignmentEnviroment (students prios, topics prios),
initialEvaluator = prios,
selectionType = Tournament 3,
termination = (steps (iterations opts)),
poulationSize = (populationSize opts),
stepSize = 120,
elitismRatio = 5/100
}
pop' <- runEffect (for (run cfg) logCsv)
prios' <- calc prios pop'
let (res, _) = bests prios' 5 pop'
prios' <- calc prios' res
mapM_ (format prios') res
where
format seminarL s = do
let f = fitness' seminarL s
putErrText $ show f <> "\n" <> output (AssignmentEnviroment (students prios, topics prios)) s
logCsv = putText . csv
csv (t, f) = show t <> " " <> show f

View File

@@ -107,6 +107,14 @@ instance Pretty AssignmentEnviroment where
pretty (AssignmentEnviroment (persons,assignables)) = "Persons: " <> show persons <> " Assignables: " <> show assignables pretty (AssignmentEnviroment (persons,assignables)) = "Persons: " <> show persons <> " Assignables: " <> show assignables
instance Environment Assignment AssignmentEnviroment where instance Environment Assignment AssignmentEnviroment where
output _ a =
T.unlines (gene <$> a)
where
gene :: (Maybe Student, Maybe Topic) -> Text
gene (s, t) =
pretty s <> ": " <> pretty t
new (AssignmentEnviroment (persons,assignables)) = do new (AssignmentEnviroment (persons,assignables)) = do
let aPadding = replicate (length persons - length assignables) Nothing let aPadding = replicate (length persons - length assignables) Nothing
let paddedAssignables = (Just <$> assignables) ++ aPadding let paddedAssignables = (Just <$> assignables) ++ aPadding
@@ -127,8 +135,6 @@ instance Environment Assignment AssignmentEnviroment where
-- Borrowed from TSP: Crossover cuts the parents in two and swaps them (if this -- Borrowed from TSP: Crossover cuts the parents in two and swaps them (if this
-- does not create an invalid offspring). -- does not create an invalid offspring).
-- --
-- TODO Assumes that both individuals are based on the same priorities.
--
crossover1 e assignment1 assignment2 = do crossover1 e assignment1 assignment2 = do
let l = fromIntegral $ min (length assignment1) (length assignment2) :: Double let l = fromIntegral $ min (length assignment1) (length assignment2) :: Double
x <- uniform 0 l x <- uniform 0 l
@@ -141,14 +147,6 @@ instance Environment Assignment AssignmentEnviroment where
f x v1 v2 i = if i <= x then v1 else v2 f x v1 v2 i = if i <= x then v1 else v2
instance Pretty Assignment where
pretty (a) =
T.unlines (gene <$> a)
where
gene :: (Maybe Student, Maybe Topic) -> Text
gene (s, t) =
pretty s <> ": " <> pretty t
-- | -- |
-- The priority value given by a student to a topic including the case of her not -- The priority value given by a student to a topic including the case of her not
-- receiving a topic. -- receiving a topic.

21
src-students/Test.hs Normal file
View File

@@ -0,0 +1,21 @@
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE Trustworthy #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE NoImplicitPrelude #-}
module Main where
import Protolude
import qualified Seminar
main :: IO ()
main = do
_ <- Seminar.runTests
return ()
if' :: Bool -> a -> a -> a
if' True x _ = x
if' False _ y = y

View File

@@ -1,177 +0,0 @@
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE NoImplicitPrelude #-}
module IrisData where
import Data.Csv
import Protolude
data IrisClass = Setosa | Virginica | Versicolor deriving (Eq, Generic, Show, Enum, Bounded)
instance FromRecord IrisClass
instance ToRecord IrisClass
irisData :: [((Float, Float, Float, Float), IrisClass)]
irisData =
[
((5.0, 3.5, 1.6, 0.6), Setosa),
((4.6, 3.1, 1.5, 0.2), Setosa),
((4.8, 3.4, 1.6, 0.2), Setosa),
((4.8, 3.0, 1.4, 0.3), Setosa),
((6.4, 2.9, 4.3, 1.3), Versicolor),
((5.5, 2.6, 4.4, 1.2), Versicolor),
((5.2, 2.7, 3.9, 1.4), Versicolor),
((6.0, 2.9, 4.5, 1.5), Versicolor),
((5.3, 3.7, 1.5, 0.2), Setosa),
((6.4, 3.2, 5.3, 2.3), Virginica),
((6.4, 3.1, 5.5, 1.8), Virginica),
((5.1, 3.8, 1.6, 0.2), Setosa),
((5.1, 3.7, 1.5, 0.4), Setosa),
((4.6, 3.4, 1.4, 0.3), Setosa),
((5.6, 3.0, 4.1, 1.3), Versicolor),
((6.1, 3.0, 4.6, 1.4), Versicolor),
((5.2, 3.5, 1.5, 0.2), Setosa),
((7.4, 2.8, 6.1, 1.9), Virginica),
((6.5, 2.8, 4.6, 1.5), Versicolor),
((6.3, 3.3, 6.0, 2.5), Virginica),
((4.8, 3.1, 1.6, 0.2), Setosa),
((7.7, 3.0, 6.1, 2.3), Virginica),
((6.0, 2.2, 5.0, 1.5), Virginica),
((5.5, 2.5, 4.0, 1.3), Versicolor),
((6.5, 3.0, 5.5, 1.8), Virginica),
((4.4, 2.9, 1.4, 0.2), Setosa),
((6.4, 3.2, 4.5, 1.5), Versicolor),
((5.0, 3.4, 1.6, 0.4), Setosa),
((6.1, 2.6, 5.6, 1.4), Virginica),
((6.6, 2.9, 4.6, 1.3), Versicolor),
((6.7, 3.1, 4.4, 1.4), Versicolor),
((5.4, 3.7, 1.5, 0.2), Setosa),
((5.4, 3.0, 4.5, 1.5), Versicolor),
((5.1, 3.8, 1.5, 0.3), Setosa),
((5.0, 2.3, 3.3, 1.0), Versicolor),
((6.0, 2.7, 5.1, 1.6), Versicolor),
((4.6, 3.2, 1.4, 0.2), Setosa),
((5.6, 2.7, 4.2, 1.3), Versicolor),
((6.7, 3.3, 5.7, 2.1), Virginica),
((6.9, 3.1, 5.1, 2.3), Virginica),
((7.7, 3.8, 6.7, 2.2), Virginica),
((6.1, 2.8, 4.7, 1.2), Versicolor),
((5.8, 2.7, 3.9, 1.2), Versicolor),
((6.7, 3.3, 5.7, 2.5), Virginica),
((5.0, 3.4, 1.5, 0.2), Setosa),
((4.7, 3.2, 1.6, 0.2), Setosa),
((6.8, 3.0, 5.5, 2.1), Virginica),
((6.2, 2.2, 4.5, 1.5), Versicolor),
((5.7, 3.8, 1.7, 0.3), Setosa),
((5.8, 4.0, 1.2, 0.2), Setosa),
((7.2, 3.2, 6.0, 1.8), Virginica),
((5.8, 2.7, 4.1, 1.0), Versicolor),
((6.5, 3.0, 5.8, 2.2), Virginica),
((6.9, 3.2, 5.7, 2.3), Virginica),
((5.8, 2.7, 5.1, 1.9), Virginica),
((5.2, 4.1, 1.5, 0.1), Setosa),
((4.6, 3.6, 1.0, 0.2), Setosa),
((4.7, 3.2, 1.3, 0.2), Setosa),
((6.9, 3.1, 5.4, 2.1), Virginica),
((6.1, 2.9, 4.7, 1.4), Versicolor),
((6.0, 3.4, 4.5, 1.6), Versicolor),
((5.6, 3.0, 4.5, 1.5), Versicolor),
((5.2, 3.4, 1.4, 0.2), Setosa),
((6.3, 3.3, 4.7, 1.6), Versicolor),
((7.2, 3.6, 6.1, 2.5), Virginica),
((6.5, 3.2, 5.1, 2.0), Virginica),
((6.3, 2.5, 4.9, 1.5), Versicolor),
((5.1, 3.8, 1.9, 0.4), Setosa),
((7.0, 3.2, 4.7, 1.4), Versicolor),
((4.9, 3.1, 1.5, 0.1), Setosa),
((4.9, 2.4, 3.3, 1.0), Versicolor),
((6.1, 3.0, 4.9, 1.8), Virginica),
((4.9, 3.1, 1.5, 0.1), Setosa),
((6.2, 2.9, 4.3, 1.3), Versicolor),
((5.7, 3.0, 4.2, 1.2), Versicolor),
((7.2, 3.0, 5.8, 1.6), Virginica),
((5.0, 2.0, 3.5, 1.0), Versicolor),
((4.3, 3.0, 1.1, 0.1), Setosa),
((6.7, 3.1, 4.7, 1.5), Versicolor),
((5.5, 2.4, 3.8, 1.1), Versicolor),
((5.7, 2.8, 4.5, 1.3), Versicolor),
((7.7, 2.8, 6.7, 2.0), Virginica),
((7.6, 3.0, 6.6, 2.1), Virginica),
((4.9, 2.5, 4.5, 1.7), Virginica),
((5.1, 2.5, 3.0, 1.1), Versicolor),
((6.4, 2.8, 5.6, 2.1), Virginica),
((6.4, 2.8, 5.6, 2.2), Virginica),
((5.9, 3.0, 5.1, 1.8), Virginica),
((4.4, 3.2, 1.3, 0.2), Setosa),
((6.3, 2.3, 4.4, 1.3), Versicolor),
((5.4, 3.4, 1.7, 0.2), Setosa),
((4.9, 3.0, 1.4, 0.2), Setosa),
((6.7, 3.0, 5.2, 2.3), Virginica),
((5.0, 3.5, 1.3, 0.3), Setosa),
((5.1, 3.3, 1.7, 0.5), Setosa),
((7.7, 2.6, 6.9, 2.3), Virginica),
((5.6, 2.9, 3.6, 1.3), Versicolor),
((7.3, 2.9, 6.3, 1.8), Virginica),
((6.7, 3.1, 5.6, 2.4), Virginica),
((6.3, 2.8, 5.1, 1.5), Virginica),
((5.6, 2.5, 3.9, 1.1), Versicolor),
((5.4, 3.9, 1.3, 0.4), Setosa),
((5.5, 2.3, 4.0, 1.3), Versicolor),
((6.4, 2.7, 5.3, 1.9), Virginica),
((5.1, 3.5, 1.4, 0.3), Setosa),
((5.5, 3.5, 1.3, 0.2), Setosa),
((5.0, 3.2, 1.2, 0.2), Setosa),
((5.1, 3.4, 1.5, 0.2), Setosa),
((5.4, 3.9, 1.7, 0.4), Setosa),
((4.5, 2.3, 1.3, 0.3), Setosa),
((6.7, 3.0, 5.0, 1.7), Versicolor),
((5.0, 3.3, 1.4, 0.2), Setosa),
((7.1, 3.0, 5.9, 2.1), Virginica),
((5.8, 2.6, 4.0, 1.2), Versicolor),
((6.3, 2.7, 4.9, 1.8), Virginica),
((6.8, 3.2, 5.9, 2.3), Virginica),
((6.6, 3.0, 4.4, 1.4), Versicolor),
((5.4, 3.4, 1.5, 0.4), Setosa),
((5.0, 3.6, 1.4, 0.2), Setosa),
((5.9, 3.2, 4.8, 1.8), Versicolor),
((6.3, 2.5, 5.0, 1.9), Virginica),
((6.0, 3.0, 4.8, 1.8), Virginica),
((7.9, 3.8, 6.4, 2.0), Virginica),
((5.9, 3.0, 4.2, 1.5), Versicolor),
((4.8, 3.0, 1.4, 0.1), Setosa),
((5.7, 2.8, 4.1, 1.3), Versicolor),
((6.7, 2.5, 5.8, 1.8), Virginica),
((5.7, 2.6, 3.5, 1.0), Versicolor),
((4.4, 3.0, 1.3, 0.2), Setosa),
((4.8, 3.4, 1.9, 0.2), Setosa),
((6.3, 3.4, 5.6, 2.4), Virginica),
((5.5, 4.2, 1.4, 0.2), Setosa),
((5.0, 3.0, 1.6, 0.2), Setosa),
((5.7, 2.9, 4.2, 1.3), Versicolor),
((6.2, 2.8, 4.8, 1.8), Virginica),
((6.2, 3.4, 5.4, 2.3), Virginica),
((6.5, 3.0, 5.2, 2.0), Virginica),
((4.9, 3.1, 1.5, 0.1), Setosa),
((5.8, 2.7, 5.1, 1.9), Virginica),
((5.1, 3.5, 1.4, 0.2), Setosa),
((5.6, 2.8, 4.9, 2.0), Virginica),
((5.5, 2.4, 3.7, 1.0), Versicolor),
((6.1, 2.8, 4.0, 1.3), Versicolor),
((5.7, 4.4, 1.5, 0.4), Setosa),
((6.9, 3.1, 4.9, 1.5), Versicolor),
((5.8, 2.8, 5.1, 2.4), Virginica),
((5.7, 2.5, 5.0, 2.0), Virginica),
((6.8, 2.8, 4.8, 1.4), Versicolor),
((6.3, 2.9, 5.6, 1.8), Virginica),
((6.0, 2.2, 4.0, 1.0), Versicolor),
]
irisTestData :: [((Float, Float, Float, Float), IrisClass)]
irisTestData =
[
]

View File

@@ -1,39 +0,0 @@
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE Trustworthy #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE NoImplicitPrelude #-}
module Main where
import Data.Random
import Data.Typeable
import qualified GA
import qualified LambdaCalculus
import Protolude
import qualified Seminar
import System.Random.MWC (createSystemRandom)
import qualified Type.Reflection as Ref
main :: IO ()
main = do
-- _ <- GA.runTests
-- _ <- Seminar.runTests
-- _ <- putStrLn $ ((show (typeRepArgs (Ref.SomeTypeRep (Ref.TypeRep @(Int -> Int -> Int -> Text))))) :: Text)
-- _ <- putStrLn $ ((show (typeRepArgs (Ref.SomeTypeRep (Ref.TypeRep @(Text))))) :: Text)
mwc <- createSystemRandom
r <- sampleFrom mwc $ GA.new LambdaCalculus.exampleLE
_ <- putStrLn $ LambdaCalculus.toLambdaExpressionS $ r
r <- sampleFrom mwc $ GA.new LambdaCalculus.exampleLE
_ <- putStrLn $ LambdaCalculus.toLambdaExpressionS $ r
-- _ <- putStrLn (LambdaCalculus.toLambdaExpressionShort LambdaCalculus.testIntToClassCorrect)
-- _ <- putStrLn $ ((show (LambdaCalculus.res 1)) :: Text)
-- _ <- putStrLn $ ((show (LambdaCalculus.res 2)) :: Text)
-- _ <- putStrLn $ ((show (LambdaCalculus.res 3)) :: Text)
return ()
if' :: Bool -> a -> a -> a
if' True x _ = x
if' False _ y = y