{-
	Copyright (C) 2018 Dr. Alistair Ward

	This file is part of BishBosh.

	BishBosh is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	BishBosh is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with BishBosh.  If not, see <http://www.gnu.org/licenses/>.
-}
{- |
 [@AUTHOR@]	Dr. Alistair Ward

 [@DESCRIPTION@]	The unweighted values of each criterion used to assess the fitness of a position, & the resulting weighted mean.
-}

module BishBosh.Attribute.WeightedMeanAndCriterionValues(
-- * Types
-- ** Data-types
	WeightedMeanAndCriterionValues(
--		MkWeightedMeanAndCriterionValues,
		getWeightedMean,
		getCriterionValues
	),
-- * Constants
	criterionValuesTag,
	weightedMeanTag,
-- * Functions
	negateWeightedMean,
-- ** Constructor
	mkWeightedMeanAndCriterionValues
) where

import qualified	BishBosh.Property.ShowFloat	as Property.ShowFloat
import qualified	BishBosh.Text.ShowList		as Text.ShowList
import qualified	Control.DeepSeq

-- | Qualifies output.
criterionValuesTag :: String
criterionValuesTag :: String
criterionValuesTag	= String
"criterion-values"

-- | Qualifies output.
weightedMeanTag :: String
weightedMeanTag :: String
weightedMeanTag		= String
"weighted-mean"

-- | A /weighted mean/ & the individual unweighted criterion-value from which it was composed.
data WeightedMeanAndCriterionValues weightedMean criterionValue	= MkWeightedMeanAndCriterionValues {
	WeightedMeanAndCriterionValues weightedMean criterionValue
-> weightedMean
getWeightedMean		:: weightedMean,	-- ^ The weighted mean of a list of criterion-values.
	WeightedMeanAndCriterionValues weightedMean criterionValue
-> [criterionValue]
getCriterionValues	:: [criterionValue]	-- ^ The unweighted 'CriterionValue's from which the weighted mean was composed.
} deriving (WeightedMeanAndCriterionValues weightedMean criterionValue
-> WeightedMeanAndCriterionValues weightedMean criterionValue
-> Bool
(WeightedMeanAndCriterionValues weightedMean criterionValue
 -> WeightedMeanAndCriterionValues weightedMean criterionValue
 -> Bool)
-> (WeightedMeanAndCriterionValues weightedMean criterionValue
    -> WeightedMeanAndCriterionValues weightedMean criterionValue
    -> Bool)
-> Eq (WeightedMeanAndCriterionValues weightedMean criterionValue)
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall weightedMean criterionValue.
(Eq weightedMean, Eq criterionValue) =>
WeightedMeanAndCriterionValues weightedMean criterionValue
-> WeightedMeanAndCriterionValues weightedMean criterionValue
-> Bool
/= :: WeightedMeanAndCriterionValues weightedMean criterionValue
-> WeightedMeanAndCriterionValues weightedMean criterionValue
-> Bool
$c/= :: forall weightedMean criterionValue.
(Eq weightedMean, Eq criterionValue) =>
WeightedMeanAndCriterionValues weightedMean criterionValue
-> WeightedMeanAndCriterionValues weightedMean criterionValue
-> Bool
== :: WeightedMeanAndCriterionValues weightedMean criterionValue
-> WeightedMeanAndCriterionValues weightedMean criterionValue
-> Bool
$c== :: forall weightedMean criterionValue.
(Eq weightedMean, Eq criterionValue) =>
WeightedMeanAndCriterionValues weightedMean criterionValue
-> WeightedMeanAndCriterionValues weightedMean criterionValue
-> Bool
Eq, Int
-> WeightedMeanAndCriterionValues weightedMean criterionValue
-> ShowS
[WeightedMeanAndCriterionValues weightedMean criterionValue]
-> ShowS
WeightedMeanAndCriterionValues weightedMean criterionValue
-> String
(Int
 -> WeightedMeanAndCriterionValues weightedMean criterionValue
 -> ShowS)
-> (WeightedMeanAndCriterionValues weightedMean criterionValue
    -> String)
-> ([WeightedMeanAndCriterionValues weightedMean criterionValue]
    -> ShowS)
-> Show
     (WeightedMeanAndCriterionValues weightedMean criterionValue)
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall weightedMean criterionValue.
(Show weightedMean, Show criterionValue) =>
Int
-> WeightedMeanAndCriterionValues weightedMean criterionValue
-> ShowS
forall weightedMean criterionValue.
(Show weightedMean, Show criterionValue) =>
[WeightedMeanAndCriterionValues weightedMean criterionValue]
-> ShowS
forall weightedMean criterionValue.
(Show weightedMean, Show criterionValue) =>
WeightedMeanAndCriterionValues weightedMean criterionValue
-> String
showList :: [WeightedMeanAndCriterionValues weightedMean criterionValue]
-> ShowS
$cshowList :: forall weightedMean criterionValue.
(Show weightedMean, Show criterionValue) =>
[WeightedMeanAndCriterionValues weightedMean criterionValue]
-> ShowS
show :: WeightedMeanAndCriterionValues weightedMean criterionValue
-> String
$cshow :: forall weightedMean criterionValue.
(Show weightedMean, Show criterionValue) =>
WeightedMeanAndCriterionValues weightedMean criterionValue
-> String
showsPrec :: Int
-> WeightedMeanAndCriterionValues weightedMean criterionValue
-> ShowS
$cshowsPrec :: forall weightedMean criterionValue.
(Show weightedMean, Show criterionValue) =>
Int
-> WeightedMeanAndCriterionValues weightedMean criterionValue
-> ShowS
Show)

