Skip to content

Commit

Permalink
[mmzk] (feat) Incorporate Year 2024 solution
Browse files Browse the repository at this point in the history
  • Loading branch information
MMZK1526 committed Jan 29, 2024
1 parent 0cd252b commit 55de337
Show file tree
Hide file tree
Showing 10 changed files with 641 additions and 0 deletions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ I have preserved all the original comments in the test. New comments are marked

Since it is a not-mini compilation of Haskell code, I use cabal to manage the project.

### Tests Before 2024

Run `cabal repl` in the root directory, it will open up a GHCi REPL that already loads the files for the tests. You can then load the modules for each year according to the following table to explore and test the functions. Note that simply running `ghci` and load the modules manually may not work because of the dependencies.

Otherwise if you have not installed `cabal`, you can just copy the solution of any given year into a standalone Haskell file (remember to remove the `Year20XX.` prefix in the imports as well as the `tester` function). It should compile.
Expand All @@ -33,3 +35,11 @@ If there's any issue or doubt on running the solutions, you are more than welcom
| 2016 | `:m Test Year2016.Exam` |
| 2015 | `:m Test Year2015.Exam` |
| 2014 | `:m Test Year2014.Exam` |

### Tests Since 2024

The tests since 2024 are presented in a different format. They are now in the form of a cabal package, and each test has its own cabal package. I have copied the original packages into the repo under folders "Year20XX". To interact with them, run `cabal repl` either in the root directory or in the folder of the test you want to explore. Then you can load the modules and test the functions as usual.

## Test Suite

Run `cabal test all` to run the test suites. The test suites before 2024 are made by myself, while later Haskell tests have their own test suites.
4 changes: 4 additions & 0 deletions cabal.project
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
packages:
.
src/Year2024/
tests: True
1 change: 1 addition & 0 deletions doc-jan-haskell.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ test-suite test
build-depends:
base,
containers,
hft,
mtl,
text,
transformers,
Expand Down
25 changes: 25 additions & 0 deletions src/Year2024/hft.cabal
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
cabal-version: 3.0
-- WARNING: YOU MUST NOT UNDER ANY CIRCUMSTANCES EDIT THIS FILE, YOU HAVE BEEN WARNED
name: hft
version: 0.1.0.0
synopsis: Haskell Final Test 23/24
author: Imperial College London
maintainer: [email protected]
build-type: Simple

library
exposed-modules: Int, Types, Utilities, Examples
hs-source-dirs: src
default-language: Haskell2010
build-depends: base >=4.13 && <5,
containers

test-suite hft-test
type: exitcode-stdio-1.0
hs-source-dirs: test
default-language: Haskell2010
other-modules: IC.TestSuite
main-is: Tests.hs
ghc-options: -threaded
build-depends: hft,
base >=4.13 && <5
68 changes: 68 additions & 0 deletions src/Year2024/src/Examples.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
module Examples where

import Types
import Data.Ratio ((%))

p1, p2, p3, p4, p5 :: Polynomial
p1 = [(5,0)]
p2 = [(1,1)]
p3 = [(2,2),(-3,1),(1,0)]
p4 = [(4,1),(-3,0)]
p5 = [(2,3),(-2,1),(2,0)]

x :: Expr
x = P [(1,1)]

-- Basic polynomials
e1, e2, e3, e4, e5 :: Expr
e1 = P p1
e2 = P p2
e3 = P p3
e4 = P p4
e5 = P p5

-- Addition of polynomials
e6 :: Expr
e6 = Add e3 e5

-- Multiplication by constant
e7 :: Expr
e7 = Mul e1 e6

-- Simple functions of x
e8, e9 :: Expr
e8 = Log e2
e9 = Pow e2 (-1)

-- Inverse chain rule, id
e10, e11 :: Expr
e10 = Mul e4 e3
e11 = Mul (Pow x (-1)) (Log x)

-- Inverse chain rule, others
e12, e13 :: Expr
e12 = Mul e4 (Log e3)
e13 = Mul (Pow e3 (3/2)) e4

-- Now with a constant factor
e14, e15 :: Expr
e14 = Mul e4 (Pow (Mul e1 e3) (3/2))
e15 = Mul (P [(1,2), (-1,0)]) (Log (P [(1,3), (-3,1)]))

-- No integral to be found
e16 :: Expr
e16 = Mul (Log e3) (Pow e4 (1/2))

-- Secret testing...
e17, e18, e19, e20, e21, e22 :: Expr
e17 =
Mul (P [(4 % 5,1),((-3) % 5,0)]) (Pow (Mul (P [(5 % 1,0)]) (P [(2 % 1,2),((-3) % 1,1),(1 % 1,0)])) (3 % 2))
e18 =
Mul (P [(1 % 5,2),((-1) % 5,0)]) (Log (P [(1 % 1,3),((-3) % 1,1)]))
-- d/dx has factor of 3 => multiply by 1/3
e19 = P [(1,2), (-1,0)]
e20 = P [(1,3), (-3,1)]
e21 = Mul e19 (Log e20)

