module Evaluation
  ( sumProducedCompounds
  , numDistinctCompounds
  , sumCompounds
  , from
  , meanAndVar
  , byCompound
  , byProducts
  ) where

import Control.Foldl as F
import Numeric.LinearAlgebra as LA
import Data.List

import Environment

eps :: Amount
eps = 0.01

-- | sum of produced compounds ignoring everything defined as 'Nutrient'.
sumProducedCompounds :: Functor f => f (LA.Vector Amount) -> f Amount
-- sumProducedCompounds :: [LA.Vector Amount] -> [Amount]
-- cut off numNutrients from the start of the vector and then sum.
sumProducedCompounds = fmap sumElements . cutoffNutrients

-- | sum of all compounds
sumCompounds :: Functor f => f (LA.Vector Amount) -> f Amount
--sumCompounds :: [LA.Vector Amount] -> [Amount]
sumCompounds = fmap sumElements

-- | count compound as active if it is over eps.
numDistinctCompounds :: Functor f => f (LA.Vector Amount) -> f Amount
--numDistinctCompounds :: [LA.Vector Amount] -> [Amount]
numDistinctCompounds comps = sumElements . LA.cmap (\x -> if abs x < eps then 0 else 1) <$> comps

-- | helper function for Foldl-Package.
--
--   Usage: @F.mean `from` sumCompounds $ v@ where v is a Set/List/Vector/... of Vector of Compounds.
infixr 9 `from`
from :: Foldable f => F.Fold a b -> (c -> f a) -> c -> b
from f w b = F.fold f (w b)

-- | helper to get mean and variance in a single pass.
meanAndVar :: F.Fold Amount (Amount,Amount)
meanAndVar = (,) <$> F.mean <*> F.variance

byProducts :: [LA.Vector Amount] -> [[Amount]]
byProducts = transpose . fmap toList . cutoffNutrients

byCompound :: [LA.Vector Amount] -> [[Amount]]
byCompound = transpose . fmap toList

-- | sum of produced compounds ignoring everything defined as 'Nutrient'.
cutoffNutrients :: Functor f => f (LA.Vector Amount) -> f (LA.Vector Amount)
-- sumProducedCompounds :: [LA.Vector Amount] -> [Amount]
-- cut off numNutrients from the start of the vector and then sum.
cutoffNutrients = fmap (\v -> LA.subVector numNutrients (size v - numNutrients) v)
    where
        numNutrients = fromEnum (maxBound :: Nutrient) + 1 --enum starts at 0, subVector-indexing at 1
