[+] TT2
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
"""CSC110 Fall 2021: Term Test 2, Question 1 (Cryptography)
|
||||
|
||||
Module Description
|
||||
==================
|
||||
This module contains instructions for this question. There are THREE
|
||||
parts of this question, labelled "Part (a)", "Part (b)", etc.
|
||||
The comments in this file contain instructions on how to complete each part,
|
||||
so please read those comments carefully.
|
||||
|
||||
At the bottom of the file we've provided code to run doctest and python_ta.
|
||||
python_ta is not required for grading.
|
||||
|
||||
SUBMIT THIS FILE FOR GRADING!
|
||||
|
||||
Copyright and Usage Information
|
||||
===============================
|
||||
|
||||
This file is provided solely for the personal and private use of students
|
||||
taking CSC110 at the University of Toronto St. George campus. All forms of
|
||||
distribution of this code, whether as given or with any changes, are
|
||||
expressly prohibited. For more information on copyright for CSC110 materials,
|
||||
please consult our Course Syllabus.
|
||||
|
||||
This file is Copyright (c) 2021 Mario Badr and Tom Fairgrieve.
|
||||
"""
|
||||
|
||||
|
||||
###################################################################################################
|
||||
# Encrypting Grade Messages
|
||||
###################################################################################################
|
||||
# We can represent your first-year courses grades using a tuple of five integers between 0 and 100,
|
||||
# inclusive. A *grades message* is a list of grades, i.e., a list[tuple[int, int, int, int, int]].
|
||||
# For example:
|
||||
#
|
||||
# [(95, 90, 67, 75, 89), (55, 64, 78, 92, 86), (100, 96, 64, 83, 87)]
|
||||
|
||||
###################################################################################################
|
||||
# Description of the Cryptosystem
|
||||
###################################################################################################
|
||||
# We define the following SYMMETRIC-KEY CRYPTOSYSTEM on grade messages:
|
||||
#
|
||||
# PLAINTEXT and CIPHERTEXT:
|
||||
# Grades messages (i.e, list[tuple[int, int, int, int, int]],
|
||||
# where each int is in 0-100, inclusive.
|
||||
#
|
||||
# SECRET KEY:
|
||||
# The secret key is an integer k.
|
||||
#
|
||||
# ENCRYPTION:
|
||||
# For each index i in the plaintext grade message (starting at i = 0), transform the i-th grade
|
||||
# tuple by adding (k^(i+1)) to each element of the tuple and then taking the remainder modulo 101.
|
||||
#
|
||||
# DECRYPTION:
|
||||
# Reverse the encryption process.
|
||||
|
||||
###################################################################################################
|
||||
# Part (a) - encryption
|
||||
###################################################################################################
|
||||
# The function below is the start of the encryption algorithm described above.
|
||||
# Complete it by doing two things:
|
||||
# 1. Complete the doctest example by showing the expected return value of the function call.
|
||||
# 2. Implement the function body. You may use loops, comprehensions, and/or helper functions.
|
||||
# You are not required to add doctests for any helper functions you create.
|
||||
#
|
||||
# Note: encryption should NOT mutate the input plaintext.
|
||||
|
||||
|
||||
def encrypt_tt2(k: int, plaintext: list[tuple[int, int, int, int, int]]) \
|
||||
-> list[tuple[int, int, int, int, int]]:
|
||||
"""Return the ciphertext grade message when plaintext is encrypted with key k.
|
||||
|
||||
Preconditions:
|
||||
- k and plaintext are valid inputs for encryption, based on the cryptosystem description
|
||||
|
||||
>>> key = 20
|
||||
>>> p = [(95, 90, 67, 75, 89), (55, 64, 78, 92, 86)]
|
||||
>>> encrypt_tt2(key, p)
|
||||
[(14, 9, 87, 95, 8), (51, 60, 74, 88, 82)]
|
||||
"""
|
||||
c = []
|
||||
for i in range(len(plaintext)):
|
||||
incr = k ** (i + 1)
|
||||
n1, n2, n3, n4, n5 = [(n + incr) % 101 for n in plaintext[i]]
|
||||
c.append((n1, n2, n3, n4, n5))
|
||||
return c
|
||||
|
||||
|
||||
###################################################################################################
|
||||
# Part (b) - decryption
|
||||
###################################################################################################
|
||||
# The function below is the start of the decryption algorithm described above.
|
||||
# Complete it by doing two things:
|
||||
# 1. Add one new doctest example for this function.
|
||||
# 2. Implement the function body. You may use loops, comprehensions, and/or helper functions.
|
||||
# You are not required to add doctests for any helper functions you create.
|
||||
# It is up to you to determine the correct algorithm for decrypting a ciphertext,
|
||||
# based on the description of the encryption algorithm.
|
||||
#
|
||||
# Note: decryption should NOT mutate the input ciphertext.
|
||||
|
||||
def decrypt_tt2(k: int, ciphertext: list[tuple[int, int, int, int, int]]) \
|
||||
-> list[tuple[int, int, int, int, int]]:
|
||||
"""Return the plaintext grade message when ciphertext is decrypted with key k.
|
||||
|
||||
Preconditions:
|
||||
- k and ciphertext are valid inputs for decryption, based on the cryptosystem description
|
||||
|
||||
>>> key = 20
|
||||
>>> c = [(19, 15, 84, 2, 6)]
|
||||
>>> decrypt_tt2(key, c)
|
||||
[(100, 96, 64, 83, 87)]
|
||||
"""
|
||||
p = []
|
||||
for i in range(len(ciphertext)):
|
||||
incr = k ** (i + 1)
|
||||
n1, n2, n3, n4, n5 = [(n - incr) % 101 for n in ciphertext[i]]
|
||||
p.append((n1, n2, n3, n4, n5))
|
||||
return p
|
||||
|
||||
|
||||
###################################################################################################
|
||||
# Part (c) - understanding the cryptosystem
|
||||
###################################################################################################
|
||||
def why_101() -> str:
|
||||
"""Return a string describing why we use a modulus of 101 instead of 100 in the cryptosystem
|
||||
defined above.
|
||||
"""
|
||||
return "This is because modding by 100 will return the last two digits of the original number" \
|
||||
", which will reveal the original content if the key is a whole number like 10 or 20"
|
||||
BIN
Binary file not shown.
+158
@@ -0,0 +1,158 @@
|
||||
% Copyright and Usage Information
|
||||
% ===============================
|
||||
|
||||
% This file is provided solely for the personal and private use of students
|
||||
% taking CSC110 at the University of Toronto St. George campus. All forms of
|
||||
% distribution of this code, whether as given or with any changes, are
|
||||
% expressly prohibited. For more information on copyright for CSC110 materials,
|
||||
% please consult our Course Syllabus.
|
||||
|
||||
% This file is Copyright (c) 2021 Mario Badr and Tom Fairgrieve.
|
||||
\documentclass{article}
|
||||
|
||||
\setlength{\parindent}{0pt}
|
||||
\setlength{\parskip}{5pt}
|
||||
|
||||
\usepackage{amsmath}
|
||||
\usepackage{amssymb}
|
||||
\usepackage{amsthm}
|
||||
\usepackage{amsfonts}
|
||||
|
||||
\usepackage[margin=1in]{geometry}
|
||||
|
||||
\title{CSC110 Fall 2021: Term Test 2\\
|
||||
Question 2 (Analyzing Algorithm Running Time)}
|
||||
\author{TODO: INSERT YOUR NAME HERE}
|
||||
\date{Wednesday December 8, 2021}
|
||||
|
||||
% Some useful LaTeX commands. You are free to use these or not, and also add your own.
|
||||
\newcommand{\N}{\mathbb{N}}
|
||||
\newcommand{\Z}{\mathbb{Z}}
|
||||
\newcommand{\R}{\mathbb{R}}
|
||||
\newcommand{\cO}{\mathcal{O}}
|
||||
\newcommand{\floor}[1]{\left\lfloor #1 \right\rfloor}
|
||||
\newcommand{\ceil}[1]{\left\lceil #1 \right\rceil}
|
||||
\newcommand{\C}{\texttt}
|
||||
|
||||
\begin{document}
|
||||
\maketitle
|
||||
|
||||
\subsection*{Question 2, Part 1}
|
||||
|
||||
\noindent
|
||||
We define the function $g: \N \to \R^{\geq 0}$ as $g(n) = 7n(n-1)^2$.
|
||||
Consider the following statement:
|
||||
|
||||
\[
|
||||
g(n) \in \cO(n^4)
|
||||
\]
|
||||
|
||||
\begin{enumerate}
|
||||
|
||||
\item[(a)]
|
||||
Rewrite the statement $g(n) \in \cO(n^4)$ by expanding the definition of Big-O.
|
||||
|
||||
\bigskip
|
||||
|
||||
\textbf{Solution}:
|
||||
|
||||
$\exists c, n_0 \in \R^+ \text{ s.t. } \forall n \in \N, n \ge n_0 \Rightarrow 7n(n-1)^2 \le c \cdot n^4$
|
||||
|
||||
\item[(b)]
|
||||
Write the \emph{negation} of the statement from (a), using negation rules to simplify the statement as much as possible.
|
||||
|
||||
\bigskip
|
||||
|
||||
\textbf{Solution}:
|
||||
|
||||
$\forall c, n_0 \in \R^+, \exists n \in \N \text{ s.t. } n \ge n_0 \land 7n(n-1)^2 > c \cdot n^4$
|
||||
|
||||
\item[(c)]
|
||||
Which of statements (a) and (b) is true? Provide a complete proof that justifies your choice.
|
||||
|
||||
In your proof, you may not use any properties or theorems about Big-O/Omega/Theta. Work from the expanded statement from (a) or (b).
|
||||
|
||||
\bigskip
|
||||
|
||||
\textbf{Solution}:
|
||||
|
||||
I think statement (a) is true.
|
||||
|
||||
\begin{proof}
|
||||
Want to show: $\exists c, n_0 \in \R^+ \text{ s.t. } \forall n \in \N, n \ge n_0 \Rightarrow 7n(n-1)^2 \le c \cdot n^4$ \\
|
||||
Prove using Induction. \\
|
||||
Take $c = 7, n_0 = 1$ \\
|
||||
Let $n$ be an arbitrary natural number such that $n \ge (n_0 = 1)$ \\
|
||||
What we want to prove becomes: $\forall n \in \N, n \ge 1 \Rightarrow 7n(n-1)^2 \le 7n^4$ \\
|
||||
\\
|
||||
Since $n \ge 1$, \\
|
||||
Multiply both sides by $n^2$, we get $n^3 \ge n^2$ \\
|
||||
From this, we also know that $(n - 1)^2 \le n^3$ \\
|
||||
Also, since $n \ge 1$, \\
|
||||
Multiply the inequality by $-2$, we get $-2n \le -2$ \\
|
||||
Adding $1$ to both sides, we get $-2n + 1 \le -1$ \\
|
||||
Putting the two inequalities together, we have $n^2 - 2n + 1 \le n^3 - 1 \le n^3$ \\
|
||||
Factoring the polynomial on the left, we have $(n - 1)^2 \le n^3$ \\
|
||||
Multiply both sides by $7n$, we get $7n(n - 1)^2 \le 7n^4$\\
|
||||
Which is what we want to prove.
|
||||
|
||||
\end{proof}
|
||||
|
||||
\end{enumerate}
|
||||
|
||||
\subsection*{Question 2, Part 2}
|
||||
|
||||
\noindent
|
||||
Consider the function below.
|
||||
|
||||
\begin{verbatim}
|
||||
def f(nums: list[int]) -> list[int]: # Line 1
|
||||
n = len(nums) # Line 2
|
||||
i = 1 # Line 3
|
||||
new_list = [] # Line 4
|
||||
while i < n: # Line 5
|
||||
if nums[i] % 2 == 0: # Line 6
|
||||
list.append(new_list, i) # Line 7
|
||||
else: # Line 8
|
||||
new_list = [i * j for j in nums] # Line 9
|
||||
i = i * 3 # Line 10
|
||||
return new_list # Line 11
|
||||
\end{verbatim}
|
||||
|
||||
\begin{enumerate}
|
||||
|
||||
\item[(a)]
|
||||
Perform an \emph{upper bound analysis} on the worst-case running time of \texttt{f}.
|
||||
The Big-O expression that you conclude should be \emph{tight}, meaning that the worst-case running time should be Theta of this expression, but you are not required to show that here.
|
||||
|
||||
\textbf{To simplify your analysis}, you may omit all floors and ceilings in your calculations (if applicable).
|
||||
Use ``at most'' or $\leq$ to be explicit about where a step count expression is an upper bound.
|
||||
|
||||
\textbf{Solution}:
|
||||
|
||||
Let $n$ be the length of the input list \C{nums}
|
||||
|
||||
There is one loop in the function which loops through \C{nums} with $i$ increasing exponentially, which will run $\ceil{log_3(n)}$ times. Inside the loop, if then number is even, it takes $\cO(1)$ to append the item at the end of \C{new\_list}. If the number is odd, it sets \C{new\_list} to a list comprehension which iterates through all number in \C{nums}, performing an $\cO(1)$ multiplication every iteration, which takes exactly $n$ steps, which is a larger running time than if the number is even. Therefore, the inside of the loop will take at most $n$ steps, if all numbers \C{nums[i]} iterated are odd.
|
||||
|
||||
Since there are only constant-time operations outside the loop, the worst-case running time would be $\ceil{log_3(n)}$ iterations multiplied by at most $n$ steps per iteration, which is $n\ceil{log_3(n)}$ steps.
|
||||
|
||||
Since $n\ceil{log_3(n)} \in \cO(n\ceil{log_3(n)})$, we can conclude that $WC_{f}(n) \in \cO(n\ceil{log_3(n)})$
|
||||
|
||||
\item[(b)]
|
||||
Perform a \emph{lower bound analysis} on the worst-case running time of \texttt{f}.
|
||||
The Omega expression you find should match your Big-O expression from part (a).
|
||||
|
||||
\textbf{Hint}: you don't need to try to find an ``exact maximum running-time'' input. \emph{Any} input family whose running time is Omega of (``at least'') the bound you found in part (a) will yield a correct analysis for this part.
|
||||
|
||||
\textbf{Solution}:
|
||||
|
||||
Let $n$ be the length of the input list \C{nums}, let \C{nums} be the list of length $n$ which every number is 1.
|
||||
|
||||
In this case, the if statement inside the loop always runs line 9 that takes $n$ steps, and then the $i = i * 3$ statement, which is 1 step, which is a total of $n + 1$ steps. The loop still iterates $\ceil{log_3(n)}$ times. Since there are only constant-time operations outside the loop, the total number of steps for this input is $(n + 1)\ceil{log_3(n)} + c$ which $c \in \N$ is a constant, which is $WC_{f}(n) \in \Omega(n\ceil{log_3(n)})$
|
||||
|
||||
\end{enumerate}
|
||||
|
||||
\begin{center}
|
||||
\textbf{SUBMIT THIS FILE AND THE GENERATED PDF q2.pdf FOR GRADING}
|
||||
\end{center}
|
||||
\end{document}
|
||||
@@ -0,0 +1,191 @@
|
||||
"""CSC110 Fall 2021: Term Test 2, Question 3 (Object Oriented Design)
|
||||
|
||||
Module Description
|
||||
==================
|
||||
This module contains instructions for this question. There are TWO
|
||||
parts of this question, labelled "Part (a)", "Part (b)", etc.
|
||||
The comments in this file contain instructions on how to complete each part,
|
||||
so please read those comments carefully.
|
||||
|
||||
SUBMIT THIS FILE FOR GRADING!
|
||||
|
||||
Copyright and Usage Information
|
||||
===============================
|
||||
|
||||
This file is provided solely for the personal and private use of students
|
||||
taking CSC110 at the University of Toronto St. George campus. All forms of
|
||||
distribution of this code, whether as given or with any changes, are
|
||||
expressly prohibited. For more information on copyright for CSC110 materials,
|
||||
please consult our Course Syllabus.
|
||||
|
||||
This file is Copyright (c) 2021 Mario Badr and Tom Fairgrieve.
|
||||
"""
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
###################################################################################################
|
||||
# Modelling a Problem Domain
|
||||
###################################################################################################
|
||||
# In this question, you will model a new problem domain by designing classes in a similar style to
|
||||
# the food delivery system we studied in lecture.
|
||||
|
||||
###################################################################################################
|
||||
# Description of the Problem Domain
|
||||
###################################################################################################
|
||||
# Your client is the University of Toronto. They want new software to manage the grades of their
|
||||
# students. The grade system will store:
|
||||
# 1. GRADES that each have the course id (e.g., 'CSC110Y'), term id (e.g., '20219'), and score in
|
||||
# the course (i.e., an integer ranging from 0 to 100, inclusive).
|
||||
# 2. STUDENTS that each have a utorid (e.g., 'astudent') and a collection of grades.
|
||||
|
||||
###################################################################################################
|
||||
# Part (a) - Entity data classes
|
||||
###################################################################################################
|
||||
# Your first task is to complete the two data classes below, which represent the two main entities
|
||||
# in our computational model. Read the provided docstrings and use them to complete each data class
|
||||
# body.
|
||||
#
|
||||
# Do NOT add any additional instance attributes or change the class docstring.
|
||||
# You do NOT need to add any representation invariants or doctest examples.
|
||||
|
||||
@dataclass
|
||||
class Grade:
|
||||
"""A grade on Acorn.
|
||||
|
||||
Instance Attributes:
|
||||
- course: the course (e.g., 'CSC110Y1') this grade was achieved in.
|
||||
- term: the term (e.g., '20219') this grade was achieved in.
|
||||
- score: an integer representing the grade achieved.
|
||||
"""
|
||||
course: str
|
||||
term: str
|
||||
score: int
|
||||
|
||||
|
||||
@dataclass
|
||||
class Student:
|
||||
"""A student who can have courses grades on acorn.
|
||||
|
||||
Instance Attributes:
|
||||
- utorid: the utorid of this student
|
||||
- grades: a dictionary mapping a course (e.g., 'CSC110Y1') to the student's Grade in that
|
||||
course.
|
||||
"""
|
||||
utorid: str
|
||||
grades: dict[str, Grade]
|
||||
|
||||
|
||||
###############################################################################
|
||||
# Part (b) - Manager class
|
||||
###############################################################################
|
||||
# The class below is responsible for keeping track of all instances of the entities in our
|
||||
# model and performing mutating operations on them.
|
||||
#
|
||||
# Read through the class and implement the methods that have empty bodies.
|
||||
# Do NOT change anything else in the class (attributes, methods that we have implemented).
|
||||
|
||||
|
||||
class AcornSystem:
|
||||
"""A class that tracks students and their grades."""
|
||||
|
||||
# Private Instance Attributes:
|
||||
# - _students: a dictionary mapping utorids to Students
|
||||
|
||||
def __init__(self, initial_students: list[Student]) -> None:
|
||||
"""Initialize a new AcornSystem, adding every student in initial_students to this system.
|
||||
|
||||
Precondition:
|
||||
- Every student in initial_students has a unique utorid
|
||||
"""
|
||||
self._students = {}
|
||||
for student in initial_students:
|
||||
self._students[student.utorid] = student
|
||||
|
||||
def student_count(self) -> int:
|
||||
"""Return the number of students in this system."""
|
||||
return len(self._students)
|
||||
|
||||
def add_grade(self, utorid: str, grade: Grade) -> bool:
|
||||
"""Add grade to the student with utorid and return whether the grade was added successfully.
|
||||
|
||||
Do not add grade if the student with utorid already has a grade assigned for that course.
|
||||
|
||||
Preconditions:
|
||||
- A student with utorid exists in this system
|
||||
"""
|
||||
student = self._students[utorid]
|
||||
|
||||
if grade.course in student.grades:
|
||||
return False
|
||||
else:
|
||||
student.grades[grade.course] = grade
|
||||
return True
|
||||
|
||||
def get_grades(self, utorid: str, term: str) -> list[tuple[str, int]]:
|
||||
"""Return a list of tuples of the courses and scores that the student with utorid achieved
|
||||
in term.
|
||||
|
||||
Preconditions:
|
||||
- A student with utorid exists in this system
|
||||
- The student in this system with utorid has a grade for course
|
||||
|
||||
>>> acorn_system = AcornSystem([Student('astudent', {})])
|
||||
>>> acorn_system.add_grade('astudent', Grade('CLA204H1', '20209', 76))
|
||||
True
|
||||
>>> acorn_system.get_grades('astudent', '20209')
|
||||
[('CLA204H1', 76)]
|
||||
"""
|
||||
return [(g.course, g.score) for g in self._students[utorid].grades.values()
|
||||
if g.term == term]
|
||||
|
||||
def amend_grades(self, utorid: str, amendments: dict[str, int]) -> int:
|
||||
"""Update the grades for the student with utorid based on the amendments, which maps courses
|
||||
to the amended score.
|
||||
|
||||
Return the number of successful amendments made. An amendment is not successful if the
|
||||
student has no grade on record for the course. No mutation should occur for students who
|
||||
have no grade on record for course.
|
||||
|
||||
Preconditions:
|
||||
- A student with utorid exists in this system
|
||||
|
||||
>>> acorn_system = AcornSystem([Student('astudent', {})])
|
||||
>>> acorn_system.add_grade('astudent', Grade('CLA204H1', '20209', 76))
|
||||
True
|
||||
>>> acorn_system.amend_grades('astudent', {'CLA204H1': 80})
|
||||
1
|
||||
>>> acorn_system.get_grades('astudent', '20209')
|
||||
[('CLA204H1', 80)]
|
||||
"""
|
||||
grades = self._students[utorid].grades
|
||||
count = 0
|
||||
for course in amendments:
|
||||
if course in grades:
|
||||
grades[course].score = amendments[course]
|
||||
count += 1
|
||||
return count
|
||||
|
||||
def calculate_averages(self, utorids: list[str]) -> dict[str, float]:
|
||||
"""Return a dictionary mapping a student's utorid to the average grade they achieved for
|
||||
all courses completed.
|
||||
|
||||
Preconditions:
|
||||
- Every utorid in amendments is a student in this system
|
||||
|
||||
>>> acorn_system = AcornSystem([Student('astudent', {}), Student('bstudent', {})])
|
||||
>>> acorn_system.add_grade('astudent', Grade('CLA204H1', '20209', 76))
|
||||
True
|
||||
>>> acorn_system.calculate_averages(['astudent'])
|
||||
{'astudent': 76.0}
|
||||
>>> acorn_system.add_grade('astudent', Grade('CLA205H1', '20219', 98))
|
||||
True
|
||||
>>> acorn_system.calculate_averages(['astudent'])
|
||||
{'astudent': 87.0}
|
||||
>>> acorn_system.add_grade('bstudent', Grade('CLA205H1', '20219', 98))
|
||||
True
|
||||
>>> temp = acorn_system.calculate_averages(['astudent', 'bstudent'])
|
||||
>>> temp == {'astudent': 87.0, 'bstudent': 98.0}
|
||||
True
|
||||
"""
|
||||
return {u: sum(g.score for g in self._students[u].grades.values())
|
||||
/ len(self._students[u].grades) for u in utorids}
|
||||
Reference in New Issue
Block a user