Commit fd87ac2f authored by Jochen Schulz's avatar Jochen Schulz
Browse files

merge and work on exercises

parent d4d2f203
...@@ -22,7 +22,7 @@ TODO 2014-09-04 Musterloesungen erstellen ...@@ -22,7 +22,7 @@ TODO 2014-09-04 Musterloesungen erstellen
ex19 parallel arrays: rsa neu erstellen ex19 parallel arrays: rsa neu erstellen
ex20p5 jacobi solver ex20p5 jacobi solver
ex21p3 centralized differences + noise ex21p3 centralized differences + noise
ex22p4 auf cg umstellen (siam problem 20000) ex22p4 auf cg umstellen (siam problem 20000) (pending..)
ex24p3 solution missing ex24p3 solution missing
ex24 mandelbrot-irgendwas ex24 mandelbrot-irgendwas
ex24 change to endtime? ex24 change to endtime?
...@@ -50,22 +50,25 @@ WAITING 2015-07-23 parallel and concurrent, cloudhaskell ...@@ -50,22 +50,25 @@ WAITING 2015-07-23 parallel and concurrent, cloudhaskell
:LOGBOOK: :LOGBOOK:
WAITING: 2015-07-23 11:08:18 WAITING: 2015-07-23 11:08:18
xx *gerlind plonka waveleti bildverarbeitung
?? pde> meshless methods (heat equation, euler equation?
xx lube: finite elements (schwache formulierung) heat equation (hmatrix) xx lube: finite elements (schwache formulierung) heat equation (hmatrix)
xx+1 *differentialgeometrie -> henrik (laplace weak implementieren) (hmatrix) xx+1 *differentialgeometrie -> henrik (laplace weak implementieren) (hmatrix)
xx *inverse probleme: intergralgleichungen, xx *inverse probleme: intergralgleichungen,
xx *gerlind plonka waveleti bildverarbeitung
volterra intergralgleichungen (numeric differentiation) (schon in ex27?)
?? pde> meshless methods (heat equation, euler equation?
TODO 2015-09-01 data analysis testen (fehlen auf jeden fall pakete) TODO 2015-09-01 data analysis testen (fehlen auf jeden fall pakete)
TODO 2015-08-05 allgemein: interpolation/fitting TODO 2015-08-05 allgemein: interpolation/fitting
TODO 2014-08-21 immutable/mutable TODO 2014-08-21 immutable/mutable
WAITING 2014-08-08 algebraische typen detaillierter DONE 2014-08-08 algebraische typen detaillierter
CLOSED: 2016-03-21 16:13:21
:LOGBOOK: :LOGBOOK:
DONE: 2016-03-21 16:13:21
WAITING: 2015-07-02 17:28:15 WAITING: 2015-07-02 17:28:15
WAITING 2014-09-01 (spline-interpolation? , (siehe auch mapy)) WAITING 2014-09-01 (spline-interpolation? , (siehe auch mapy))
...@@ -80,6 +83,8 @@ WAITING 2014-07-29 headmay : http://hackage.haskell.org/package/safe-0.3/docs/Sa ...@@ -80,6 +83,8 @@ WAITING 2014-07-29 headmay : http://hackage.haskell.org/package/safe-0.3/docs/Sa
:LOGBOOK: :LOGBOOK:
WAITING: 2015-06-12 12:28:11 WAITING: 2015-06-12 12:28:11
ANDEREVORLESUNG:
WAITING 2014-08-05 (Lambda Kalkuel einfuehren) WAITING 2014-08-05 (Lambda Kalkuel einfuehren)
:LOGBOOK: :LOGBOOK:
WAITING: 2015-06-12 12:28:12 WAITING: 2015-06-12 12:28:12
......
-- ghc -O2 -prof -fprof-auto -rtsopts factorial.hs && ./factorial +RTS -pi -hc -sstderr -RTS -- ghc -O2 -prof -fprof-auto -rtsopts factorial.hs && ./factorial +RTS -pi -hc -sstderr -RTS
{-# LANGUAGE BangPatterns #-} {-# LANGUAGE BangPatterns #-}
facE :: (Show a, Integral a) => a -> a facE :: (Show a, Integral a) => a -> a
facE i facE i
| i<0 = error "Negative Faculty not defined" | i<0 = error "Negative Faculty not defined"
...@@ -20,6 +21,8 @@ facRf x = fac' x 1 where ...@@ -20,6 +21,8 @@ facRf x = fac' x 1 where
fac' 1 y = y fac' 1 y = y
fac' f y = fac' (f-1) $! (f*y) fac' f y = fac' (f-1) $! (f*y)
Fractional
main :: IO () main :: IO ()
main = do main = do
let g = facNE 10000 let g = facNE 10000
......
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
# Exercises: type classes # Exercises: type classes
## problem 1 ## problem 1
Explain the difference between Explain the difference between
```haskell ```haskell
type Point = (Double, Double) type Point = (Double, Double)
``` ```
and and
```haskell ```haskell
data Point = Point Double Double data Point = Point Double Double
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## problem 2 ## problem 2
Write an instance of `Show` for `Shape` Write an instance of `Show` for `Shape`
```haskell ```haskell
data Point = Point Double Double data Point = Point Double Double
instance Show Point where instance Show Point where
show (Point x y) = "(" ++ show x ++ ", " ++ show y ++ ")" show (Point x y) = "(" ++ show x ++ ", " ++ show y ++ ")"
data Shape = Circle Point Double data Shape = Circle Point Double
| Rectangle Point Double Double | Rectangle Point Double Double
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## problem 3 ## problem 3
- Write an instance of `Eq` for `Shape`. - Write an instance of `Eq` for `Shape`.
- Write an instance of `Ord` for `Shape`. - Write an instance of `Ord` for `Shape`.
- Compare to the behaviour of the automatically generated `Ord` instance from a `deriving` clause and explain. - Compare to the behaviour of the automatically generated `Ord` instance from a `deriving` clause and explain.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## problem 4 ## problem 4
Vectors (in the mathematical sense) are required in many numerical applications. Vectors (in the mathematical sense) are required in many numerical applications.
- Implement a typeclass for vectors of arbitrary dimensions. - Implement a typeclass for vectors of arbitrary dimensions.
- Implement addition, scalar multiplication and inner product. - Implement addition, scalar multiplication and inner product.
- How could matrices be represented? - How could matrices be represented?
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## problem 5 ## problem 5
Write classes `ShowHex` and `ShowBin` which output numbers in hex and binary, and implement them for `Int`. Write classes `ShowHex` and `ShowBin` which output numbers in hex and binary, and implement them for `Int`.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## problem 6 ## problem 6
lookup the function `unfoldr` and first write an own version of `iterate` by using `unfoldr`. Then rewrite the instances of problem 5 via using `unfoldr`. lookup the function `unfoldr` and first write an own version of `iterate` by using `unfoldr`. Then rewrite the instances of problem 5 via using `unfoldr`.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## problem 7 ## problem 7
Converting between metric and imperial units: Write a function `convertUnit :: (Double, String) -> (Double, String)` that behaves like Converting between metric and imperial units: Write a function `convertUnit :: (Double, String) -> (Double, String)` that behaves like
```haskell ```haskell
convertUnit (1, "m") == (1.09361, "yd") convertUnit (1, "m") == (1.09361, "yd")
convertUnit (1, "kg") == (2.20462, "lb") convertUnit (1, "kg") == (2.20462, "lb")
``` ```
etc... etc...
Is there a more type-safe way of doing this? Is there a more type-safe way of doing this?
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## problem 8 ## problem 8
Prove the second functor law for lists: Prove the second functor law for lists:
```haskell ```haskell
fmap (f . g) == fmap f . fmap g fmap (f . g) == fmap f . fmap g
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## problem 9 ## problem 9
Create a data type for polynominial rings with real coefficients and write the instances for `Show`, `Eq` and `Num`. Create a data type for polynomial rings with real coefficients and write the instances for `Show`, `Eq` and `Num`.
*Note*: a formal polynominial is nothing else than a list of coefficents. *Note*: a formal polynomial is nothing else than a list of coefficents.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
``` ```
......
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
# Exercises: boundary value problems # Exercises: boundary value problems
## problem 1 ## problem 1
implement a *Gauss-Seidel* algorithm for solving linear equations. implement a *Gauss-Seidel* algorithm for solving linear equations.
The Gauss–Seidel method is an iterative technique for solving a square system of n linear equations with unknown x: The Gauss–Seidel method is an iterative technique for solving a square system of n linear equations with unknown x:
$$A x = b$$ $$A x = b$$
It is defined by the iteration It is defined by the iteration
$$L_∗ x^{( k + 1 )} = b − U x^{( k )}$$ $$L_∗ x^{( k + 1 )} = b − U x^{( k )}$$
where $x^{( k )}$ is the $k$-th approximation or iteration of $x$ ,$x^{k + 1}$ is the next value of $x$ , and the matrix $A$ is decomposed into a lower triangular component $L_∗$ , and a strictly upper triangular component $U$: $A = L_∗ + U$ where $x^{( k )}$ is the $k$-th approximation or iteration of $x$ ,$x^{k + 1}$ is the next value of $x$ , and the matrix $A$ is decomposed into a lower triangular component $L_∗$ , and a strictly upper triangular component $U$: $A = L_∗ + U$
We rewrite this a little bit to for the algorithm: We rewrite this a little bit to for the algorithm:
$$x^{( k + 1 )} = T x^{( k )} + C$$ $$x^{( k + 1 )} = T x^{( k )} + C$$
where where
$$T = - L_∗^{-1} U$$ and $$C = L_∗^{-1} b$$ $$T = - L_∗^{-1} U$$ and $$C = L_∗^{-1} b$$
Write a recursive function which makes this iteration. The iteration should stop both from a tolerance value of the difference of adjacent $x$ and a maximum of iterations. Write a recursive function which makes this iteration. The iteration should stop both from a tolerance value of the difference of adjacent $x$ and a maximum of iterations.
For a test case use the matrix and right hand side from the lecture. For a test case use the matrix and right hand side from the lecture.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## problem 2 ## problem 2
Implement the *jacobi* iterative algorithm for solving linear equations. First decompose the Implement the *jacobi* iterative algorithm for solving linear equations. First decompose the
matrix $A$ into the diagonal part $D$ and the remnant $R$: matrix $A$ into the diagonal part $D$ and the remnant $R$:
$$ A = D + R$$ $$ A = D + R$$
Then iterate the following Then iterate the following
$$x^{( k + 1 )} = D^{ - 1} ( b - R x^{( k )} )$$ $$x^{( k + 1 )} = D^{ - 1} ( b - R x^{( k )} )$$
where $x^{ ( k )}$ is the $k$-th approximation or iteration of $x$ and $x^{ ( k + 1 )}$ is the next. where $x^{ ( k )}$ is the $k$-th approximation or iteration of $x$ and $x^{ ( k + 1 )}$ is the next.
Write a recursive function which makes this iteration. The iteration should stop both from a tolerance value of the difference of adjacent x and a maximum of iterations. For a testcase use the matrix and right hand side from the lecture. Write a recursive function which makes this iteration. The iteration should stop both from a tolerance value of the difference of adjacent x and a maximum of iterations. For a testcase use the matrix and right hand side from the lecture.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## problem 3 ## problem 3
Write an implementation of the *conjugate gradient* (CG) method. This method solves Write an implementation of the *conjugate gradient* (CG) method. This method solves
$$A x = b$$ $$A x = b$$
by an iteration of the form $x_0 = 0$, $r_0 = p_0 = b$, by an iteration of the form $x_0 = 0$, $r_0 = p_0 = b$,
$$ $$
\begin{align} \begin{align}
\alpha_k &= \frac{{\lVert r_k \rVert}^2}{\langle p_k, A p_k \rangle} \\ \alpha_k &= \frac{{\lVert r_k \rVert}^2}{\langle p_k, A p_k \rangle} \\
x_{k+1} &= x_k + \alpha_k p_k \\ x_{k+1} &= x_k + \alpha_k p_k \\
r_{k+1} &= r_k - \alpha_k A p_k \\ r_{k+1} &= r_k - \alpha_k A p_k \\
p_{k+1} &= r_{k+1} + \frac{{\lVert r_{k+1} \rVert}^2}{{\lVert r_k \rVert}^2} p_k p_{k+1} &= r_{k+1} + \frac{{\lVert r_{k+1} \rVert}^2}{{\lVert r_k \rVert}^2} p_k
\end{align}, \end{align},
$$ $$
stopping the iterations at the smallest $K$ for which $\lVert r_K \rVert < \text{tol}$. stopping the iterations at the smallest $K$ for which $\lVert r_K \rVert < \text{tol}$.
An interesting property of this method in contrast to the ones from the previous problems is that it does not need $A$ in form of a matrix; it suffices to be able to apply $A$ to any given vector $p$, so $A$ can also be passed as a function `Vec Double -> Vec Double`. An interesting property of this method in contrast to the ones from the previous problems is that it does not need $A$ in form of a matrix; it suffices to be able to apply $A$ to any given vector $p$, so $A$ can also be passed as a function `Vec Double -> Vec Double`.
The CG implementation should therefore have a signature like this: The CG implementation should therefore have a signature like this:
```haskell ```haskell
cg :: Double -> (Vec Double -> Vec Double) -> Vec Double -> Vec Double cg :: Double -> (Vec Double -> Vec Double) -> Vec Double -> Vec Double
cg tol f rhs = [...] cg tol f rhs = [...]
``` ```
Apply the method to the same test case as above, but this time reimplement it using the function Apply the method to the same test case as above, but this time reimplement it using the function
```haskell ```haskell
conv :: Vec t -> Vec t -> Vec t conv :: Vec t -> Vec t -> Vec t
``` ```
from `Numeric.LinearAlgebra.Repa`, which implements a convolution without actually creating the matrix. Note that `conv` returns a vector that is larger than the input; use the boundary values to handle this. from `Numeric.LinearAlgebra.Repa`, which implements a convolution without actually creating the matrix. Note that `conv` returns a vector that is larger than the input; use the boundary values to handle this.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## problem 4 ## problem 4
Let A be a $20.000 \times 20.000$ matrix, which entries are all zero besides the prime numbers $2, 3, 5, 7, \ldots, 224737$ on the diagonal and the number 1 in all entries $a_{ij}$ with Let A be a $20.000 \times 20.000$ matrix, which entries are all zero besides the prime numbers $2, 3, 5, 7, \ldots, 224737$ on the diagonal and the number 1 in all entries $a_{ij}$ with
$$|i − j| = 1, 2, 4, 8, \ldots , 16384.$$ $$|i − j| = 1, 2, 4, 8, \ldots , 16384.$$
What is the $(1, 1)$ entry of $A^{−1}$? How can you check/visualize the structure of the matrix? Be sure to use a good method for saving the matrix (use sparse..). What is the $(1, 1)$ entry of $A^{−1}$? How can you check/visualize the structure of the matrix? Be sure to use a good method for saving the matrix.
*bonus*: implement sparse variants of gauss-seidel and/or conjugate gradiant and try to use them as solver here.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
``` ```
......
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
# Exercises: type classes # Exercises: type classes
## problem 1 ## problem 1
Explain the difference between Explain the difference between
```haskell ```haskell
type Point = (Double, Double) type Point = (Double, Double)
``` ```
and and
```haskell ```haskell
data Point = Point Double Double data Point = Point Double Double
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## problem 2 ## problem 2
Write an instance of `Show` for `Shape` Write an instance of `Show` for `Shape`
```haskell ```haskell
data Point = Point Double Double data Point = Point Double Double
instance Show Point where instance Show Point where
show (Point x y) = "(" ++ show x ++ ", " ++ show y ++ ")" show (Point x y) = "(" ++ show x ++ ", " ++ show y ++ ")"
data Shape = Circle Point Double data Shape = Circle Point Double
| Rectangle Point Double Double | Rectangle Point Double Double
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
data Point = Point Double Double data Point = Point Double Double
instance Show Point where instance Show Point where
show (Point x y) = "(" ++ show x ++ ", " ++ show y ++ ")" show (Point x y) = "(" ++ show x ++ ", " ++ show y ++ ")"
data Shape = Circle Point Double data Shape = Circle Point Double
| Rectangle Point Double Double | Rectangle Point Double Double
instance Show Shape where instance Show Shape where
show (Circle c r) = "Circle with center " ++ show c ++ " and radius " ++ show r show (Circle c r) = "Circle with center " ++ show c ++ " and radius " ++ show r
show (Rectangle p a b) = "Rectangle with top-left corner " ++ show p ++ show (Rectangle p a b) = "Rectangle with top-left corner " ++ show p ++
" and edges " ++ show a ++ " and " ++ show b " and edges " ++ show a ++ " and " ++ show b
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## problem 3 ## problem 3
- Write an instance of `Eq` for `Shape`. - Write an instance of `Eq` for `Shape`.
- Write an instance of `Ord` for `Shape`. - Write an instance of `Ord` for `Shape`.
- Compare to the behaviour of the automatically generated `Ord` instance from a `deriving` clause and explain. - Compare to the behaviour of the automatically generated `Ord` instance from a `deriving` clause and explain.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
instance Eq Point where instance Eq Point where
(Point x1 y1) == (Point x2 y2) = (x1 == x2) && (y1 == y2) (Point x1 y1) == (Point x2 y2) = (x1 == x2) && (y1 == y2)
instance Eq Shape where instance Eq Shape where
(Circle c1 r1) == (Circle c2 r2) = (c1 == c2) && (r1 == r2) (Circle c1 r1) == (Circle c2 r2) = (c1 == c2) && (r1 == r2)
(Rectangle p1 a1 b1) == (Rectangle p2 a2 b2) = (p1 == p2) && (a1 == a2) && (b1 == b2) (Rectangle p1 a1 b1) == (Rectangle p2 a2 b2) = (p1 == p2) && (a1 == a2) && (b1 == b2)
_ == _ = False _ == _ = False
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
import Data.Function import Data.Function
-- problem: unclear how to compare shapes. e.g. compare areas: -- problem: unclear how to compare shapes. e.g. compare areas:
instance Ord Shape where instance Ord Shape where
compare = compare `on` area compare = compare `on` area
where area (Rectangle _ a b) = a * b where area (Rectangle _ a b) = a * b
area (Circle _ r) = pi * r**2 area (Circle _ r) = pi * r**2
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
data PointDeriv = PointDeriv Double Double deriving (Eq, Ord) data PointDeriv = PointDeriv Double Double deriving (Eq, Ord)
data ShapeDeriv = CircleDeriv PointDeriv Double data ShapeDeriv = CircleDeriv PointDeriv Double
| RectangleDeriv PointDeriv Double Double | RectangleDeriv PointDeriv Double Double
deriving (Eq, Ord) deriving (Eq, Ord)
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
CircleDeriv (PointDeriv 0 0) 1 < CircleDeriv (PointDeriv 1 0) 10 CircleDeriv (PointDeriv 0 0) 1 < CircleDeriv (PointDeriv 1 0) 10
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
CircleDeriv (PointDeriv 0 0) 10 < RectangleDeriv (PointDeriv 0 0) 1 1 CircleDeriv (PointDeriv 0 0) 10 < RectangleDeriv (PointDeriv 0 0) 1 1
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
RectangleDeriv (PointDeriv 0 0) 2 3 < RectangleDeriv (PointDeriv 0 0) 3 2 RectangleDeriv (PointDeriv 0 0) 2 3 < RectangleDeriv (PointDeriv 0 0) 3 2
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## problem 4 ## problem 4
Vectors (in the mathematical sense) are required in many numerical applications. Vectors (in the mathematical sense) are required in many numerical applications.
- Implement a typeclass for vectors of arbitrary dimensions. - Implement a typeclass for vectors of arbitrary dimensions.
- Implement addition, scalar multiplication and inner product. - Implement addition, scalar multiplication and inner product.
- How could matrices be represented? - How could matrices be represented?
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
data Vector = Vector { vec :: [Double] } deriving (Show) data Vector = Vector { vec :: [Double] } deriving (Show)
-- Downside: length of vector is unspecified, needs to be checked at runtime. -- Downside: length of vector is unspecified, needs to be checked at runtime.
-- Otherwise, we would need a seperate type for each dimension: Vector1d, Vector2d, ... -- Otherwise, we would need a seperate type for each dimension: Vector1d, Vector2d, ...
addVector :: Vector -> Vector -> Vector addVector :: Vector -> Vector -> Vector
addVector a b addVector a b
| length c /= length d = error "Dimensions are not equal" | length c /= length d = error "Dimensions are not equal"
| otherwise = Vector (zipWith (+) c d) | otherwise = Vector (zipWith (+) c d)
where c = vec a where c = vec a
d = vec b d = vec b
scalar :: Vector -> Double -> Vector scalar :: Vector -> Double -> Vector
scalar a b = Vector (map (*b) (vec a)) scalar a b = Vector (map (*b) (vec a))
scalarProd :: Vector -> Vector -> Double scalarProd :: Vector -> Vector -> Double
scalarProd a b scalarProd a b
| length c /= length d = error "Vector sizes must match" | length c /= length d = error "Vector sizes must match"
| otherwise = sum (zipWith (*) c d) | otherwise = sum (zipWith (*) c d)
where c = vec a where c = vec a
d = vec b d = vec b
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
data Matrix = Matrix { columns :: [Vector] } data Matrix = Matrix { columns :: [Vector] }
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## problem 5 ## problem 5
Write classes `ShowHex` and `ShowBin` which output numbers in hex and binary, and implement them for `Int`. Write classes `ShowHex` and `ShowBin` which output numbers in hex and binary, and implement them for `Int`.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
class ShowHex a where class ShowHex a where
showHex :: a -> String showHex :: a -> String
instance ShowHex Int where instance ShowHex Int where
showHex 0 = "0x0" showHex 0 = "0x0"
showHex n = "0x" ++ (reverse $ showHex' n) showHex n = "0x" ++ (reverse $ showHex' n)
where showHex' 0 = "" where showHex' 0 = ""
showHex' m = let (q, r) = quotRem m 16 showHex' m = let (q, r) = quotRem m 16
in ((['0'..'9']++['a'..'f']) !! r) : showHex' q in ((['0'..'9']++['a'..'f']) !! r) : showHex' q
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
class ShowBin a where class ShowBin a where
showBin :: a -> String showBin :: a -> String
instance ShowBin Int where instance ShowBin Int where
showBin 0 = "0" showBin 0 = "0"
showBin n = reverse $ showBin' n showBin n = reverse $ showBin' n
where showBin' 0 = "" where showBin' 0 = ""
showBin' m = let (q, r) = quotRem m 2 showBin' m = let (q, r) = quotRem m 2
in (['0','1'] !! r) : showBin' q in (['0','1'] !! r) : showBin' q
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## problem 6 ## problem 6
lookup the function `unfoldr` and first write an own version of `iterate` by using `unfoldr`. Then rewrite the instances of problem 5 via using `unfoldr`. lookup the function `unfoldr` and first write an own version of `iterate` by using `unfoldr`. Then rewrite the instances of problem 5 via using `unfoldr`.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
import Data.List import Data.List
iterate' f = unfoldr (\x -> Just (x, f x)) iterate' f = unfoldr (\x -> Just (x, f x))
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
-- The recursion pattern above is abstracted by -- The recursion pattern above is abstracted by
-- unfoldr :: (a -> Maybe (b, a)) -> a -> [b] -- unfoldr :: (a -> Maybe (b, a)) -> a -> [b]
-- So a nicer way to write the instances is this: -- So a nicer way to write the instances is this:
import Data.List import Data.List
import Data.Tuple import Data.Tuple
toRadix rad 0 = [0] toRadix rad 0 = [0]
toRadix rad n = reverse . unfoldr (\m -> if m == 0 then Nothing else Just (swap $ quotRem m rad)) $ n toRadix rad n = reverse . unfoldr (\m -> if m == 0 then Nothing else Just (swap $ quotRem m rad)) $ n
toDigit = ((['0'..'9'] ++ ['a'..'z']) !!) toDigit = ((['0'..'9'] ++ ['a'..'z']) !!)
instance ShowHex Int where instance ShowHex Int where
showHex = ("0x" ++) . map toDigit . toRadix 16 showHex = ("0x" ++) . map toDigit . toRadix 16
instance ShowBin Int where instance ShowBin Int where
showBin = ("0x" ++) . map toDigit . toRadix 2 showBin = ("0x" ++) . map toDigit . toRadix 2
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## problem 7 ## problem 7
Converting between metric and imperial units: Write a function `convertUnit :: (Double, String) -> (Double, String)` that behaves like Converting between metric and imperial units: Write a function `convertUnit :: (Double, String) -> (Double, String)` that behaves like
```haskell ```haskell
convertUnit (1, "m") == (1.09361, "yd") convertUnit (1, "m") == (1.09361, "yd")
convertUnit (1, "kg") == (2.20462, "lb") convertUnit (1, "kg") == (2.20462, "lb")
``` ```
etc... etc...
Is there a more type-safe way of doing this? Is there a more type-safe way of doing this?
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
convertUnit :: (Double, String) -> (Double, String) convertUnit :: (Double, String) -> (Double, String)
convertUnit (x, l) convertUnit (x, l)
| l == "m" = (1.09361 * x, "yd") | l == "m" = (1.09361 * x, "yd")
| l == "l" = (0.264172 * x, "gal") | l == "l" = (0.264172 * x, "gal")
| l == "kg" = (2.20462 * x, "lb") | l == "kg" = (2.20462 * x, "lb")
| l == "yd" = (x / 1.09361, "m") | l == "yd" = (x / 1.09361, "m")
| l == "gal" = (x / 0.264172, "l") | l == "gal" = (x / 0.264172, "l")
| l == "lb" = (x / 2.20462, "kg") | l == "lb" = (x / 2.20462, "kg")
| otherwise = error "Invalid input" | otherwise = error "Invalid input"
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
-- Using types (via http://shuklan.com/haskell/lec05.html): -- Using types (via http://shuklan.com/haskell/lec05.html):
data MetricUnit = Meter data MetricUnit = Meter
| Liter | Liter
| KiloGram | KiloGram
deriving (Show, Eq) deriving (Show, Eq)
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
data ImperialUnit = Yard data ImperialUnit = Yard
| Gallon | Gallon
| Pound | Pound
deriving (Show, Eq) deriving (Show, Eq)
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
data Measurement = MetricMeasurement Double MetricUnit data Measurement = MetricMeasurement Double MetricUnit
| ImperialMeasurement Double ImperialUnit | ImperialMeasurement Double ImperialUnit
deriving (Show, Eq) deriving (Show, Eq)
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
convertUnit :: Measurement -> Measurement convertUnit :: Measurement -> Measurement
convertUnit (MetricMeasurement x u) convertUnit (MetricMeasurement x u)
| u == Meter = ImperialMeasurement (1.0936*x) Yard | u == Meter = ImperialMeasurement (1.0936*x) Yard
| u == Liter = ImperialMeasurement (0.2642*x) Gallon | u == Liter = ImperialMeasurement (0.2642*x) Gallon
| u == KiloGram = ImperialMeasurement (2.2046*x) Pound | u == KiloGram = ImperialMeasurement (2.2046*x) Pound
convertUnit (ImperialMeasurement x u) convertUnit (ImperialMeasurement x u)
| u == Yard = MetricMeasurement (0.9144*x) Meter | u == Yard = MetricMeasurement (0.9144*x) Meter
| u == Gallon = MetricMeasurement (3.7854*x) Liter | u == Gallon = MetricMeasurement (3.7854*x) Liter
| u == Pound = MetricMeasurement (0.4536*x) KiloGram | u == Pound = MetricMeasurement (0.4536*x) KiloGram
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## problem 8 ## problem 8
Prove the second functor law for lists: Prove the second functor law for lists:
```haskell ```haskell
fmap (f . g) == fmap f . fmap g fmap (f . g) == fmap f . fmap g
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
-- Induction start: -- Induction start:
fmap (f . g) [] == [] == fmap f (fmap g []) fmap (f . g) [] == [] == fmap f (fmap g [])
-- Induction step: -- Induction step:
fmap (f . g) (x:xs) fmap (f . g) (x:xs)
== (f . g) x : fmap (f . g) xs == (f . g) x : fmap (f . g) xs
== f (g x) : fmap f (fmap g xs) == f (g x) : fmap f (fmap g xs)
== fmap f (g x : fmap g xs) == fmap f (g x : fmap g xs)
== fmap f (fmap g (x:xs)) == fmap f (fmap g (x:xs))
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## problem 9 ## problem 9
Create a data type for polynominial rings with real coefficients and write the instances for `Show`, `Eq` and `Num`. Create a data type for polynomial rings with real coefficients and write the instances for `Show`, `Eq` and `Num`.
*Note*: a formal polynominial is nothing else than a list of coefficents. *Note*: a formal polynomial is nothing else than a list of coefficents.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
-- TODO : cleanup -- TODO : cleanup
import Data.List import Data.List
newtype Polynomial = Polynomial [Double] newtype Polynomial = Polynomial [Double]
cleanPoly (Polynomial a) = Polynomial (dropWhileEnd (==0) a) cleanPoly (Polynomial a) = Polynomial (dropWhileEnd (==0) a)
deg :: Polynomial -> Int deg :: Polynomial -> Int
deg (Polynomial a) = length a - 1 deg (Polynomial a) = length a - 1
lcoeff :: Polynomial -> Double lcoeff :: Polynomial -> Double
lcoeff (Polynomial a) = last a lcoeff (Polynomial a) = last a
monomial :: Int -> Double -> Polynomial monomial :: Int -> Double -> Polynomial
monomial d a = Polynomial (replicate d 0 ++ [a]) monomial d a = Polynomial (replicate d 0 ++ [a])
fromDouble :: Double -> Polynomial fromDouble :: Double -> Polynomial
fromDouble a = Polynomial [a] -- also: fromDouble = monomial 0 fromDouble a = Polynomial [a] -- also: fromDouble = monomial 0
zero = Polynomial [] zero = Polynomial []
printPoly a = ((++) "P(X) = " . intercalate " + " . reverse . filter (/= "") . zipWith zipper [0..length a-1]) a printPoly a = ((++) "P(X) = " . intercalate " + " . reverse . filter (/= "") . zipWith zipper [0..length a-1]) a
where where
zipper _ 0 = "" zipper _ 0 = ""
zipper power coeff = show coeff ++ "*X^" ++ show power zipper power coeff = show coeff ++ "*X^" ++ show power
instance Show Polynomial where instance Show Polynomial where
show (Polynomial a) = printPoly a show (Polynomial a) = printPoly a
instance Eq Polynomial where instance Eq Polynomial where
(Polynomial a) == (Polynomial b) = a == b (Polynomial a) == (Polynomial b) = a == b
addPoly [] p = p addPoly [] p = p
addPoly p [] = p addPoly p [] = p
addPoly (x:xs) (y:ys) = (x+y:addPoly xs ys) addPoly (x:xs) (y:ys) = (x+y:addPoly xs ys)
cauchyProd p q = [sum [(p !! i) * (q !! j) | i <- [0..lp-1], j <- [0..lq-1], i+j == n] | n <- [0..lp+lq-2]] cauchyProd p q = [sum [(p !! i) * (q !! j) | i <- [0..lp-1], j <- [0..lq-1], i+j == n] | n <- [0..lp+lq-2]]
where where
lp = length p lp = length p
lq = length q lq = length q
instance Num Polynomial where instance Num Polynomial where
(Polynomial a) + (Polynomial b) = cleanPoly (Polynomial (addPoly a b)) (Polynomial a) + (Polynomial b) = cleanPoly (Polynomial (addPoly a b))
negate (Polynomial a) = Polynomial (map negate a) negate (Polynomial a) = Polynomial (map negate a)
fromInteger a = Polynomial [fromInteger a] fromInteger a = Polynomial [fromInteger a]
abs (Polynomial a) = Polynomial (map abs a) abs (Polynomial a) = Polynomial (map abs a)
signum (Polynomial a) = Polynomial (map signum a) signum (Polynomial a) = Polynomial (map signum a)
(Polynomial a) * (Polynomial b) = Polynomial (cauchyProd a b) (Polynomial a) * (Polynomial b) = Polynomial (cauchyProd a b)
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
-- example -- example
p1 = fromDouble 3.14 p1 = fromDouble 3.14
p2 = monomial 3 2.17 p2 = monomial 3 2.17
p1 p1
p2 p2
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
``` ```
......
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
# Exercises: integration and differentiation # Exercises: integration and differentiation
## problem 1 ## problem 1
Find an approximate solution for the fixed point equation Find an approximate solution for the fixed point equation
$$x = e^{-x}.$$ $$x = e^{-x}.$$
Use $x_0 = 1.1$ as initial value and break after 1000 iterations or if the error is small enough. Use $x_0 = 1.1$ as initial value and break after 1000 iterations or if the error is small enough.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
fixp :: Double -> Int -> Double -> (Double -> Double) -> Double fixp :: Double -> Int -> Double -> (Double -> Double) -> Double
fixp tol maxit x0 f = fixp tol maxit x0 f =
case converged of case converged of
x:_ -> x x:_ -> x
otherwise -> last iterates otherwise -> last iterates
where iterates = take maxit $ iterate f x0 where iterates = take maxit $ iterate f x0
converged = [ x | (x, xprev) <- zip (tail iterates) iterates converged = [ x | (x, xprev) <- zip (tail iterates) iterates
, abs (x - xprev) < tol ] , abs (x - xprev) < tol ]
fixp 1e-5 1000 1.1 $ \x -> exp (-x) fixp 1e-5 1000 1.1 $ \x -> exp (-x)
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## problem 2 ## problem 2
Write a function that performs simple numerical (Riemann) integration using step functions. Write a function that performs simple numerical (Riemann) integration using step functions.
A function $\phi:[a,b] \rightarrow \mathbb{R}$ is called step function if there exists a partion of $[a,b]$ into intervals such that $\phi$ is constant on each interval. A function $\phi:[a,b] \rightarrow \mathbb{R}$ is called step function if there exists a partion of $[a,b]$ into intervals such that $\phi$ is constant on each interval.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
int :: Double -> Double -> Int -> (Double -> Double) -> Double int :: Double -> Double -> Int -> (Double -> Double) -> Double
int a b n f = (b-a) / n' * sum (map f xs) int a b n f = (b-a) / n' * sum (map f xs)
where xs = [ a + fromIntegral k / n' * (b-a) | k <- [0..n] ] where xs = [ a + fromIntegral k / n' * (b-a) | k <- [0..n] ]
n' = fromIntegral n n' = fromIntegral n
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## problem 3 ## problem 3
Numerically compute the derivative of $f(x) = \sin(15x)$, $x \in [0, 2\pi]$ given a vector of noisy values $f(x_k) + \epsilon_k$, for $x_k = 2 \pi k / N$, $k \in \{0, 1, \ldots, N-1\}$. Here, $\epsilon_k$ are normally distributed noise variables with mean 0 and variance $\sigma$. Compare the result to the analytical derivative by computing a suitably scaled norm of the difference, averaged over sufficiently many noise realizations, and present the results graphically for varying $N$ and $\sigma$. Numerically compute the derivative of $f(x) = \sin(15x)$, $x \in [0, 2\pi]$ given a vector of noisy values $f(x_k) + \epsilon_k$, for $x_k = 2 \pi k / N$, $k \in \{0, 1, \ldots, N-1\}$. Here, $\epsilon_k$ are normally distributed noise variables with mean 0 and variance $\sigma$. Compare the result to the analytical derivative by computing a suitably scaled norm of the difference, averaged over sufficiently many noise realizations, and present the results graphically for varying $N$ and $\sigma$.
*Note*: You can generate random vectors either using the standard `System.Random` functions, or *Note*: You can generate random vectors either using the standard `System.Random` functions, or
```haskell ```haskell
randomVector :: Seed -> RandDist -> Int -> Vec Double randomVector :: Seed -> RandDist -> Int -> Vec Double
``` ```
from `Numeric.LinearAlgebra.Repa`. As seed values for the different noise realization, you can use `[0..]` for simplicity. from `Numeric.LinearAlgebra.Repa`. As seed values for the different noise realization, you can use `[0..]` for simplicity.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
import Graphics.Rendering.Plot import Graphics.Rendering.Plot
import qualified Data.Array.Repa as Repa import qualified Data.Array.Repa as Repa
import Data.Array.Repa hiding (map, (++)) import Data.Array.Repa hiding (map, (++))
import Numeric.LinearAlgebra.Helpers import Numeric.LinearAlgebra.Helpers
import Numeric.LinearAlgebra.Repa import Numeric.LinearAlgebra.Repa
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
periodicCentralDiff :: Double -> Vec Double -> Vec Double periodicCentralDiff :: Double -> Vec Double -> Vec Double
periodicCentralDiff h f = computeS $ scale (1/(2*h)) (computeS (fLeft -^ fRight) :: Vec Double) periodicCentralDiff h f = computeS $ scale (1/(2*h)) (computeS (fLeft -^ fRight) :: Vec Double)
where where
n = vlength f n = vlength f
fLeft = subVector 1 (n-1) f `append` subVector 0 1 f fLeft = subVector 1 (n-1) f `append` subVector 0 1 f
fRight = subVector (n-1) 1 f `append` subVector 0 (n-1) f fRight = subVector (n-1) 1 f `append` subVector 0 (n-1) f
periodicCentralDiff 1 (vec [1,2,3,2,1,0]) :: Vec Double periodicCentralDiff 1 (vec [1,2,3,2,1,0]) :: Vec Double
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` haskell ``` haskell
steps = 200
xs = subVector 0 steps $ computeS $ linspace (steps + 1) (0, 2*pi)
--xs
fs :: Vec Double
fs = computeS $ Repa.map (\x -> sin (15*x)) xs
--fs
dfs :: Vec Double
dfs = computeS $ Repa.map (\x -> 15*cos (15*x)) xs
--dfs
```
%% Cell type:code id: tags:
``` haskell
h = 2*pi/(steps+1)
--h
--periodicCentralDiff h fs
```
%% Cell type:code id: tags:
``` haskell
computeS $ Repa.map (\x -> sin (x*2)) (vec [0,1,3.14,6.28]) :: Vec Double
```
%% Cell type:code id: tags:
``` haskell
normInf :: Vec Double -> Double normInf :: Vec Double -> Double
normInf = maximum . map abs . toList normInf = maximum . map abs . toList
errs :: Int -> Double -> [Double] -- create vals x and step size h
errs steps variance = map (err . makeNoise) [0..] coords :: Int -> (Vec Double, Double)
where coords steps = (xs,h)
xs :: Vec Double -- all x locations where
xs = subVector 0 steps $ computeS $ linspace (steps + 1) (0, 2*pi) xs = subVector 0 steps $ computeS $ linspace (steps + 1) (0, 2*pi)
f :: Vec Double -- f at all x locations h = xs!(ix1 1) - xs!(ix1 0)
f = computeS $ Repa.map (\x -> sin (15*x)) xs
f'exact :: Vec Double -- exact derivative at the locations err :: Int -> Double -> Seed -> Double -- one norm error for one seed
f'exact = computeS $ Repa.map (\x -> 15*cos (15*x)) xs err steps variance seed = sqrt h * normInf (computeS (fdt -^ fdn))
h :: Double -- the step size where
h = xs!(ix1 1) - xs!(ix1 0) (xs,h) = coords steps
makeNoise :: Seed -> Vec Double -- generate noise for a given seed ft = computeS $ Repa.map (\x -> sin (15*x)) xs :: Vec Double