diff --git a/TT1/q1/q1.py b/TT1/q1/q1.py new file mode 100755 index 0000000..daca00b --- /dev/null +++ b/TT1/q1/q1.py @@ -0,0 +1,137 @@ +"""CSC110 Fall 2021: Term Test 1, Question 1 (Function Design) + +Module Description +================== +This Python file 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, pytest, 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. +""" + +from hypothesis import given +from hypothesis.strategies import integers, tuples + + +#################################################################################################### +# Part (a) +#################################################################################################### +# Here is a definition: +# +# Let p be a 3-item tuple of the form (a, b, c) where a, b and c are positive integers. +# We say that p is a Pythagorean triple whenever c squared is equal to the sum of a squared plus b +# squared. +# For example, p = (3, 4, 5) is a Pythagorean triple because 25 = 9 + 16. +# +# Use the Function Design Recipe to define a function is_pythagorean_triple that returns +# whether a given 3-item tuple is a Pythagorean triple. You need to write: +# +# 1. A precondition (as a Python expression) expressing that the items in p are positive integers. +# 2. TWO different doctest examples. +# 3. A correct function body. + + +def is_pythagorean_triple(p: tuple[int, int, int]) -> bool: + """Return whether p is a Pythagorean triple. + + Preconditions: + - all(n > 0 for n in p) + + >>> is_pythagorean_triple((3, 4, 5)) + True + >>> is_pythagorean_triple((1, 1, 2)) + False + """ + a, b, c = p + return (c ** 2) == a ** 2 + b ** 2 + + +#################################################################################################### +# Part (b) +#################################################################################################### +# Here is another definition: +# +# Let L be a list where every item is a tuple of three positive integers that we will call (a,b,c). +# We say that L is a *Pythagorean list* when every item in the list is a Pythagorean triple. +# An empty list is NOT considered to be a Pythagorean triple. +# +# Use the Function Design Recipe to define a function is_pythagorean_list that returns +# whether a given list is a Pythagorean list. You need to write: +# +# 1. A precondition (as a Python expression) expressing that every item in list lst is a tuple that +# contains positive integers. +# 2. TWO different doctest examples. +# 3. A correct function body that uses a comprehension and any/all. +# You must call is_pythagorean_triple in this function, and you may NOT use loops. + + +def is_pythagorean_list(lst: list[tuple[int, int, int]]) -> bool: + """Return whether lst is a Pythagorean list. + + Preconditions: + - all(n > 0 for t in lst for n in t) + + >>> is_pythagorean_list([]) + False + >>> is_pythagorean_list([(3, 4, 5), (6, 8, 10)]) + True + """ + if len(lst) == 0: + return False + return all(is_pythagorean_triple(n) for n in lst) + + +#################################################################################################### +# Part (c) +#################################################################################################### +# Consider the following property: +# +# For all positive integers a, b, c and k, +# if p = (a, b, c) is a Pythagorean triple then (k*a, k*b, k*c) is also a Pythagorean triple. +# +# Complete the property-based test below to express this property. +# We have started it for you; you only need to fill in the body of the test. + + +@given(p=tuples(integers(min_value=1), integers(min_value=1), integers(min_value=1)), + k=integers(min_value=1)) +def test_multiplier_pyth_triple(p: tuple[int, int, int], k: int) -> None: + """Test the multiplier property of Pythagorean triples.""" + if is_pythagorean_triple(p): + a, b, c = p + assert is_pythagorean_triple((k * a, k * b, k * c)) + + +if __name__ == '__main__': + import python_ta.contracts + python_ta.contracts.DEBUG_CONTRACTS = False + python_ta.contracts.check_all_contracts() + + import doctest + doctest.testmod() + + # You can uncomment this to check your test in Part (c). + import pytest + pytest.main(['q1.py']) + + import python_ta + python_ta.check_all(config={ + 'disable': ['R1729', 'C0412'], + 'extra-imports': ['python_ta.contracts', 'hypothesis.strategies'], + 'max-line-length': 100 + }) diff --git a/TT1/q2/q2.pdf b/TT1/q2/q2.pdf new file mode 100644 index 0000000..204039e Binary files /dev/null and b/TT1/q2/q2.pdf differ diff --git a/TT1/q2/q2.tex b/TT1/q2/q2.tex new file mode 100755 index 0000000..0799c27 --- /dev/null +++ b/TT1/q2/q2.tex @@ -0,0 +1,92 @@ +% 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[margin=1in]{geometry} + +\title{CSC110 Fall 2021: Term Test 1, Question 2 (Predicate Logic)} +\author{Azalea Gui} +\date{Wednesday October 20, 2021} + +\begin{document} +\maketitle + +Let $A$ be the set of all animals and all plants. +Suppose we define the following predicates: + +\begin{itemize} + \item $Plant(x):$ ``$x$ is a plant", where $x \in A$. + \item $Omnivore(x):$ ``$x$ is an omnivore", where $x \in A$. + \item $Herbivore(x):$ ``$x$ is a herbivore", where $x \in A$. + \item $IsColourful(x):$ ``$x$ is colourful", where $x \in A$. + \item $Eats(x, y):$ ``$x$ eats $y$", where $x, y \in A$. +\end{itemize} +(An omnivore is an animal that eats food of both plant and animal origin. +A herbivore is an animal that only eats plants.) + +For parts (1) to (3), translate each of the following statements from English into symbolic predicate logic. +In part (4), you will translate an English statement into Python code. + +No explanation is necessary. +Do not define any of your own predicates or sets. + +Use parentheses to indicate how you want to group logical expressions with multiple operators (especially when dealing with $\Rightarrow$ and $\Leftrightarrow$). + +\begin{enumerate} +\item +At least one plant is colourful. + +\textbf{Solution}: + +$\exists x \in A$ s.t. $Plant(x) \land IsColourful(x)$ + +\item +Omnivores eat any animal or plant. + +\textbf{Solution}: + +$\forall x, y \in A$, $Omnivore(x) \Rightarrow Eats(x, y)$ + +\item +At least one herbivore does not eat colourful plants. + +\textbf{Solution}: + +$\exists x \in A$, $\forall y \in A$, $Herbivore(x) \land ((IsColorful(y) \land Plant(y)) \Rightarrow \neg Eats(x, y))$ + +\item +Suppose we define the following in Python: +\begin{itemize} + \item A variable \texttt{animals\_and\_plants} which represents a set of animals and plants. + \item Functions \texttt{is\_herbivore} and \texttt{eats} that take in argument values from \texttt{animals\_and\_plants}, and correspond to the predicates $Herbivore$ and $Eats$, respectively, defined at the top of this question. + \item A variable \texttt{brussel\_sprouts} that refers to the plant brussel sprouts. (Note: \texttt{brussel\_sprouts in animals\_and\_plants} is True) +\end{itemize} + +Using these definitions, translate the following statement into a Python expression: +\begin{quote} +All herbivores eat brussel sprouts. +\end{quote} + +You must use a comprehension in your solution, and may not use any loops. + +\begin{verbatim} +all([eats(x, brussel_sprouts) for x in animals_and_plants if is_herbivore(x)]) + +\end{verbatim} + +\begin{center} + \textbf{SUBMIT THIS FILE AND THE GENERATED PDF q2.pdf FOR GRADING} +\end{center} +\end{enumerate} +\end{document} diff --git a/TT1/q3/q3.py b/TT1/q3/q3.py new file mode 100755 index 0000000..04f9ba3 --- /dev/null +++ b/TT1/q3/q3.py @@ -0,0 +1,247 @@ +"""CSC110 Fall 2021: Term Test 1, Q3 + +Module Description +================== +This Python file contains instructions for this question. There are FOUR +parts of this question, labelled "Part (a)", "Part (b)", etc. +The docstrings in this file contain instructions on how to complete each part, +so please read those comments carefully. + +python_ta is not required 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 + + +#################################################################################################### +# Part (a) +#################################################################################################### +def create_nested_list_data() -> list[list]: + """Return a small dataset in a nested list format. + + Each nested list is composed of items with type: str, str, float, in that order. + - The first str is the title (i.e., name) of a book + - The second str is the name of the author + - the float is the average rating for the book + + INSTRUCTIONS: Do NOT change this function. + """ + return [ + ['Shogun', 'James Clavell', 4.39], + ['1984', 'George Orwell', 4.4], + ['Animal Farm', 'George Orwell', 3.96], + ['The Ex Hex', 'Erin Sterling', 3.76] + ] + + +def comma_separated_titles(data: list[list]) -> str: + """Return a string of the book titles in data in the order that they appear, where each title + ends with a comma and a space (i.e., ', '). + + Preconditions: + - data is in the format as specified in create_nested_list_data + + INSTRUCTIONS: Complete the body of this function. You must follow the docstring description + exactly. Do NOT add any more doctest examples. + + RESTRICTIONS: + - You must use a for loop + - You may not use any comprehensions + - You may not use any built-in functions/methods + + >>> example_data = create_nested_list_data() + >>> comma_separated_titles(example_data) + 'Shogun, 1984, Animal Farm, The Ex Hex, ' + """ + csv = "" + for entry in data: + csv += entry[0] + ', ' + return csv + + +def reset_ratings(data: list[list], author: str) -> None: + """Reset (i.e., MUTATE) the ratings of all books by author in data to 0.0. + + Preconditions: + - data is in the format as specified in create_nested_list_data + + INSTRUCTIONS: Complete the body of this function and add ONE doctest example that demonstrates + what the function does. + + RESTRICTIONS: + - You must use a for loop + - You may not use any comprehensions + - You may not use any built-in functions/methods + + >>> example_data = create_nested_list_data() + >>> reset_ratings(example_data, 'George Orwell') + >>> example_data[1][2] == 0.0 and example_data[2][2] == 0.0 + True + """ + for entry in data: + if entry[1] == author: + entry[2] = 0.0 + + +#################################################################################################### +# Part (b) +#################################################################################################### +def has_valid_ratings(data: list[list]) -> bool: + """Return whether every rating in data is a valid rating. + + A valid rating is a rating between 0.0 and 5.0, inclusive. + + Preconditions: + - data is in the format as specified in create_nested_list_data + - len(data) > 0 + + INSTRUCTIONS: Do NOT change this function. We know that it contains at least one bug. + """ + for book in data: + if 0.0 <= book[2] <= 5.0: + return False + + return True + + +def test_has_valid_ratings() -> None: + """Test has_valid_ratings (see instructions). + + INSTRUCTIONS: There is at least one bug in has_valid_ratings. Complete the body of this UNIT + TEST so that it demonstrates a bug. That is, this unit test should fail when run on + has_valid_ratings. + + RESTRICTIONS: + - You may not use hypothesis + - You may not violate the function's preconditions (including the type contract) + """ + data = create_nested_list_data() + assert has_valid_ratings(data) + + +def has_valid_ratings_bug() -> str: + """Return a BRIEF English description of the bug you found in has_valid_ratings. + + INSTRUCTIONS: Complete the body of this function so that it returns your description of the + bug in a single string. + + RESTRICTIONS: + - Your description must be less than 200 characters (i.e., + len(has_valid_ratings_bug()) < 200) + """ + return "The body should not return False when it found a valid rating (between 0 and 5), it should return false when it found an invalid rating instead." + + +#################################################################################################### +# Part (c) +#################################################################################################### +@dataclass +class Book: + """A data class that represents a book at Indigo. + + INSTRUCTIONS: Do NOT change this dataclass. + + Instance Attributes: + - title: the title (or name) of the book + - author: the name of the author of the book + - rating: the average rating of the book + + Representation Invariants: + - self.title != '' + - self.author != '' + - self.rating >= 0.0 + + >>> some_book = Book('1984', 'George Orwell', 4.4) + """ + title: str + author: str + rating: float + + +def create_dataclass_data() -> list[Book]: + """Return a small dataset in a list of dataclass format. + + INSTRUCTIONS: Do NOT change this function. + """ + return [ + Book('Shogun', 'James Clavell', 4.39), + Book('1984', 'George Orwell', 4.4), + Book('Animal Farm', 'George Orwell', 3.96), + Book('The Ex Hex', 'Erin Sterling', 3.76) + ] + + +def collect_ll_authors(data: list[Book]) -> set[str]: + """Return the set of all author names in data where the author name contains two adjacent + lowercase l's (i.e., 'll'). + + INSTRUCTIONS: Complete the body of this function and add ONE doctest example that demonstrates + what the function does. + + RESTRICTIONS: + - You must use a for loop + - You may not use any comprehensions + - You may not use any built-in functions/methods, EXCEPT FOR: set.add + + >>> example_data = create_dataclass_data() + >>> collect_ll_authors(example_data) == {'James Clavell', 'George Orwell'} + True + """ + ll_authors = set() + for entry in data: + if 'll' in entry.author: + ll_authors.add(entry.author) + return ll_authors + + +#################################################################################################### +# Part (d) +#################################################################################################### +def add_book_titles(titles: list[str], data: list[Book], author: str) -> None: + """Add (i.e., MUTATE) to titles, in the order that they appear, the names of the books from data + that are written by author. + + INSTRUCTIONS: Do NOT change this function. We know that it contains at least one bug. + """ + for book in data: + if book.author == author: + titles = titles + [book.title] + + +def test_add_book_titles() -> None: + """Test add_book_titles. + + INSTRUCTIONS: There is at least one bug in add_book_titles. Complete the body of this UNIT + TEST so that it demonstrates a bug. That is, this unit test should fail when run on + add_book_titles. + + RESTRICTIONS: + - You may not use hypothesis + - You may not violate the function's preconditions (including the type contract) + """ + titles: list[str] = [] + data = create_dataclass_data() + add_book_titles(titles, data, 'George Orwell') + assert titles == ['1984', 'Animal Farm'] + + +def add_book_titles_bug() -> str: + """Return a BRIEF English description of the bug you found in add_book_titles. + + INSTRUCTIONS: Complete the body of this function so that it returns your description of the + bug in a single string. + + RESTRICTIONS: + - Your description must be less than 200 characters (i.e., len(add_book_titles_bug()) < 200) + """ + return "The docstring said that it should mutate the titles list, but it did not mutate the list. It created a new list each time a matching author is found. It should use list.append instead."