instance Control.DeepSeq.NFData weightedMean => Control.DeepSeq.NFData (WeightedMeanAndCriterionValues weightedMean criterionValue) where
	rnf :: WeightedMeanAndCriterionValues weightedMean criterionValue -> ()
rnf MkWeightedMeanAndCriterionValues { getWeightedMean :: forall weightedMean criterionValue.
WeightedMeanAndCriterionValues weightedMean criterionValue
-> weightedMean
getWeightedMean = weightedMean
weightedMean }	= weightedMean -> ()
forall a. NFData a => a -> ()
Control.DeepSeq.rnf weightedMean
weightedMean	-- The other field is a prerequisite.

instance (Real criterionValue, Real weightedMean) => Property.ShowFloat.ShowFloat (WeightedMeanAndCriterionValues weightedMean criterionValue) where
	showsFloat :: (Double -> ShowS)
-> WeightedMeanAndCriterionValues weightedMean criterionValue
-> ShowS
showsFloat Double -> ShowS
fromDouble MkWeightedMeanAndCriterionValues {
		getWeightedMean :: forall weightedMean criterionValue.
WeightedMeanAndCriterionValues weightedMean criterionValue
-> weightedMean
getWeightedMean		= weightedMean
weightedMean,
		getCriterionValues :: forall weightedMean criterionValue.
WeightedMeanAndCriterionValues weightedMean criterionValue
-> [criterionValue]
getCriterionValues	= [criterionValue]
criterionValues
	} = [(String, ShowS)] -> ShowS
Text.ShowList.showsAssociationList' [
		(String
weightedMeanTag, Double -> ShowS
fromDouble (Double -> ShowS) -> Double -> ShowS
forall a b. (a -> b) -> a -> b
$ weightedMean -> Double
forall a b. (Real a, Fractional b) => a -> b
realToFrac weightedMean
weightedMean),
		(String
criterionValuesTag, (criterionValue -> ShowS) -> [criterionValue] -> ShowS
forall a. (a -> ShowS) -> [a] -> ShowS
Text.ShowList.showsFormattedList' (Double -> ShowS
fromDouble (Double -> ShowS)
-> (criterionValue -> Double) -> criterionValue -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. criterionValue -> Double
forall a b. (Real a, Fractional b) => a -> b
realToFrac) [criterionValue]
criterionValues)
	 ]

-- | Constructor
mkWeightedMeanAndCriterionValues :: weightedMean -> [criterionValue] -> WeightedMeanAndCriterionValues weightedMean criterionValue
mkWeightedMeanAndCriterionValues :: weightedMean
-> [criterionValue]
-> WeightedMeanAndCriterionValues weightedMean criterionValue
mkWeightedMeanAndCriterionValues	= weightedMean
-> [criterionValue]
-> WeightedMeanAndCriterionValues weightedMean criterionValue
forall weightedMean criterionValue.
weightedMean
-> [criterionValue]
-> WeightedMeanAndCriterionValues weightedMean criterionValue
MkWeightedMeanAndCriterionValues

{- |
	* Negate the weightedMean, but leave the criterion-values unaltered.

	* This can be used to assess the fitness of a position from the perspective of one's opponent.
-}
negateWeightedMean :: Num weightedMean => WeightedMeanAndCriterionValues weightedMean criterionValue -> WeightedMeanAndCriterionValues weightedMean criterionValue
negateWeightedMean :: WeightedMeanAndCriterionValues weightedMean criterionValue
-> WeightedMeanAndCriterionValues weightedMean criterionValue
negateWeightedMean weightedMeanAndCriterionValues :: WeightedMeanAndCriterionValues weightedMean criterionValue
weightedMeanAndCriterionValues@MkWeightedMeanAndCriterionValues { getWeightedMean :: forall weightedMean criterionValue.
WeightedMeanAndCriterionValues weightedMean criterionValue
-> weightedMean
getWeightedMean = weightedMean
weightedMean }	= WeightedMeanAndCriterionValues weightedMean criterionValue
weightedMeanAndCriterionValues { getWeightedMean :: weightedMean
getWeightedMean = weightedMean -> weightedMean
forall a. Num a => a -> a
negate weightedMean
weightedMean }