cs1101s 2425s1 Final Solutions
cs1101s 2425s1 Final Solutions
SOLUTIONS
INSTRUCTIONS
3. Use a pen or pencil to write your Student Number in the designated space on the front
page of the ANSWER SHEET, and shade the corresponding circle completely in the grid
for each digit or letter. DO NOT WRITE YOUR NAME!
4. You must submit only the ANSWER SHEET and no other documents. Do not tear off any
pages from the ANSWER SHEET.
5. All questions must be answered in the space provided in the ANSWER SHEET; no extra
sheets will be accepted as answers.
6. Write legibly with a pen or pencil (do not use red color). Untidiness will be penalized.
7. For multiple choice questions (MCQ), shade in the circle of the correct answer
completely.
9. This is a Closed-Book assessment, but you are allowed to bring with you one double-sided
A4 / letter-sized sheet of handwritten or printed notes.
10. Where programs are required, write them in the Source §4 language. A reference of some
of the pre-declared functions is given in the Appendix of the Question Paper.
11. In any question, unless it is specifically allowed, your answer must not use functions given
in, or written by you for, other questions.
CS1101S
A. Θ(1) E. Θ(n 3 )
B. Θ(log n) F. Θ(n log n)
C. Θ(n) (answer) G. Θ(2n )
D. Θ(n 2) H. Θ(n1/2 )
A. Θ(1) E. Θ(n 3 )
B. Θ(log n) F. Θ(n log n)
C. Θ(n) G. Θ(2n ) (answer)
D. Θ(n 2) H. Θ(n1/2 )
A. Θ(1) E. Θ(n 3 )
B. Θ(log n) F. Θ(n log n)
C. Θ(n) G. Θ(2n )
D. Θ(n 2) (answer) H. Θ(n1/2 )
—— Page 2 of 24 ——
CS1101S
—— Page 3 of 24 ——
CS1101S
? is_prefix(tail(xs), tail(ys))
: false ;
—— Page 4 of 24 ——
CS1101S
A. An iterative process
B. A recursive process (answer)
C. Not enough information to determine.
—— Page 5 of 24 ——
CS1101S
(8) [2 marks]
Implement the function logging_function that takes a unary function fn and a string log, and
returns a new logging function. This new function, when called with an argument, should return a
pair whose head is the result of applying fn to the argument and the tail is the log string. For
example,
const add_one = logging_function(x => x + 1, "+1");
const multiply_two = logging_function(x => 2 * x, "*2");
add_one(1); // returns [2, "+1"]
multiply_two(2); // returns [4, "*2"]
(9) [5 marks]
Implement the function compose that takes two unary “logging functions” (as in the above question)
fn1 and fn2, and returns a new function. This new function, when called with an argument x, should
return a pair whose head is the result of applying fn2(fn1(x)) and the tail is a concatenated
string of the logs from both functions.
For example,
const f1 = compose(add_one, add_one);
f1(1); // returns [3, "+1+1"]
const f2 = compose(add_one, multiply_two);
f2(1); // returns [4, "+1*2"]
const f3 = compose(f2, multiply_two);
f3(1); // returns [8, "+1*2*2"]
const a = fn1(x);
const b = fn2(head(a));
}
return wrapper;
}
—— Page 6 of 24 ——
CS1101S
I.
PS5
PS5
II.
PS5
PS5 PS5
PS5
—— Page 7 of 24 ——
CS1101S
You can access binary trees using only the following functions, which provide the binary tree
abstraction:
—— Page 8 of 24 ——
CS1101S
(12) [5 marks]
function count_leaves_at_depths(tree){
const ans = [];
const max_d = max_depth(tree);
if( !is_empty_tree(tree) ){
}
}
help(tree, 0);
return ans;
}
—— Page 9 of 24 ——
CS1101S
(13) [5 marks]
Monotonically Increasing path (MI-path) is defined as a path in a binary tree, starting at the root
node and ending at a leaf node where, every visited node along the path has a value larger than its
parent.
Complete the implementation of longest_mi_path, which takes as arguments a tree and returns
the length of the longest MI-path in the tree. If there are no MI-paths it should return 0.
You can assume the tree only contains positive integers as entries.
function longest_mi_path(t){
return 0;
} else {
if (entry(t) > p) {
const ans1 = 1 + help(left_branch(t), entry(t));
const ans2 = 1 + help(right_branch(t), entry(t));
return math_max(ans1, ans2);
} else {
return 0;
}
}
}
—— Page 10 of 24 ——
CS1101S
(14) [5 marks]
Complete the declaration of the function sort_descending, which takes as argument an array of
numbers, and sorts the array elements in descending order. For example,
const AA = [3, 9, 2, -5, 1, 6, 5, -2, 3, 8];
sort_descending(AA);
AA; // evaluates to [9, 8, 6, 5, 3, 3, 2, 1, -2, -5]
Your answer must consist of at most three statements, and each statement must be an application of
the function map_array or sort_ascending. Write each statement in one of the three dashed-line
boxes.
function sort_descending(A) {
sort_ascending(A);
—— Page 11 of 24 ——
CS1101S
(15) [5 marks]
Complete the declaration of the function reverse_array, which takes as argument an array of
numbers, where every number x is 0 ≤ x < 1000, and arranges the array elements in reverse order.
For example,
const AA = [3, 9, 2, 1, 6, 5, 3, 8];
reverse_array(AA);
AA; // evaluates to [8, 3, 5, 6, 1, 2, 9, 3]
Your answer must consist of at most three statements, and each statement must be an application of
the function map_array, sort_ascending, or the function sort_descending from the
preceding question. Write each statement in one of the three dashed-line boxes.
function reverse_array(A) {
sort_descending(A);
—— Page 12 of 24 ——
CS1101S
The notion of a tensor generalizes the order of numerical objects. A vector is called a first-order
tensor, and a matrix is a second-order tensor. We assume that multidimensional tensors are
hypercubic: They have a uniform size in every order. A second-order size-5 tensor (matrix) has 5 x
5 = 25 numbers, and a third-order size-4 tensor has 4 x 4 x 4 = 64 numbers. In this question, we
assume that the size of a tensor is always greater than or equal to 1. As a special case, any number is
considered to be a zero-order tensor of any size greater than or equal to 1. We represent tensors using
arrays, whose indices start with 0. Therefore, if T is an order-4 size-3 tensor, T[0][1][2][0] returns a
number.
(16) [5 marks]
Write a function make_tensor that takes a non-negative integer n as first argument and an integer
k greater than or equal to 1 as second argument and returns an order-n size-k tensor whose numbers
are all 0.
Examples:
—— Page 13 of 24 ——
CS1101S
function make_tensor(n, k) {
if (n === 0) {
return 0;
} else {
const t = [];
return t;
}
}
(17) [5 marks]
Write a function tensor_write that takes an order-n size-k tensor t, an array of indices idxs,
and a number v as arguments and writes v to t at the given position indicated by idxs. You can
assume that the size of the array idxs is n and that each element of idxs is a non-negative integer
smaller than k. The function tensor_write should return undefined.
Example:
—— Page 14 of 24 ——
CS1101S
(18) [5 marks]
Write a function tensor_order that takes a tensor as argument and returns its order.
Examples:
display(tensor_order(44)); // displays 0
display(tensor_order([6, 5, 4, 3])); // displays 1
display(tensor_order([[1,1], [2,2]]); // displays 2
display(tensor_order(t2)); // displays 4, if t2 as above
function tensor_order(t) {
return is_number(t)
? 0
: tensor_order(t[0]) + 1;
—— Page 15 of 24 ——
CS1101S
(19) [5 marks]
Write a function tensor_add that takes as arguments two tensors t1 and t2 of the same order and
size and returns a tensor of the same order and size in which the numbers in each position are the
results of adding the numbers of t1 and t2 at the same position. The function tensor_add must
not modify the two argument tensors.
Example:
return t1 + t2;
} else {
const t3 = [];
}
}
—— Page 16 of 24 ——
CS1101S
—— Page 17 of 24 ——
CS1101S
A. 1 2 3 2 3 2 3
B. 1 2 3 2 3 2 3 2 3 (answer)
C. 1 2 3 2 3 1 2 3 2 3
D. 1 2 3 1 2 3 1 2 3
E. 1 2 3 1 2 3 1 2 3 1 2 3
F. 1 2 3 2 3 1 2 3
G. 1 2 3 1 2 3
A. 1 2 3 3 3 3 (answer)
B. 1 2 3 3
C. 1 2 3 3 1
D. 1 2 3 3 1 2 3 3
—— Page 18 of 24 ——
CS1101S
E. 1 2 3 3 1 2 3 1 2 3 1
F. 1 2 3
G. 1 2 3 1 2 3
—— Page 19 of 24 ——
CS1101S
—— Page 20 of 24 ——
CS1101S
The CSE machine includes env instructions to handle environments in function calls. During the
execution of call instructions, env instructions are placed on the control so that the environment
at the time of the function call is restored when the function returns.
You saw in the lectures that proper tail calls in JavaScript do not create env instructions because
the environment at the time of the function call is not needed after the function returns.
Another case when env instructions are not necessary is when the environment to be used for
evaluating the function body is the same as the environment at the time of the function call.
Consider this example:
The application of ones_stream in line 2 creates the env instruction in the control, shown here
just before it is executed.
The environment that was used for evaluating the body of ones_stream is the same as the
environment that the env instruction is about to restore. The env instruction therefore does
nothing: It is unnecessary.
(25) [5 marks]
Modify the CSE machine for simple functions to avoid the creation of unnecessary data structures
when the environment to be used for evaluating the function body is the same as the environment at
the time of the function call. Only change the program by filling the indicated boxes. Do not make
any other modifications. Your modification must not change the result of evaluating any given
Source program.
—— Page 21 of 24 ——
CS1101S
function evaluate(program) {
let C = list(make_block(program));
let S = null; E = the_global_environment;
while (! is_null(C)) {
const command = head(C);
C = tail(C);
if (…) { …
} … else if (is_call_instruction(command)) {
const arity = call_instruction_arity(command);
let args = null; let n = arity;
while (n > 0) {
args = pair(head(S), args);
S = tail(S); n = n - 1;
}
const fun = head(S);
S = tail(S);
if (is_primitive_function(fun)) {
S = pair(apply_primitive_function(fun, args),
S);
} else if (is_simple_function(fun)) {
if (
<condition>
) {
<block>
} else {
C = pair(function_body(fun),
pair(make_env_instruction(E),
C));
E = extend_environment(
function_parameters(fun),
args,
function_environment(fun));
}
} else { error(fun, "unknown function type -- call"); }
…
Implementation of the function extend_environment is available in the appendix for your
reference.
Write the appropriate condition and block to complete the implementation.
<condition>
arity === 0 &&
function_environment(fun) === E
<block>
C = pair(function_body(fun), C);
—— Page 22 of 24 ——
CS1101S
Appendix
We assume the following pre-declared functions in Source §4 are declared as follows:
function stream_map(f, s) {
return is_null(s)
? null
: pair(f(head(s)), () => stream_map(f, stream_tail(s)));
}
function stream_filter(p, s) {
return is_null(s)
? null
: p(head(s))
? pair(head(s), () => stream_filter(p, stream_tail(s)))
: stream_filter(p, stream_tail(s));
}
function stream_ref(s, n) {
return n === 0
? head(s)
: stream_ref(stream_tail(s), n - 1);
}
—— Page 23 of 24 ——
CS1101S
function eval_stream(s, n) {
return n === 0
? null
: pair(head(s), eval_stream(stream_tail(s), n - 1));
}
function integers_from(n) {
return pair(n, () => integers_from(n + 1));
}
—— Page 24 of 24 ——