Department of Statistics

STATS 782 Statistical Computing

Assignment 4(2020.FC)

Total: 50 marks Due: 2:00 pm NZST, Friday 12 June 2020

1. Please read these instructions carefully. Further instructions might be posted on the class

webpage.

2. Upload your soft copy (assignment source) to Canvas: the file should end in .Rmd, or possibly

.R or .Rnw. The marker may run or knit your R code, so include your name and ID in all

files. The file names should contain your UPI. RMarkdown is strongly recommended.

3. Also upload your .pdf to Canvas too. Note the time difference between countries.

4. Coversheet: please make sure you do one of the following else your assignment will not be

marked:

(a) Sign the Cover Sheet and combine with your assignment document (pdf or Word) into

a single file before submission, OR

(b) Type or write for the following at the beginning of your assignment: Your name (as it

appears in Canvas), your UPI, and the following statement: “I have read the declaration

on the cover sheet and confirm my agreement with it.”

5. Include everything in your report: R code (tidied up), outputs (including error/warning mes-

sages), and your explanations (if any). Please comment on almost all of your output, espe-

cially parts that need human interpretation, else marks will be deducted. That is, you need

to convince the marker that you understand what the data or solution is saying.

6. Print some intermediate results to show how your code works step by step, if not obvious.

Comment your code if appropriate, e.g., for functions, blocks of code, and key variables.

7. Type help.start() when you open R. You need to use the online help to find details and

functions that may not be covered directly in the coursebook. This requires maturity; we

cannot cover everything in class or the coursebook.

8. Your mark for this assignment will depend on getting the right answer, the elegance/efficiency

of your approach, and the tidiness and documentation of your code/report. The R Tidyverse

Style Guide or R Google Style Guide is recommended. Marks (up to 7) will be deducted

for messy code, etc.

9. This PDF file may contain colour that is important to see.

1. [23 marks] Let us create a class "points2d" using the S3 object system representing a

set of points by Cartesian coordinates in two-dimensional Euclidean space. The representation

will be a named list with two numeric vectors, x and y of the same length.

(a) Define a constructor points2d(x, y) creating an object of the above class "points2d".

Make sure the returned object is valid. Allow for the zero-length constructor points2d().

[2 marks]

(b) Create a print() method printing the points as a two-dimensional matrix with columns

"x" and "y" and a length() method returning the number of points. [2 marks]

Test it as follows:

> a <- points2d(c(0, 1, -2), c(1, -1, -1))

> a

x y

[1,] 0 1

[2,] 1 -1

[3,] -2 -1

> length(a)

[1] 3

(c) Arithmetics. Let us define arithmetics as follows: multiplication and division is only

allowed with scalar number λ and corresponds to scaling λ(xi, yi)→ (λxi, λyi). Addition

and subtraction is only allowed between points and is implemented as the corresponding

vector operation on each coordinate (xi, yi) + (ai, bi)→ (xi + ai, yi + bi) with standard R

recycling rules. [4 marks]

Test with following expressions:

> (a3 <- 3 * a)

x y

[1,] 0 3

[2,] 3 -3

[3,] -6 -3

> a / 2

x y

[1,] 0.0 0.5

[2,] 0.5 -0.5

[3,] -1.0 -0.5

> -a

x y

[1,] 0 -1

[2,] -1 1

[3,] 2 1

> a3 - a

x y

[1,] 0 2

[2,] 2 -2

[3,] -4 -2

> a3 - a - 2 * a

x y

[1,] 0 0

[2,] 0 0

[3,] 0 0

(d) Coercion. Our points2d objects can be directly represented as numeric matrices with

two columns. Write a method as.matrix() which coerces point2d object to such a

matrix. Then write a new generic as.points2d(x) and implement it both for point2d

and matrix classes. Note that all point2d objects can be represented as matrices (so

as.point2d(as.matrix(x)) is an indentity for valid point2d objects x) but not vice-

versa. Make sure you raise errors when appropriate. [3 marks]

(e) Define accessor generics getx(o), gety(o) to retrieve each coordinate vector and the

corresponding methods for point2d. Define a method for the combine generic c(...)

such that it concatenates multiple point2d objects into one. [3 marks]

Test it with print(b <- c(a, a3, a3 - 2 * a)).

2

(f) Define a method unique() for point2d such that it removes any duplicate points. [3 marks]

Test it with

> unique(b)

x y

[1,] 0 1

[2,] 1 -1

[3,] -2 -1

[4,] 0 3

[5,] 3 -3

[6,] -6 -3

(g) Create a generic rotate(x, phi) which rotates the points x around the origin by phi

degrees counter-clockwise. Implement the method for points2d. A rotation can be written

in matrix form as

Rot(φ) =

