packages feed

ideas-statistics-1.0: src/Domain/Hypothesis/Exercises.hs

-----------------------------------------------------------------------------
-- Copyright 2020, Ideas project team. This file is distributed under the
-- terms of the Apache License 2.0. For more information, see the files
-- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution.
-----------------------------------------------------------------------------
module Domain.Hypothesis.Exercises (hypothesisExercise) where

import Control.Monad
import qualified Data.Map as M
import Data.List
import Data.Maybe
import Domain.Math.Data.Relation
import Domain.Hypothesis.Examples
import Domain.Hypothesis.Constraints
import Domain.Hypothesis.BuggyRules
import Domain.Hypothesis.Rules
import Domain.Hypothesis.Strategies
import Domain.Statistics.ComponentSet
import Domain.Statistics.Parser
import Ideas.Common.Library  hiding (Predicate)
import Domain.Math.Expr.Data
import Ideas.Encoding.OpenMathSupport
import Ideas.Utils.Uniplate
import Ideas.Text.XML hiding (children)
import Prelude               hiding (until)

-- Debug functions
css :: [ComponentSet]
css = mapMaybe fromContext $ concatMap terms $
   mapMaybe (defaultDerivation hypothesisExercise) (examplesAsList hypothesisExercise)

_testPP :: IO ()
_testPP = forM_ css $ \x ->
   let s = prettyPrinter hypothesisExercise x in
   case parser hypothesisExercise s of
      Right y | x == y    -> putChar '.'
              | otherwise -> error $ show (x, y)
      Left msg -> error $ s ++ "\n" ++ msg

_testOM :: IO ()
_testOM = forM_ css $ \x ->
   case toOpenMath hypothesisExercise x of
      Right omobj ->
         case fromOpenMath hypothesisExercise omobj of
            Just y | x == y    -> putChar '.'
                   | otherwise -> error $ "Not the same:\n" ++ show x ++ "\n" ++ show y
            Nothing -> error $ show omobj
      Left msg -> error $ show x ++ "\n" ++ msg

_see :: Int -> IO ()
_see n = printDerivation hypothesisExercise (examplesAsList hypothesisExercise !! n)

_testje :: IO ()
_testje = printDerivation hypothesisExercise opgave_5_4

_save :: IO ()
_save = do
   let pilot = [("A", mayPilotA), ("B", mayPilotB), ("C", mayPilotC), ("D", mayPilotD)]
       ex = hypothesisExercise
   forM_ pilot $ \(n, cs) -> do
      writeFile ("Task" ++ n ++ ".txt") $ showDerivation ex cs
      writeFile ("Task" ++ n ++ "-OM.txt") $ showDerivationOM ex cs

showDerivationOM :: Exercise a -> a -> String
showDerivationOM ex a =
   case defaultDerivation ex a of
      Just d  -> show $ biMap fst f d
      Nothing -> "no derivation"
 where
   errorXML = makeXML "error" mempty
   f ctx = fromMaybe errorXML $ do
       x     <- fromContext ctx
       omobj <- toOpenMath ex x
       return (toXML omobj)

------------------------------

hypothesisExercise :: Exercise ComponentSet
hypothesisExercise = emptyExercise
   { exerciseId    = describe "Hypothesis testing" $ newId "hypothesis"
   , prettyPrinter = show
   , status        = Experimental
   , parser        = parseComponentSet
   , strategy      = liftToContext hypothesisStrategy
   , extraRules    = fmap liftToContext buggyRules
   , ruleOrdering  = ruleOrderingWith highPriorityRules
   , examples      = examplesWithDifficulty [ (Medium, cs) | cs <- opgavenSW ++ opgavenEconomie ]  -- hypothesisExamples
   , equivalence   = withoutContext eqComponentSet
   , similarity    = withoutContext similarComponentSet
   , constraints   = map liftToContext hypothesisConstraints
   , hasTypeable   = useTypeable
   , ready         = predicate (hasConclusionHypotheses <&&> checkConstraints)
   , hasTermView   = Just termView
   }
   