-- As above but making 5/3
e22 = Mul (Mul e1 e19) (Log e20)
130 changes: 130 additions & 0 deletions src/Year2024/src/Int.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
{-# LANGUAGE NegativeLiterals #-}
{-# LANGUAGE ViewPatterns #-}

module Int where

import GHC.Real
import Data.List
import Data.Maybe
import Control.Applicative

import Types
import Utilities
import Examples

import Data.Bifunctor

--
-- Universal assumptions/preconditions:
-- 1. All polynomials are in standard form with decreasing
-- powers of x
-- 2. 0 is represented by P [(0, 0)]; P [] is undefined for
-- the purposes of the exercise.
-- 3. All constants will be polynomials of the form
-- [(c, 0)], e.g. logarithms of constants and constant
-- powers will not appear.
-- 4. All computed integrals omit the constant of integration.
--

-------------------------------------------------
-- Part I (13 marks)

addP :: Polynomial -> Polynomial -> Polynomial
addP p1@((c1,e1):r1) p2@((c2,e2):r2)
| e1 > e2 = (c1, e1) : addP r1 p2
| e1 < e2 = (c2, e2) : addP p1 r2
| otherwise = (c1 + c2, e1) : addP r1 r2
addP p1 p2 = p1 ++ p2 -- one of them is empty

mulP :: Polynomial -> Polynomial -> Polynomial
mulP p = sumP . map (\(c,e) -> map (bimap (c *) (e +)) p)

sumP :: [Polynomial] -> Polynomial
sumP = foldl' addP [(0, 0)]

prodP :: [Polynomial] -> Polynomial
prodP = foldl' mulP [(1, 0)]

diffT :: Term -> Term
diffT (c, 0) = (0, 0)
diffT (c, e) = (c * (e % 1), e - 1)

-- > The speç should specify the constant term to be zero!
intT :: Term -> Term
intT (0, 0) = (0, 0)
intT (c, e) = (c / (e % 1 + 1), e + 1)

diffP :: Polynomial -> Polynomial
diffP = map diffT

intP :: Polynomial -> Polynomial
intP = map intT

-------------------------------------------------
-- Part II (7 marks)

diffE :: Expr -> Expr
diffE (P p) = P $ diffP p
diffE (Add e1 e2) = Add (diffE e1) (diffE e2)
diffE (Mul e1 e2) = Add (Mul (diffE e1) e2) (Mul e1 (diffE e2))
diffE (Pow e n) = Mul (Mul (P [(n, 0)]) (Pow e (n - 1))) (diffE e)
diffE (Log e) = Mul (Pow e (-1)) (diffE e)

--
-- Given
--
toExpr :: Rational -> Expr
toExpr n = P [(n, 0)]

isConstant :: Expr -> Bool
isConstant (P [(_, 0)]) = True
isConstant _ = False

simplifiedDiff :: Expr -> Expr
simplifiedDiff = simplify . diffE

printDiff :: Expr -> IO ()
printDiff = prettyPrint . simplifiedDiff

-------------------------------------------------
-- Part III (10 marks)

intE :: Expr -> Maybe Expr
intE (P p) = Just $ P (intP p)
intE (Add e1 e2) = Add <$> intE e1 <*> intE e2
intE (Mul e1 e2)
| isConstant e1 = Mul e1 <$> intE e2
| isConstant e2 = Mul e2 <$> intE e1
| otherwise = applyICR e1 e2 <|> applyICR e2 e1
intE e = applyICR e (toExpr 1)

applyICR :: Expr -> Expr -> Maybe Expr
applyICR fg g' = case factorise g' (diffE fg) of
Just coeff -> Just $ Mul (toExpr $ coeff / 2) (Pow fg 2)
Nothing -> case fg of
Pow g n -> do
coeff <- factorise g' (diffE g)
pure $ case n of
-1 -> Mul (toExpr coeff) (Log g)
_ -> Mul (toExpr $ coeff / (n + 1)) (Pow g (n + 1))
Log g -> do
coeff <- factorise g' (diffE g)
pure $ Mul (toExpr coeff) (Mul g (Add (Log g) (toExpr -1)))
_ -> Nothing
where
splitByCoeff (simplify -> e) = case e of
P [(c, 0)] -> (c, toExpr 1)
Mul (P [(c, 0)]) e' -> (c, e')
_ -> (1, e)
factorise (splitByCoeff -> (c1, r1)) (splitByCoeff -> (c2, r2))
| r1 == r2 = Just $ c1 / c2
| otherwise = Nothing

--
-- Given...
--
simplifiedInt :: Expr -> Maybe Expr
simplifiedInt = fmap simplify . intE

printInt :: Expr -> IO ()
printInt e = maybe (putStrLn "Fail") prettyPrint (simplifiedInt e)
15 changes: 15 additions & 0 deletions src/Year2024/src/Types.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module Types where

-- WARNING: DO NOT EDIT THIS FILE FOR *ANY* REASON, ANY CHANGES WILL BE DISCARDED
-- YOU WILL BE PENALISED IF YOU CODE NO LONGER COMPILES.

type Coefficient = Rational
type Exponent = Integer
type Term = (Coefficient, Exponent)
type Polynomial = [Term]
data Expr = P Polynomial
| Add Expr Expr
| Mul Expr Expr
| Pow Expr Rational
| Log Expr
deriving (Eq, Ord, Show)
Loading

0 comments on commit 55de337

Please sign in to comment.