4. Working with matrices and images using higher-order functions
1. Introduction
We shall represent matrices as lists of lists, i.e. values of type [ [Integer ] ]
. Each element in the outer list represents a line of the matrix.
Hence, the matrix
$ \displaystyle \left(\begin{array}{ccc} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \\ \end{array}\right)$
will be represented by the list [ [1,2,3],[4,5,6],[7,8,9] ]
.
To make signatures more legible, add the type alias to your code:
type Matrix = [[Integer]]
which makes the type-name Matrix
stand for [ [Integer] ]
.
1.1. Write a function parsem
which takes a string and parses it to a Matrix
. In the string, the columns are separated by whitespace and lines - by '\n'.
- (Hint: You need to perform two types of very similar splitting operations: one into lines, and another into column values, for each line)
parsem :: String -> Matrix parsem =
1.2. Write a function that converts a matrix to a string encoded as illustrated in the previous exercise.
- (Hint: use folds)
- (Hint: test the function
show
on several different values) - (Hint: first make a function to display one line)
toString:: Matrix -> String toString=
1.3. Add the following to your code. Test the function displayMatrix
.
displayMatrix = putStrLn . toString
2. Matrix operations
2.1. Write a function that computes the scalar product with an integer:
$ \displaystyle 2 * \left(\begin{array}{ccc} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \\ \end{array}\right) = \left(\begin{array}{ccc} 2 & 4 & 6 \\ 8 & 10 & 12 \\ 14 & 16 & 18 \\ \end{array}\right)$
vprod :: Integer -> Matrix -> Matrix vprod v =
2.2. Write a function which adjoins two matrices by extending rows:
$ \displaystyle \left(\begin{array}{cc} 1 & 2 \\ 3 & 4\\\end{array}\right) hjoin \left(\begin{array}{cc} 5 & 6 \\ 7 & 8\\\end{array}\right) = \left(\begin{array}{cc} 1 & 2 & 5 & 6 \\ 3 & 4 & 7 & 8\\\end{array}\right) $
hjoin :: Matrix -> Matrix -> Matrix hjoin =
2.3. Write a function which adjoins two matrices by adding new rows:
$ \displaystyle \left(\begin{array}{cc} 1 & 2 \\ 3 & 4\\\end{array}\right) vjoin \left(\begin{array}{cc} 5 & 6 \\ 7 & 8\\\end{array}\right) = \left(\begin{array}{cc} 1 & 2 \\ 3 & 4 \\ 5 & 6\\ 7 & 8\\ \end{array}\right) $
vjoin :: Matrix -> Matrix -> Matrix vjoin =
2.4. Write a function which adds two matrices.
msum :: Matrix -> Matrix -> Matrix msum =
2.5. Write a function which computes the transposition of a matrix:
$ tr \left(\begin{array}{ccc} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \\ \end{array}\right) = \left(\begin{array}{ccc} 1 & 4 & 7 \\ 2 & 5 & 8 \\ 3 & 6 & 9 \\ \end{array}\right) $
tr :: [[a]] -> [[a]] tr ([]:_) = tr m =
2.6. Write a function which computes the vectorial product of two matrices.
- (Hint: start by writing a function which computes $ a_{ij}$ for a given line $ i$ and column $ j$ (both represented as lists))
- (Hint: write a function which takes a line of matrix m1 and the matrix m2 and computes the respective line from the product)
mprod :: Matrix -> Matrix -> Matrix mprod m1 m2 =
3. Image operations
We can represent images as matrices of pixels. In our example a pixel will be represented as a Char
, which can take the values: '*' (signifying that the respective pixel is on) and ' ' (the pixel is off).
type Image = [String]
For instance, a rectangle could be represented as:
******** * * ********
more precisely, as the string:
"********\n* *\n********\n"
3.1. Implement an image-displaying function. Use the image from the Appendix as a test.
toStringImg :: Image -> String toStringImg =
Add the following function in order to view images in a nicer format:
displayImg = putStrLn . toStringImg
3.2. Implement a function which flips an image horizontally:
flipH :: Image -> Image flipH =
3.3. Implement a function which flips an image vertically:
flipV :: Image -> Image flipV =
3.4. Implement a function which rotates an image 90grd clockwise
rotate90r :: Image -> Image rotate90r =
3.5. Implement a function which rotates an image -90grd clockwise
rotate90l :: Image -> Image rotate90l =
3.6. Implement a function which inverts an image: ' ' becomes * and * becomes ' ':
invert :: Image -> Image invert =
3.7. Implement a function maskKeep
which takes a mask and some image and only keeps the part of image which overlays the mask. Use the mask and the logo from Appendix to test it.
maskKeep :: Image -> Image -> Image maskKeep =
$ maskKeep \left(\begin{array}{ccc} & & * \\ & & * \\ & & * \\ \end{array}\right) \left(\begin{array}{ccc} * & & * \\ * & & \\ * & & * \\ \end{array}\right) = \left(\begin{array}{ccc} & & * \\ & & \\ & & * \\ \end{array}\right) $
3.8. Implement a function maskDiscard
which takes a mask and some image and discards the part of the mask which overlays the image.
$ maskDiscard\left(\begin{array}{ccc} & & * \\ & & * \\ & & * \\ \end{array}\right) \left(\begin{array}{ccc} * & & * \\ * & & \\ * & & * \\ \end{array}\right) = \left(\begin{array}{ccc} & & \\ & & * \\ & & \\ \end{array}\right) $
3.9. Implement the union
' of two images.
union' :: Image -> Image -> Image union' =
$ union \left(\begin{array}{ccc} & & * \\ & & * \\ & & * \\ \end{array}\right) \left(\begin{array}{ccc} * & & * \\ * & & \\ * & & * \\ \end{array}\right) = \left(\begin{array}{ccc} * & & * \\ * & & * \\ * & & * \\ \end{array}\right) $
3.10. Implement a function which takes a list of transformation and an image and applies all those transformations.
transformationSequence :: [Image -> Image] -> Image -> Image
Test it with the following sequence
seq1 = transformationSequence [invert, union' mask, rotate90r]
4. More matrices
4.1. Implement a function which places zeros above the diagonal of a square matrix. Use folds.
4.2. Implement a function which places zeros below the diagonal of a square matrix. Use folds.
4.3. Implement either of 4.1 or 4.2 using the function(s) take
and drop
. Check the types of these and test them.
4.4. Implement a function which computes the diagonal matrix of a square matrix.
4.5. Implement a function which computes recursively the determinant of a matrix. What additional functions would be necessary?
Appendix
logo = [l1,l2,l3,l4,l5,l6,l7,l8,l9,l10,l11,l12,l13,l14,l15,l16,l17,l18,l19] where l1 =" ***** ** ***** ** " l2 =" ****** **** ****** **** " l3 =" ** * * *** ** * * *** " l4 =" * * * *** * * * *** " l5 =" * * ** * * ** " l6 =" ** ** ** ** ** ** " l7 =" ** ** ** ** ** ** " l8 =" **** ** * **** ** * " l9 =" * *** ** * * *** ** * " l10=" ** ******* ** ******* " l11=" ** ****** ** ****** " l12=" ** ** ** ** " l13=" ** ** ** ** " l14=" ** ** ** ** " l15=" ** ** ** ** ** ** " l16="*** * * *** * * " l17=" *** * *** * " l18=" ****** ****** " l19=" *** *** "
mask = [l1,l2,l3,l4,l5,l6,l7,l8,l9,l10,l11,l12,l13,l14,l15,l16,l17,l18,l19] where l1 =" *****************" l2 =" *****************" l3 =" *****************" l4 =" *****************" l5 =" *****************" l6 =" *****************" l7 =" *****************" l8 =" *****************" l9 =" *****************" l10=" *****************" l11=" *****************" l12=" *****************" l13=" *****************" l14=" *****************" l15=" *****************" l16=" *****************" l17=" *****************" l18=" *****************" l19=" *****************"