{-|
Module      : IT.FI2POP 
Description : Feasible-Infeasible Two-Population Interaction-Transformation Evolutionary Algorithm
Copyright   : (c) Fabricio Olivetti de Franca, 2020
License     : GPL-3
Maintainer  : fabricio.olivetti@gmail.com
Stability   : experimental
Portability : POSIX

Generic implementation of Interaction-Transformation Evolutionary Algorithm
for any instance of IT expression with Feasible-Infeasible Two-Population for
constraint handling.

To run itea you just need to call 'fi2pop mutFun fitness (pop0-feasible, pop0-infeasible)', 
where 'mutFun' is a mutation function of the type 'Mutation',
'fitness' is a fitness function of type 'Fitness',
and 'pop0-x' is the initial 'Population' of solutions of feasible or infeasible .
This function will result in an infinite list of populations, with
the /i/-th element being the population of the /i/-th generation.

This library also provides some generic mutation function builders.
-}
module IT.FI2POP where

import IT.Algorithms
import IT.Random
import IT.ITEA

import Control.Monad.Extra (iterateM)

-- * FI2POP

-- | Creates a stream of generations the /i/-th 
-- element corresponds to the population of the /i/-th generation.
fi2pop :: Mutation -> Fitness -> (Population, Population) -> Rnd [(Population, Population)]
fi2pop :: Mutation
-> Fitness
-> (Population, Population)
-> Rnd [(Population, Population)]
fi2pop Mutation
f Fitness
g (Population
feas0, Population
infeas0) = let n :: Int
n = Population -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length Population
feas0 -- + length infeas0
                              in  ((Population, Population)
 -> StateT StdGen Identity (Population, Population))
-> (Population, Population) -> Rnd [(Population, Population)]
forall (m :: * -> *) a. Monad m => (a -> m a) -> a -> m [a]
iterateM (Mutation
-> Fitness
-> Int
-> (Population, Population)
-> StateT StdGen Identity (Population, Population)
step2pop Mutation
f Fitness
g Int
n) (Population
feas0, Population
infeas0)

-- | Splits the population as feasible and infeasible. 
splitPop :: Population -> (Population, Population)
splitPop :: Population -> (Population, Population)
splitPop Population
pop = Population -> Population -> Population -> (Population, Population)
go Population
pop [] []
  where
    go :: Population -> Population -> Population -> (Population, Population)
go []     Population
feas Population
infeas = (Population
feas, Population
infeas)
    go (Solution
p:Population
ps) Population
feas Population
infeas
      | Solution -> Double
_constr Solution
p Double -> Double -> Bool
forall a. Eq a => a -> a -> Bool
== Double
0 = Population -> Population -> Population -> (Population, Population)
go Population
ps (Solution
pSolution -> Population -> Population
forall a. a -> [a] -> [a]
:Population
feas) Population
infeas
      | Bool
otherwise      = Population -> Population -> Population -> (Population, Population)
go Population
ps Population
feas (Solution
pSolution -> Population -> Population
forall a. a -> [a] -> [a]
:Population
infeas)
      
-- | Performs one iteration of FI2POP
step2pop :: Mutation -> Fitness -> Int -> (Population, Population) -> Rnd (Population, Population)
step2pop :: Mutation
-> Fitness
-> Int
-> (Population, Population)
-> StateT StdGen Identity (Population, Population)
step2pop Mutation
mutFun Fitness
fitFun Int
nPop (Population
feas, Population
infeas) = do
  let tourn :: Population -> Int -> Rnd Population
tourn = if Int
nPop Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
1000 then Population -> Int -> Rnd Population
tournamentSeq else Population -> Int -> Rnd Population
tournament
  Population
childrenF <- Int
-> (Solution -> Rnd Expr)
-> Fitness
-> Population
-> Rnd Population
parRndMap Int
nPop (Mutation
mutFun Mutation -> (Solution -> Expr) -> Solution -> Rnd Expr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Solution -> Expr
_expr) Fitness
fitFun Population
feas
  Population
childrenI <- Int
-> (Solution -> Rnd Expr)
-> Fitness
-> Population
-> Rnd Population
parRndMap Int
nPop (Mutation
mutFun Mutation -> (Solution -> Expr) -> Solution -> Rnd Expr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Solution -> Expr
_expr) Fitness
fitFun Population
infeas
  let (Population
feas', Population
infeas') = Population -> (Population, Population)
splitPop (Population
childrenF Population -> Population -> Population
forall a. [a] -> [a] -> [a]
++ Population
childrenI)
  Population
nextFeas <- Population -> Int -> Rnd Population
tourn (Population
feas Population -> Population -> Population
forall a. [a] -> [a] -> [a]
++ Population
feas') Int
nPop
  Population
nextInfeas <- Population -> Int -> Rnd Population
tourn (Population
infeas Population -> Population -> Population
forall a. [a] -> [a] -> [a]
++ Population
infeas') Int
nPop  
  (Population, Population)
-> StateT StdGen Identity (Population, Population)
forall (m :: * -> *) a. Monad m => a -> m a
return (Population
nextFeas, Population
nextInfeas)

-- TODO: test it \/
{-
      nFeas            = max (length feas) (length feas')
      nInfeas          = max (length infeas) (length infeas')
      halfPop          = nPop `div` 2
  nextFeas <- if null feas'
                then tournament feas nFeas
                else tournament (feas ++ feas') (min nFeas halfPop)
  nextInfeas <- if null infeas'
                  then tournament infeas nInfeas
                  else tournament (infeas ++ infeas') (min nInfeas halfPop)
-}