packages feed

shikumi-eval-0.1.0.0: src/Shikumi/Eval/Types.hs

-- | The evaluation data model — MasterPlan integration point #5. The optimizer
-- (@docs/plans/10-optimizer-framework.md@) and the CLI
-- (@docs/plans/12-cli-and-developer-experience.md@) /consume/ these types and
-- must not redefine them.
--
-- A 'Score' is a 'Double' clamped to the closed interval @[0, 1]@ at
-- construction, so downstream ranking code can assume @0 <= s <= 1@ without
-- re-checking (a @Bool@ metric maps @True -> 1@, @False -> 0@). An 'Example' is
-- one labelled datum (input + expected output); a 'Dataset' is a list of them. A
-- 'Prediction' is a program's actual output for one example, carrying a primary
-- output plus the non-empty set of sampled outputs (a single-output program
-- yields a one-element 'Prediction'), so agreement-rewarding metrics
-- (majority-vote, ensemble) can inspect every sample.
module Shikumi.Eval.Types
  ( -- * Scores
    Score (..),
    mkScore,
    scoreZero,
    scoreOne,
    boolScore,
    unScore,

    -- * Examples and datasets
    Example (..),
    example,
    Dataset (..),
    dataset,
    datasetExamples,
    datasetSize,

    -- * Predictions (program outputs)
    Prediction (..),
    prediction,
    predictionPrimary,
    predictionSamples,
  )
where

import Data.Aeson (Value)
import Data.List.NonEmpty (NonEmpty (..))

-- | A metric score, always in the closed interval @[0, 1]@.
newtype Score = Score Double
  deriving stock (Eq, Ord, Show)

-- | Clamp any 'Double' into @[0, 1]@.
mkScore :: Double -> Score
mkScore d = Score (max 0 (min 1 d))

-- | The two interval endpoints as scores.
scoreZero, scoreOne :: Score
scoreZero = Score 0
scoreOne = Score 1

-- | Map a boolean outcome to a score: @True -> 1@, @False -> 0@.
boolScore :: Bool -> Score
boolScore True = scoreOne
boolScore False = scoreZero

-- | Project the underlying 'Double' (always in @[0, 1]@).
unScore :: Score -> Double
unScore (Score d) = d

-- | One labelled datum: an input of type @i@ and its expected output of type @o@.
data Example i o = Example
  { input :: !i,
    expected :: !o
  }
  deriving stock (Eq, Show)

-- | Build an 'Example' from an input and its expected output.
example :: i -> o -> Example i o
example = Example

-- | A typed evaluation dataset.
newtype Dataset i o = Dataset [Example i o]
  deriving stock (Eq, Show)

-- | Build a 'Dataset' from a list of examples.
dataset :: [Example i o] -> Dataset i o
dataset = Dataset

-- | The examples of a dataset, in order.
datasetExamples :: Dataset i o -> [Example i o]
datasetExamples (Dataset xs) = xs

-- | The number of examples in a dataset.
datasetSize :: Dataset i o -> Int
datasetSize (Dataset xs) = length xs

-- | A program's actual output for one example. Carries a primary output and the
-- non-empty set of sampled outputs (a single-output program yields one sample).
-- An optional raw JSON @detail@ lets adapters or judges attach structure.
data Prediction o = Prediction
  { primary :: !o,
    samples :: !(NonEmpty o),
    detail :: !(Maybe Value)
  }
  deriving stock (Eq, Show)

-- | Build a single-sample prediction (primary output, one sample, no detail).
prediction :: o -> Prediction o
prediction o = Prediction o (o :| []) Nothing

-- | The designated primary output of a prediction.
predictionPrimary :: Prediction o -> o
predictionPrimary = primary

-- | The non-empty set of sampled outputs.
predictionSamples :: Prediction o -> NonEmpty o
predictionSamples = samples