packages feed

ideas-math-1.1: src/Domain/Logic/Exercises.hs

-----------------------------------------------------------------------------
-- Copyright 2014, Open Universiteit Nederland. This file is distributed
-- under the terms of the GNU General Public License. For more information,
-- see the file "LICENSE.txt", which is included in the distribution.
-----------------------------------------------------------------------------
-- |
-- Maintainer  :  bastiaan.heeren@ou.nl
-- Stability   :  provisional
-- Portability :  portable (depends on ghc)
--
-- Exercise for the logic domain, used for the OUNL course
-- "Discrete Wiskunde A (DWA)"
--
-----------------------------------------------------------------------------
--  $Id: Exercises.hs 6548 2014-05-16 10:34:18Z bastiaan $

module Domain.Logic.Exercises
   ( dnfExercise, dnfUnicodeExercise, cnfUnicodeExercise
   , extraLogicRules
   ) where

import Data.Maybe
import Domain.Logic.BuggyRules
import Domain.Logic.Formula
import Domain.Logic.GeneralizedRules
import Domain.Logic.Generator
import Domain.Logic.InverseRules
import Domain.Logic.Parser
import Domain.Logic.Rules
import Domain.Logic.Strategies
import Domain.Logic.Utils
import Ideas.Common.Library
import Test.QuickCheck

-- Currently, we use the DWA strategy
dnfExercise :: Exercise SLogic
dnfExercise = makeExercise
   { exerciseId     = describe "Proposition to DNF" $
                         propositionalId # "dnf"
   , status         = Stable
   , parser         = parseLogicPars
   , prettyPrinter  = ppLogicPars
   , equivalence    = withoutContext eqLogic
   , similarity     = withoutContext equalLogicA
   , ready          = predicate isDNF
   , suitable       = predicate notTooManyEquivs
   , extraRules     = map liftToContext (extraLogicRules ++ buggyRules)
   , strategy       = dnfStrategyDWA
   , navigation     = navigator
   , testGenerator  = Just (arbitrary `suchThat` notTooManyEquivs)
   , randomExercise = useGenerator dnfExerciseGenerator
   }

-- Direct support for unicode characters
dnfUnicodeExercise :: Exercise SLogic
dnfUnicodeExercise = dnfExercise
   { exerciseId    = describe "Proposition to DNF (unicode support)" $
                        propositionalId # "dnf.unicode"
   , parser        = parseLogicUnicodePars
   , prettyPrinter = ppLogicUnicodePars
   }

cnfUnicodeExercise :: Exercise SLogic
cnfUnicodeExercise = makeExercise
   { exerciseId     = describe "Proposition to CNF (unicode support)" $
                         propositionalId # "cnf.unicode"
   , status         = Stable
   , parser         = parseLogicUnicodePars
   , prettyPrinter  = ppLogicUnicodePars
   , equivalence    = withoutContext eqLogic
   , similarity     = withoutContext equalLogicA
   , ready          = predicate isCNF
   , suitable       = predicate notTooManyEquivs
   , extraRules     = map liftToContext (extraLogicRules ++ buggyRules)
   , strategy       = cnfStrategyDWA
   , navigation     = navigator
   , testGenerator  = Just (arbitrary `suchThat` notTooManyEquivs)
   , randomExercise = useGenerator cnfExerciseGenerator
   }

extraLogicRules :: [Rule SLogic]
extraLogicRules =
   [ ruleCommOr, ruleCommAnd, ruleAssocOr, ruleAssocAnd
   , generalRuleOrOverAnd, ruleOrOverAnd
   , inverseDeMorganOr, inverseDeMorganAnd
   , inverseAndOverOr, inverseOrOverAnd
   -- Rules that are NOT allowed in DWA
   -- , ruleFalseInEquiv, ruleTrueInEquiv, ruleFalseInImpl, ruleTrueInImpl
   -- , ruleCommEquiv, ruleDefEquivImpls, ruleEquivSame, ruleImplSame
   ]

notTooManyEquivs :: SLogic -> Bool
notTooManyEquivs = (<=2) . countEquivalences

dnfExerciseGenerator :: Maybe Difficulty -> Gen SLogic
dnfExerciseGenerator = exerciseGeneratorFor dnfExercise

cnfExerciseGenerator :: Maybe Difficulty -> Gen SLogic
cnfExerciseGenerator = exerciseGeneratorFor cnfUnicodeExercise

exerciseGeneratorFor :: Exercise SLogic -> Maybe Difficulty -> Gen SLogic
exerciseGeneratorFor ex mdif =
   let (gen, (minStep, maxStep)) = generateLevel (fromMaybe Medium mdif)
       ok p = let i = fromMaybe maxBound (stepsRemaining maxStep p)
              in notTooManyEquivs p && i >= minStep && i <= maxStep
   in gen `suchThat` ok
 where
   stepsRemaining i =
      lengthMax i . derivationTree (strategy ex) . inContext ex

-- QuickCheck property to monitor the number of steps needed
-- to normalize a random proposition (30-40% is ok)
{-
testGen :: Property
testGen = forAll generateLogic $ \p ->
   let n = steps p
   in countEquivalences p <= 2 ==> label (show (n >= 4 && n <= 12)) True

testme :: IO ()
testme = quickCheck testGen

start = ((r :<->: p) :||: (q :->: s)) :&&: (Not s :<->: (p :||: r))
 where
  (p, q, r, s) = (Var "p", Var "q", Var "r", Var "s")

go = derivation . emptyState dnfExercise
-}