{- 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 . -} {- | [@AUTHOR@] Dr. Alistair Ward [@DESCRIPTION@] * Defines the value of a single /criterion/, which quantifies the significance of some concept; many such criteria may exist, & their weighted-mean drives automated selection of /move/s. * Each /criterion-value/ is normalised into the /signed closed unit-interval/. [@CAVEAT@] * While this data-type could implement the classes 'Num', 'Fractional' & 'Real', these interfaces would allow one to construct invalid instances. -} module BishBosh.Attribute.CriterionValue( -- * Types -- ** Data-types CriterionValue(), -- * Constants zero, -- * Functions calculateWeightedMean, -- ** Constructor mkCriterionValue ) where import Control.Arrow((&&&)) import qualified BishBosh.Attribute.CriterionWeight as Attribute.CriterionWeight import qualified BishBosh.Attribute.WeightedMeanAndCriterionValues as Attribute.WeightedMeanAndCriterionValues import qualified BishBosh.Types as T import qualified Control.Exception import qualified Factory.Math.Statistics -- | Quantifies some criterion; the larger the signed value, the better. newtype CriterionValue criterionValue = MkCriterionValue criterionValue deriving (Eq, Show) instance Num criterionValue => Bounded (CriterionValue criterionValue) where minBound = MkCriterionValue $ negate 1 maxBound = MkCriterionValue 1 -- | Smart constructor. mkCriterionValue :: ( Num criterionValue, Ord criterionValue ) => criterionValue -> CriterionValue criterionValue mkCriterionValue criterionValue = Control.Exception.assert (abs criterionValue <= 1) $ MkCriterionValue criterionValue -- | Constant. zero :: Num criterionValue => CriterionValue criterionValue zero = MkCriterionValue 0 {- | * Calculates the /weighted mean/ of the specified 'CriterionValue's using the corresponding /criterion-weight/s. * Also writes individual unweighted 'CriterionValue's, to facilitate post-analysis; if the corresponding weight is @0@, evaluation of the criterion is, for efficiency, avoided. * CAVEAT: if all weights are @0@, then the result is indeterminate. -} calculateWeightedMean :: ( Fractional weightedMean, Real criterionValue, Real criterionWeight ) => [(CriterionValue criterionValue, Attribute.CriterionWeight.CriterionWeight criterionWeight)] -> Attribute.WeightedMeanAndCriterionValues.WeightedMeanAndCriterionValues weightedMean criterionValue {-# SPECIALISE calculateWeightedMean :: [(CriterionValue T.CriterionValue, Attribute.CriterionWeight.CriterionWeight T.CriterionWeight)] -> Attribute.WeightedMeanAndCriterionValues.WeightedMeanAndCriterionValues T.WeightedMean T.CriterionValue #-} calculateWeightedMean assocs = uncurry Attribute.WeightedMeanAndCriterionValues.mkWeightedMeanAndCriterionValues $ ( Factory.Math.Statistics.getWeightedMean &&& map fst ) [ (bareCriterionValue, bareCriterionWeight) | (MkCriterionValue bareCriterionValue, criterionWeight) <- assocs, let bareCriterionWeight = Attribute.CriterionWeight.deconstruct criterionWeight, bareCriterionWeight /= 0 ] -- List-comprehension.