highPriorityRules :: [Rule ComponentSet]
highPriorityRules = 
   [ addHypothesesRule
   , lookupTValueRule, lookupZValueRule
   , computePValueTTest, computePValueZTest
   , addTestValueRule
   , hypothesesConclusionCriticalRule, hypothesesConclusionPValueRule
     -- buggy rules
   , buggyTValueSided, buggyTValueTestValue -- Sietske: higher priority than corresponding buggy alpha rule
   , buggyRValueSided, buggyRValueTestValue -- idem
   , buggyZValueSided, buggyZValueTestValue
   , buggyChiValueSided, buggyChiValueTestValue
   ]

----------------------------------------------------------
-- Equivalence
eqComponentSet :: ComponentSet -> ComponentSet -> Bool
eqComponentSet x y = compareIntials
                  && checkConstraints x
                  && checkConstraints y
 where
   compareIntials =
     M.fromList (toList (initials x)) == M.fromList (toList (initials y))

checkConstraints :: ComponentSet -> Bool
checkConstraints cs =
   all (`checkConstraint` cs) hypothesisConstraints
   
checkConstraint :: Constraint ComponentSet -> ComponentSet -> Bool
checkConstraint p cs 
   | not (isRelevant p cs) = True
   | otherwise = isSatisfied p cs

----------------------------------------------------------
-- Similarity

-- To do: not all component ids compare doubles with the same precision
-- (e.g. pvalue uses 3 decimals, default is 2)
similarComponentSet :: ComponentSet -> ComponentSet -> Bool
similarComponentSet cs1 cs2 = sorted cs1 `eqList` sorted cs2
 where
   sorted = map f . sortOn fst . toList
    where
      f (n, CExpr e)     = (n, CExpr (normalizeExpr e))
      f (n, CRelation r) = (n, CRelation (fmap normalizeExpr r))
      f (n, c)           = (n, c)
   
   eqList :: [(ComponentId, Component)] -> [(ComponentId, Component)] -> Bool
   eqList xs ys = length xs == length ys && all (\((a, x), (b, y)) -> a == b && x `eqComponent` y) (zip xs ys)

   eqComponent :: Component -> Component -> Bool
   eqComponent (CExpr x) (CExpr y) = eqExpr x y
   eqComponent (CRelation x) (CRelation y) = 
      eqExpr (leftHandSide x) (leftHandSide y) && eqExpr (rightHandSide x) (rightHandSide y)
         && relationType x == relationType y
   eqComponent x y = x == y
   
   eqExprs :: [Expr] -> [Expr] -> Bool
   eqExprs [] [] = True
   eqExprs (x:xs) (y:ys) = eqExpr x y && eqExprs xs ys
   eqExprs _ _ = False
   
   eqExpr :: Expr -> Expr -> Bool
   eqExpr (Number x) (Number y) = equalDouble x y
   eqExpr x y = 
      case (getFunction x, getFunction y) of 
         (Just (f, xs), Just (g, ys)) -> f == g && xs `eqExprs` ys
         _ -> x == y


-- we vouwen hier de definities uit zodat we formules kunnen herkennen
-- afronden op 2 decimalen: beter is om expressies component-gewijs te 
-- vergelijken en daarbij de hulpfunctie 'equal' te gebruiken
normalizeExpr :: Expr -> Expr
normalizeExpr (Var "sigmaM") = Var "sigma" / sqrt (Var "n")
normalizeExpr (Var "SEM") = Var "s" / sqrt (Var "n")
normalizeExpr (Nat n)     = Number (fromInteger n)
normalizeExpr expr = descend normalizeExpr expr

-- | Test whether the conclusionhypothesis is present in the componentset. If
-- the predicate holds then he exercise is considered /done/.
hasConclusionHypotheses :: ComponentSet -> Bool
hasConclusionHypotheses cs = contains cs ConclusionHypotheses