[

cosφ − sinφ

sinφ cosφ

]

(1)

with Rot(φ)

[

x

y

]

yielding the rotated vector. [3 marks]

(h) Make sure the following code runs and produces the correct result as shown in Figure 1.

Define any missing generics or methods if needed. [3 marks]

> plot(a3, col=2, pch=19)

> abline(h=0, v=0, lty=3)

> polygon(a * 2, col=grey(0.8))

> polygon(a, col=grey(0.7))

> b <- a - points2d(4, 2)

> polygon(b, col=grey(0.9))

> l <- points2d()

> for (phi in seq(0, 360, 15))

l <- c(l, rotate(a, phi))

> points(unique(l), col=4, pch=19)

> lines(rotate(b, -45), col=2, lwd=2)

3

−6 −4 −2 0 2

−

4

−

2

0

2

4

x

y

Figure 1:

4

2. [27 marks] Let us create a class "pts2d" using the S4 object system representing a set of

points by Cartesian coordinates in two-dimensional Euclidean space. The representation will

consist of two numeric vectors x and y of the same length, so the idea is the same as in the

first question, but this time we will use the S4 class system.

(a) Declare the class "pts2d", write a constructor pts2d(x, y), also allowing for pts2d().

Write methods for length() and show(). [3 marks]

Test with

> (a <- pts2d(c(0, 1, -2), c(1, -1, -1)))

x y

1 0 1

2 1 -1

3 -2 -1

> length(a)

[1] 3

(b) Arithmetics. Define arithmetics for the class pts2d to behave in the same way as in 1(c).

Use the same tests to validate. [4 marks]

(c) Coercion. Define corresponding coercion methods such that as(a, "matrix") and as(m,

"pts2d") work (for suitable m). For compatibility, ensure that as.matrix(a) yields the

same result as as(a, "matrix"). [2 marks]

(d) Implement the accessors getx(), gety(), methods for subsetting ‘[‘ and combination

c(). [3 marks]

(e) Define a subclass graph2d representing a directed graph based on pts2d which adds two

slots i and j, both integer vectors of the same length defining edges between the points.

For example, i=1L, j=2L defines an edge from the first to the second point. Edges from a

point to itself are not permitted.

Define a constructor graph2d(x, y, i, j) which ensures that the inputs are valid. Allow

for graph2d() and graph2d(pts2d(...)). Define the show method to also print the edge

index pairs. [3 marks]

Test with

> graph2d(a)

Points:

x y

1 0 1

2 1 -1

3 -2 -1

Edges:

[1] i j

<0 rows> (or 0-length row.names)

> (g <- graph2d(a, i=1:3, j=c(3L, 1:2)))

Points:

x y

1 0 1

2 1 -1

3 -2 -1

Edges:

i j

1 3

2 1

3 2

(f) Arithmetics. Ensure that arithmetic operations from (b) are still working for objects of

our subclass. Scaling with scalars and shifts by pts2d should produce valid graph2d

objects since neither affects the edges. Binary + and - operations for two graph2d objects

should not be allowed. [3 marks]

5

Test with:

> 2 * g

> a + g / 2

> -g

> g + g

> g - as(g, "pts2d")

(g) Define the subset ‘[‘ method. The resulting graph consists of the subset of points as

obtained from the corresponding method for pts2d and edges between those points. Any

edges that pointed to or from points that are not in the result set should be removed.

Raise errors on any subsetting that creates ambiguity or missing points. [4 marks]

Test with

> g[-1]

Points:

x y

1 1 -1

2 -2 -1

Edges:

i j

2 1

(h) Define the combine c() method. The result should contain all points and edges of the

arguments. You don’t need to guarantee uniqueness of the points, (i.e., you don’t have to

fuse separate graphs that include the same points). [3 marks]

Test with

> c(g, g*2)

Points:

x y

1 0 1

2 1 -1

3 -2 -1

4 0 2

5 2 -2

6 -4 -2

Edges:

i j

1 3

2 1

3 2

4 6

5 4

6 5

> c(g, g*2)[2:5]

Points:

x y

1 1 -1

2 -2 -1

3 0 2

4 2 -2

Edges:

i j

2 1

4 3

> c(g[-1], g/2)[2:4]

Points:

x y

1 -2.0 -1.0

2 0.0 0.5

3 0.5 -0.5

Edges:

i j

3 2

(i) Define a plot method that works for the class graph2d which draws the points and arrows

for edges. [2 marks]

Test with:

> plot(c(g, a + g))

6

−4 −3 −2 −1 0 1 2

−

2

−

1

0

1

2

x

y

> plot(c(g, g*2, -g, (g * 3)[2:3]), pch=19, col=2, cex=1.5)

−6 −4 −2 0 2

−

4

−

2

0

2

x

y

7