packages feed

HaskellAnalysisProgram-0.1.0: src/MetaHS/Extensions/MacroLevelAggregation/GiniCoefficient.hs

{-|
Module      : MetaHS.MacroLevelAggregation
Description : The MetaHS Macro-level aggregation method: Gini-coefficient
Copyright   : Copyright (C) 2017-2019 H.H.R.F. Vos, S. Kamps
License     : -- This file is distributed under the  terms of the Apache License 2.0.
              For more information, see the file "LICENSE", which is included in the distribution.
Stability   : experimental
Calculates the Gini-coefficient of the metric population corresponding
to supplied Relation Key. Result is a value bounded by [0,1].
-}
module MetaHS.Extensions.MacroLevelAggregation.GiniCoefficient
  (giniCoefficient)
  where

import MetaHS.Extensions.MacroLevelAggregation.Utils
import qualified MetaHS.DataModel.MetaModel as MetaModel
import MetaHS.EDSL.MetaModel
import qualified Data.Set as Set
import qualified Data.List as List

-- | Calculate the Gini-coefficient of the metric values associated with the supplied metric Relation key
giniCoefficient :: RelationKey          -- ^ The MetaModel Relation Key (E.g., LCOM).
                -> MetaModel.MetaModel  -- ^ The MetaModel Containing the associated key.
                -> Double               -- ^ The Gini coefficient
giniCoefficient key mm = gini ordered_list
  where
  ordered_list = List.sort xs
  xs = getMetricElements key mm

-- | Calculates the Gini-coefficient of the elements contained in the supplied list
gini :: [Int]  -- ^ Ordered list
     -> Double -- ^ The Gini-coefficient
gini xs | null xs = 0.0
        | length xs == 1 = 0.0
        | otherwise = fromIntegral (deltaSum xs) / fromIntegral (last $ xsAccum xs) / fromIntegral (length xs)

-- | Sums up halve of all delta's of each consecutive element in a list. (x_i - x_i-1)
-- | This means that from a supplied list, the delta of each member with respect to
-- | each other member, will be added together.
-- | This function represents the numerator part of the Gini-coefficient algorithm.
-- | (although with one halve of the symmetric metric)
deltaSum :: [Int] -- ^ An ordered list
         -> Int   -- ^ All delta's added together
deltaSum xs = fromIntegral delta_cum
  where
  delta_cum = sum deltas
  deltas = zipWith3 (\idx x x_accum -> idx * x - x_accum) indices xs $ xsAccum xs
  xs_ord = List.sort xs
  indices = [0..length xs - 1]

-- | Every element in the resulting list is an accumulation of all it's predecessors.
xsAccum :: [Int] -- ^ An ordered list
         -> [Int] -- ^ Accumulated values
xsAccum = scanl (+) 0