CS1010S — Programming Methodology School of Computing National University of Singapore Midterm Test Time allowed: 1 hour 30 Sep 2020 Instructions (please read carefully): 1. This is a CLOSED book assessment, but you are allowed to bring ONE double-sided A4 sheet of notes for this assessment. 2. The assessment paper contains FOUR (4) questions and comprises EIGHT (8) pages including this cover page. 3. The time allowed for solving this test is 1 hour. 4. Weightage of each question is given in square brackets. The maximum attainable score is 50. 5. Enter all your answers in the correct space provided on Examplify. No other mode of submission will be accepted. 6. Use of physical calculators are not allowed in the test. You may however use the on-screen calculator in Examplify. 7. Marks may be deducted for i) unrecognisable handwriting, and/or ii) excessively long code. A general guide would be not more than twice the length of our model answers. GOOD LUCK! CS1010S Midterm Test — 30 Sep 2020 Question 1: Python Expressions [15 marks] There are several parts to this problem. Answer each part independently and separately. In each part, one or more Python expressions are entered into the interpreter (Python shell). Determine the printed output and write the exact output in the answer box. If the interpreter produces an error message, or enters an infinite loop, explain why and clearly state the responsible evaluation step. A. a = 1 b = 2 def fib(a): print(b) def fab(b): print(b - a) fab(b - a) print(b) print(fib(b)) [5 marks] B. a = (1, (2, (3,))) b = (4, 5) if 1 in a: print(2) if 3 == a[1][1]: print(4) elif 5 == b[-1]: b += 6 else: print(7) print(b) [5 marks] C. d = 4 while d >= 0: print(d) if d % 2 == 1: d = d - 1 print("c") continue if d % 3 == 0: print("b") break d = d // 2 [5 marks] 2 CS1010S Midterm Test — 30 Sep 2020 Question 2: Zombie Island Apocalypse [14 marks] Just when you thought that the world was recovering from COVID-19, a new zombie apocalypse has broken out on a desert island. You have been asked to model the outcome of the outbreak with your newfound skills in Pythonfu. The outbreak starts on day 0 with one infected person (zombie). The rate of the zombie infection is modelled by a parameter r0 . On each new day, the zombies will infect an additional r0 × the existing zombie population, rounded up (you can use the python function ceil() ). For example, with r0 = 0.5, the sequence of zombie population is 1, 2, 3, 5, 8, 12, 18, 27, 41, 62, 93, · · · with r0 = 1, the sequence of zombie population is 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, · · · with r0 = 2, the sequence of zombie population is 1, 3, 9, 27, 81, 243, 729, 2187, 6561, 19683, · · · The function infected(r0, j, k) takes three inputs: r0 the parameter described above, and non-negative integers j and k. It returns a tuple, representing the sequence of zombie population of the outbreak from day j to day k inclusive, i.e., a slice of the complete sequence. If j > k, infected will return an empty tuple. Sample execution: >>> infected(0.5, 0, 10) (1, 2, 3, 5, 8, 12, 18, 27, 41, 62, 93) >>> infected(1, 5, (32, 64, 128, 256, >>> infected(2, 3, (27, 81, 243, 729, 10) 512, 1024) 7) 2187) A. Provide a recursive implementation of infected . Partial marks may be given for incom- plete solution, e.g., returning the complete sequence instead of the slice. [5 marks] B. What is the order of growth in time and in space for the function you wrote in Part A? Briefly explain your answer. [2 marks] C. Provide an iterative implementation of infected . Partial marks may be given for incomplete solution, e.g., returning the complete sequence instead of the slice. [5 marks] D. What is the order of growth in time and in space for the function you wrote in Part C? Briefly explain your answer. [2 marks] 3 CS1010S Midterm Test — 30 Sep 2020 Question 3: Higher-Order Zombies [4 marks] A. [HARD] Consider the higher-order function fold which was taught in class. def fold(op, f, n): if n == 0: return f(0) else: return op(f(n), fold(op, f, n-1)) The function infected defined in Question 2 can be defined in terms of fold , by first obtaining the entire sequence and then slicing the tuple to the required section: def infected(r0, j, k): <PRE> return fold(<T1>, <T2>, <T3>)[j:] Please provide possible implementations for the terms T1, T2, and T3. You may optionally define other functions in PRE if needed. Note: You are to use the higher-order function and not solve it recursively or iteratively or use a formula. [4 marks] 4 CS1010S Midterm Test — 30 Sep 2020 Question 4: Hotel Reservations [17 marks] INSTRUCTIONS: Please read the entire question clearly before you attempt this problem!! You are also not to use any Python data types which have not yet been taught in class. Breaking News [OK to skip] The Singapore Tourism Board (STB) said on Wednesday (Sep 16) that every Singapore citizen aged 18 and above this year will soon receive S$100 worth of SingapoRediscovers vouchers, which can be used on staycations, attraction tickets and tours. The vouchers are expected to support the local tourism business, which has been badly hit by the COVID-19 pandemic and border restrictions. Source: CNA You have been hired by The Waffles Hotel to help develop a new software booking system to deal with the expected surge in hotel reservations as dutiful Singaporeans do their part to stimulate the local economy by taking government-paid staycations to work from hotel. Your first task is to design a booking data type to capture a room booking. A guest makes a booking by stating the size of the room required, and the check-in and check-out dates. To simplify the handling of dates, the hotel’s existing system automatically converts dates into days since the hotel’s founding, i.e., dates are simply running integers. Though guests will specify a check-out day in their booking, it should not be counted in the reservation system as hotels are only interested in the nights that are stayed. For example, a guest who checks-in on day 20 and checks-out on day 22 is considered to be staying on day 20 and 21. The booking data type should be supported by the following functions: • make_booking(room_size, check_in, check_out) takes in a room size (which is the number of guests in the room), and the check-in and check-out day. • size_of(booking) takes in a booking, and returns the size of the room that is booked. • booked_days(booking) takes in an booking, and returns a tuple containing the days that the room is being booked. Sample Execution: >>> booking = make_booking(2, 27, 30) >>> size_of(booking) 2 >>> booked_days(booking) (27, 28, 29) A. Decide on a data structure using tuples to represent a booking, and implement the functions make_booking , size_of and booked_days . 5 [3 marks] CS1010S Midterm Test — 30 Sep 2020 [Important!] For the remaining parts of this question, you should not break the abstraction of a booking in your code. A sample execution is given on the next page for reference. B. The hotel will need to keep track of all the bookings made, using a reservation schedule. Decide on a data structure using tuples to represent a reservation schedule and support it with the following functions: • make_empty_reservations() takes no inputs and returns an empty reservation schedule. • add_booking(booking, reservations) takes in a booking and the existing reservation schedule, and returns a new reservation schedule with the booking added to it. [2 marks] C. The hotel staff needs to know what are the current bookings for a given room size, for a particular day. Implement the function current_bookings(reservations, room_size, day) that takes in the reservation schedule, the room size and the day, and returns a tuple of bookings that fulfils the criteria. [4 marks] D. The hotel of course has a limited number of rooms, which is denoted using a tuple, where the index of the elements denote the room size and the value denotes the number of rooms it has. For example, a hotel with 10 single rooms (for one person), 30 double rooms (for two persons) and 5 quad rooms (for 4 persons) who have its capacity represented as a tuple (0, 10, 30, 0, 5) . Assume a global variable hotel_capacity defines the Waffles Hotel capacity. The function can_accept(booking, reservations) takes in the current reservation schedule, and a new booking, and returns True if the hotel has an available room, of the matching size, to service the entire booking, and False if there is one day that the hotel has no rooms, of the matching size, available for the booking. Note that the same room does not have to be used for the entire booking. We force our guest to change rooms if needed. Provide an implementation for the function can_accept . [4 marks] E. Now if a booking was rejected because there are no available rooms of the given size, the hotel might have a larger room that can accommodate the booking if the guest is willing to upgrade. For example, a guest requesting a single room can be put into a quad room if there are no single or double rooms available. But a booking cannot be “downgraded”, i.e. into smaller rooms from what was requested. Implement the function accept_upgrade(booking, reservations) that takes in the same inputs as can_accept , and returns a booking with the next available room size if one is available, and False if the hotel is completely unable to service the booking. [4 marks] 6 CS1010S Midterm Test — 30 Sep 2020 Sample execution: >>> hotel_capacity = (0, 1, 1) # hotel only has 1 single and 1 double room >>> b1 = make_booking(1, 0, 2) >>> b2 = make_booking(1, 1, 3) >>> b3 = make_booking(2, 2, 3) # check-in day 0, check-out day 2 >>> schedule = make_empty_reservations() >>> can_accept(b1, schedule) True >>> schedule = add_booking(b1, schedule) >>> b1 in current_bookings(schedule, 1, 0) True >>> b1 in current_bookings(schedule, 1, 2) False >>> can_accept(b2, schedule) False >>> can_accept(b3, schedule) True # b1 is booked on day 0 # b1 is not booked on day 2 # single room is booked on day 1 # double room is available >>> accept_upgrade(b2, schedule) != False True # upgrade to double room is available >>> accept_upgrade(b3, schedule) != False True # double room available >>> b2 = accept_upgrade(b2, schedule) >>> schedule = add_booking(b2, schedule) # booking is upgraded # double room booked day 1 to day 2 >>> accept_upgrade(b3, schedule) False — END OF # only single room available on day 2 QUESTIONS — 7 CS1010S Midterm Test — 30 Sep 2020 Appendix The following are some functions that were introduced in class. For your reference, they are reproduced here. def sum(term, a, next, b): if a > b: return 0 else: return term(a) + sum(term, next(a), next, b) def product(term, a, next, b): if a > b: return 1 else: return term(a) * product(term, next(a), next, b) def fold(op, f, n): if n == 0: return f(0) else: return op(f(n), fold(op, f, n-1)) def enumerate_interval(low, high): return tuple(range(low,high+1)) def map(fn, seq): if seq == (): return () else: return (fn(seq[0]),) + map(fn, seq[1:]) def filter(pred, seq): if seq == (): return () elif pred(seq[0]): return (seq[0],) + filter(pred, seq[1:]) else: return filter(pred, seq[1:]) def accumulate(fn, initial, seq): if seq == (): return initial else: return fn(seq[0], accumulate(fn, initial, seq[1:])) — END OF 8 PAPER — CS1010S — Programming Methodology School of Computing National University of Singapore Midterm Test — Answer Sheet Time allowed: 1 hour 30 Sep 2020 Student No: S O L U T I O N S Instructions (please read carefully): 1. Write down your student number on this answer sheet. DO NOT WRITE YOUR NAME! 2. This answer sheet comprises NINE (9) pages. 3. All questions must be answered in the space provided; no extra sheets will be accepted as answers. You may use the extra page provided at the back if you need more space for your answers. 4. You must submit only the ANSWER SHEET and no other documents. The question set may be used as scratch paper. 5. An excerpt of the question may be provided to aid you in answering in the correct box. It is not the exact question. You should refer to the original question in the question booklet. 6. You are allowed to use pencils, ball-pens or fountain pens, as you like as long as it is legible (no red color, please). 7. Marks may be deducted for i) unrecognisable handwriting, and/or ii) excessively long code. A general guide would be not more than twice the length of our model answers. GOOD LUCK! For Examiner’s Use Only Question Marks Remarks Q1 / 15 Q2 / 14 Q3 / Q4 / 17 Total / 50 4 Answer Sheet CS1010S Midterm Test — 30 Sep 2020 This page is intentionally left blank. Use it ONLY if you need extra space for your answers, in which case indicate the question number clearly as well as in the original answer box. DO NOT use this for your rough work. 2 Answer Sheet CS1010S Midterm Test — 30 Sep 2020 Question 1A a = 1 b = 2 def fib(a): print(b) def fab(b): print(b - a) fab(b - a) print(b) print(fib(b)) 2 -2 2 None [5 marks] Tests the understanding of scoping and whether students are careful with parameter substitution. Checks if students understand what the difference between print and return. +1 2 +1 -2 +1 2 +1 None +1 Correct order of output Note Additional marks may be deducted if the answer does not demonstrate understanding of scoping, even if some of the output match. Question 1B a = (1, (2, (3,))) b = (4, 5) if 1 in a: print(2) if 3 == a[1][1]: print(4) elif 5 == b[-1]: b += 6 else: print(7) print(b) [5 marks] Tests tuple indexing and concatenation, managing nested tuples, and differences in tuples vs integers. Tests understanding of independence of each if statement. +1 +2 +1 +1 2 State error occurs Does not print more output after error occurs Specifies TypeError or pinpoints error line a += (6) or states cannot add tuple and int Sympathy Marks 2m if printed 2, 4, b . Demonstrates if/elif/else understanding 2m if printed 2, 7, b . Demonstrates if/elif/else understanding 2 TypeError: cannot add tuple and int 3m if printed 2, (4, 5, 6,) . Only mistake is failing to recognize (6) causes an error when added to tuple. 3 Answer Sheet CS1010S Midterm Test — 30 Sep 2020 Question 1C d = 4 while d >= 0: print(d) if d % 2 == 1: d = d - 1 print("c") continue if d % 3 == 0: print("b") break d = d // 2 4 2 1 c 0 b [5 marks] General guidelines: 1 mark for demonstration of understanding how a while-loops works. 2 marks each for correct understanding of continue and break . 5m 4m 3m 2m 1m 1m 0m 4 2 1 c 0 b 4 2 1 c b 4 2 1 c 0 0 ... 4 2 1 c 4 2 1 0 0 ... 4 2 1 States infinite loop without demonstrating 4 2 1 4 Answer Sheet CS1010S Midterm Test — 30 Sep 2020 Question 2A Recursive implementation. [5 marks] def infected(r0, j, k): def helper(k): if k == 0: return (1,) else: return helper(k-1) + (ceil(helper(k-1)[-1] * (1+r0)),) return helper(k)[j:] Question 2B Order of growth for Part A. [2 marks] Time: O(2k ), there are two recursive calls to helper(k-1) for helper(k) , which is a tree recursion with branching factor of 2. O(k2 ), if the result of helper(k-1) is stored in a variable and reused, there is only one recursive call. Thus, there is a total of k recursive calls, with each call creating a tuple of increasing length. Space:O(k2 ), the first recursive call to helper(k-1) will return a tuple of length k. This will be stored in memory as the second call is executed. In the final leg, there will be k recursive calls, with each call stack storing a tuple of decreasing size. O(k), if the result of helper(k-1) is stored in a variable and reused, there is only one recursive call. The tuple returned by each call is immediately replaced by a new tuple. So only space for the final tuple is needed. Question 2C Iterative implementation. [5 marks] def infected(r0, j, k): result = () if j == 0: result = (1,) num = 1 for i in range(1, k + 1): num = ceil(num * (1 + r0)) if j <= i: result += (num,) return result 5 Answer Sheet CS1010S Midterm Test — 30 Sep 2020 Question 2D Order of growth for Part C. [2 marks] Time: O(k2 ), there is a total of k steps in the loop, and each iteration constructs a new tuple of increasing size. Space:O(k), each new tuple created is stored over the previous one, and finally a tuple of k length is created. Question 3A [4 marks] *optional <PRE>: <T1>: lambda a, b: b + (ceil(b[-1] * (1+r0)),) <T2>: lambda a: (1,) <T3>: k Question 4A [3 marks] def make_booking(room_size, start_day, end_day): return (room_size, tuple(range(start_day, end_day))) def size_of(booking): return booking[0] def booked_days(booking): return booking[1] 6 Answer Sheet CS1010S Midterm Test — 30 Sep 2020 Question 4B [2 marks] def make_empty_reservations(): return () def add_booking(booking, reservations): return reservations + (booking,) Question 4C [4 marks] def current_bookings(reservations, room_size, day): bookings = () for booking in reservations: if size_of(booking) == room_size and day in booked_days(booking): bookings += (booking,) return bookings Question 4D Provide an implementation. [4 marks] def can_accept(booking, reservations): size = size_of(booking) for day in booked_days(booking): num_booked = len(current_bookings(reservations, size, day)) if hotel_capacity[size] <= num_booked: return False return True 7 Answer Sheet CS1010S Midterm Test — 30 Sep 2020 Question 4E [4 marks] def accept_upgrade(booking, reservations): for size in range(size_of(booking), len(hotel_capacity)): if can_accept(booking, reservations): return booking else: booking = make_booking(size+1, booked_days(booking)[0], booked_days(booking)[-1] + 1) return False 8 Answer Sheet CS1010S Midterm Test — 30 Sep 2020 This page is intentionally left blank. Use it ONLY if you need extra space for your answers, in which case indicate the question number clearly. DO NOT use it for your rough work. — END OF ANSWER SHEET — 9 Solutions CS1010S Midterm Test — 30 Sep 2020 Question 1A a = 1 b = 2 def fib(a): print(b) def fab(b): print(b - a) fab(b - a) print(b) print(fib(b)) 2 -2 2 None [5 marks] Tests the understanding of scoping and whether students are careful with parameter substitution. Checks if students understand what the difference between print and return. +1 2 +1 -2 +1 2 +1 None +1 Correct order of output Note Additional marks may be deducted if the answer does not demonstrate understanding of scoping, even if some of the output match. Question 1B a = (1, (2, (3,))) b = (4, 5) if 1 in a: print(2) if 3 == a[1][1]: print(4) elif 5 == b[-1]: b += 6 else: print(7) print(b) [5 marks] Tests tuple indexing and concatenation, managing nested tuples, and differences in tuples vs integers. Tests understanding of independence of each if statement. +1 +2 +1 +1 2 State error occurs Does not print more output after error occurs Specifies TypeError or pinpoints error line a += (6) or states cannot add tuple and int Sympathy Marks 2m if printed 2, 4, b . Demonstrates if/elif/else understanding 2m if printed 2, 7, b . Demonstrates if/elif/else understanding 2 TypeError: cannot add tuple and int 3m if printed 2, (4, 5, 6,) . Only mistake is failing to recognize (6) causes an error when added to tuple. 3 Solutions CS1010S Midterm Test — 30 Sep 2020 Question 1C d = 4 while d >= 0: print(d) if d % 2 == 1: d = d - 1 print("c") continue if d % 3 == 0: print("b") break d = d // 2 4 2 1 c 0 b [5 marks] General guidelines: 1 mark for demonstration of understanding how a while-loops works. 2 marks each for correct understanding of continue and break . 5m 4m 3m 2m 1m 1m 0m 4 2 1 c 0 b 4 2 1 c b 4 2 1 c 0 0 ... 4 2 1 c 4 2 1 0 0 ... 4 2 1 States infinite loop without demonstrating 4 2 1 4 Solutions CS1010S Midterm Test — 30 Sep 2020 Question 2A Recursive implementation. [5 marks] def infected(r0, j, k): def helper(k): if k == 0: return (1,) else: return helper(k-1) + (ceil(helper(k-1)[-1] * (1+r0)),) return helper(k)[j:] Question 2B Order of growth for Part A. [2 marks] Time: O(2k ), there are two recursive calls to helper(k-1) for helper(k) , which is a tree recursion with branching factor of 2. O(k2 ), if the result of helper(k-1) is stored in a variable and reused, there is only one recursive call. Thus, there is a total of k recursive calls, with each call creating a tuple of increasing length. Space:O(k2 ), the first recursive call to helper(k-1) will return a tuple of length k. This will be stored in memory as the second call is executed. In the final leg, there will be k recursive calls, with each call stack storing a tuple of decreasing size. O(k), if the result of helper(k-1) is stored in a variable and reused, there is only one recursive call. The tuple returned by each call is immediately replaced by a new tuple. So only space for the final tuple is needed. Question 2C Iterative implementation. [5 marks] def infected(r0, j, k): result = () if j == 0: result = (1,) num = 1 for i in range(1, k + 1): num = ceil(num * (1 + r0)) if j <= i: result += (num,) return result 5 Solutions CS1010S Midterm Test — 30 Sep 2020 Question 2D Order of growth for Part C. [2 marks] Time: O(k2 ), there is a total of k steps in the loop, and each iteration constructs a new tuple of increasing size. Space:O(k), each new tuple created is stored over the previous one, and finally a tuple of k length is created. Question 3A [4 marks] *optional <PRE>: <T1>: lambda a, b: b + (ceil(b[-1] * (1+r0)),) <T2>: lambda a: (1,) <T3>: k Question 4A [3 marks] def make_booking(room_size, start_day, end_day): return (room_size, tuple(range(start_day, end_day))) def size_of(booking): return booking[0] def booked_days(booking): return booking[1] 6 Solutions CS1010S Midterm Test — 30 Sep 2020 Question 4B [2 marks] def make_empty_reservations(): return () def add_booking(booking, reservations): return reservations + (booking,) Question 4C [4 marks] def current_bookings(reservations, room_size, day): bookings = () for booking in reservations: if size_of(booking) == room_size and day in booked_days(booking): bookings += (booking,) return bookings Question 4D Provide an implementation. [4 marks] def can_accept(booking, reservations): size = size_of(booking) for day in booked_days(booking): num_booked = len(current_bookings(reservations, size, day)) if hotel_capacity[size] <= num_booked: return False return True 7 Solutions CS1010S Midterm Test — 30 Sep 2020 Question 4E [4 marks] def accept_upgrade(booking, reservations): for size in range(size_of(booking), len(hotel_capacity)): if can_accept(booking, reservations): return booking else: booking = make_booking(size+1, booked_days(booking)[0], booked_days(booking)[-1] + 1) return False 8