From c0e4bef7aec9a9a13ea52098dbaa11f75604a957 Mon Sep 17 00:00:00 2001 From: "github-classroom[bot]" <66690702+github-classroom[bot]@users.noreply.github.com> Date: Tue, 8 Jul 2025 13:31:04 +0000 Subject: [PATCH 1/5] GitHub Classroom Autograding Workflow --- .github/workflows/classroom.yml | 67 +++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 .github/workflows/classroom.yml diff --git a/.github/workflows/classroom.yml b/.github/workflows/classroom.yml new file mode 100644 index 00000000..694e0c44 --- /dev/null +++ b/.github/workflows/classroom.yml @@ -0,0 +1,67 @@ +name: Autograding Tests +'on': +- workflow_dispatch +- repository_dispatch +permissions: + checks: write + actions: read + contents: read +jobs: + run-autograding-tests: + runs-on: ubuntu-latest + if: github.actor != 'github-classroom[bot]' + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Setup + id: setup + uses: classroom-resources/autograding-command-grader@v1 + with: + test-name: Setup + setup-command: sudo -H pip3 install -qr requirements.txt; sudo -H pip3 install + flake8==5.0.4 + command: flake8 --ignore "N801, E203, E266, E501, W503, F812, E741, N803, + N802, N806" minitorch/ tests/ project/; mypy minitorch/* + timeout: 10 + - name: Task 0.1 + id: task-0-1 + uses: classroom-resources/autograding-command-grader@v1 + with: + test-name: Task 0.1 + setup-command: sudo -H pip3 install -qr requirements.txt + command: pytest -m task0_1 + timeout: 10 + - name: Task 0.2 + id: task-0-2 + uses: classroom-resources/autograding-command-grader@v1 + with: + test-name: Task 0.2 + setup-command: sudo -H pip3 install -qr requirements.txt + command: pytest -m task0_2 + timeout: 10 + - name: Task 0.3 + id: task-0-3 + uses: classroom-resources/autograding-command-grader@v1 + with: + test-name: Task 0.3 + setup-command: sudo -H pip3 install -qr requirements.txt + command: pytest -m task0_3 + timeout: 10 + - name: Task 0.4 + id: task-0-4 + uses: classroom-resources/autograding-command-grader@v1 + with: + test-name: Task 0.4 + setup-command: sudo -H pip3 install -qr requirements.txt + command: pytest -m task0_4 + timeout: 10 + - name: Autograding Reporter + uses: classroom-resources/autograding-grading-reporter@v1 + env: + SETUP_RESULTS: "${{steps.setup.outputs.result}}" + TASK-0-1_RESULTS: "${{steps.task-0-1.outputs.result}}" + TASK-0-2_RESULTS: "${{steps.task-0-2.outputs.result}}" + TASK-0-3_RESULTS: "${{steps.task-0-3.outputs.result}}" + TASK-0-4_RESULTS: "${{steps.task-0-4.outputs.result}}" + with: + runners: setup,task-0-1,task-0-2,task-0-3,task-0-4 From 0104b83555a312918c9632834ab5b7ebadba5e4f Mon Sep 17 00:00:00 2001 From: "github-classroom[bot]" <66690702+github-classroom[bot]@users.noreply.github.com> Date: Tue, 8 Jul 2025 13:31:04 +0000 Subject: [PATCH 2/5] GitHub Classroom Feedback --- .github/.keep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 .github/.keep diff --git a/.github/.keep b/.github/.keep new file mode 100644 index 00000000..e69de29b From e1f2c918b34fcd03c055c52c05adb868e234ffdc Mon Sep 17 00:00:00 2001 From: "github-classroom[bot]" <66690702+github-classroom[bot]@users.noreply.github.com> Date: Tue, 8 Jul 2025 13:31:05 +0000 Subject: [PATCH 3/5] Setting up GitHub Classroom Feedback From eae831d381232fe78c3ae82a44854f3adfaba6f1 Mon Sep 17 00:00:00 2001 From: "github-classroom[bot]" <66690702+github-classroom[bot]@users.noreply.github.com> Date: Tue, 8 Jul 2025 13:31:08 +0000 Subject: [PATCH 4/5] add online IDE url --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 62e4d6ba..8a47e6df 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ +[![Open in Visual Studio Code](https://classroom.github.com/assets/open-in-vscode-2e0aaae1b6195c2367325f4f02e2d04e9abb55f0b24a779b69b11b9e10269abc.svg)](https://classroom.github.com/online_ide?assignment_repo_id=19910318&assignment_repo_type=AssignmentRepo) # MiniTorch Module 0 From 77862e5eee808116cf32e34ef89598a29799e8dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9E=97=E8=B6=85?= Date: Wed, 9 Jul 2025 01:03:39 +0800 Subject: [PATCH 5/5] task0_1 task0_2 task0_3 --- minitorch/datasets.py | 24 +++++++--- minitorch/operators.py | 100 +++++++++++++++++++++++++++++++++++++++- tests/test_operators.py | 28 +++++------ 3 files changed, 129 insertions(+), 23 deletions(-) diff --git a/minitorch/datasets.py b/minitorch/datasets.py index b3bd9faa..699cad04 100644 --- a/minitorch/datasets.py +++ b/minitorch/datasets.py @@ -67,19 +67,29 @@ def circle(N): def spiral(N): - def x(t): return t * math.cos(t) / 20.0 def y(t): return t * math.sin(t) / 20.0 - X = [(x(10.0 * (float(i) / (N // 2))) + 0.5, y(10.0 * (float(i) / (N // - 2))) + 0.5) for i in range(5 + 0, 5 + N // 2)] - X = X + [(y(-10.0 * (float(i) / (N // 2))) + 0.5, x(-10.0 * (float(i) / - (N // 2))) + 0.5) for i in range(5 + 0, 5 + N // 2)] + + X = [ + (x(10.0 * (float(i) / (N // 2))) + 0.5, y(10.0 * (float(i) / (N // 2))) + 0.5) + for i in range(5 + 0, 5 + N // 2) + ] + X = X + [ + (y(-10.0 * (float(i) / (N // 2))) + 0.5, x(-10.0 * (float(i) / (N // 2))) + 0.5) + for i in range(5 + 0, 5 + N // 2) + ] y2 = [0] * (N // 2) + [1] * (N // 2) return Graph(N, X, y2) -datasets = {'Simple': simple, 'Diag': diag, 'Split': split, 'Xor': xor, - 'Circle': circle, 'Spiral': spiral} +datasets = { + "Simple": simple, + "Diag": diag, + "Split": split, + "Xor": xor, + "Circle": circle, + "Spiral": spiral, +} diff --git a/minitorch/operators.py b/minitorch/operators.py index 37cc7c09..161103b4 100644 --- a/minitorch/operators.py +++ b/minitorch/operators.py @@ -32,7 +32,71 @@ # $f(x) = |x - y| < 1e-2$ -# TODO: Implement for Task 0.1. +def mul(x: float, y: float) -> float: + return x * y + + +def id(x: float) -> float: + return x + + +def add(x: float, y: float) -> float: + return x + y + + +def neg(x: float) -> float: + return -x + + +def lt(x: float, y: float) -> bool: + return x < y + + +def eq(x: float, y: float) -> bool: + return x == y + + +def max(x: float, y: float) -> float: + return x if x > y else y + + +def is_close(x: float, y: float) -> bool: + return abs(x - y) < 1e-2 + + +def sigmoid(x: float) -> float: + if x >= 0: + return 1.0 / (1.0 + math.exp(-x)) + else: + return math.exp(x) / (1.0 + math.exp(x)) + + +def relu(x: float) -> float: + return x if x > 0 else 0.0 + + +def log(x: float) -> float: + return math.log(x) + + +def exp(x: float) -> float: + return math.exp(x) + + +def log_back(x: float, y: float) -> float: + return y / x + + +def inv(x: float) -> float: + return 1.0 / x + + +def inv_back(x: float, y: float) -> float: + return -y / (x * x) + + +def relu_back(x: float, y: float) -> float: + return y if x > 0 else 0.0 # ## Task 0.3 @@ -51,4 +115,36 @@ # - prod: take the product of lists -# TODO: Implement for Task 0.3. +def map(fn: Callable[[float], float], ls: Iterable[float]) -> Iterable[float]: + return [fn(x) for x in ls] + + +def zipWith( + fn: Callable[[float, float], float], ls1: Iterable[float], ls2: Iterable[float] +) -> Iterable[float]: + return [fn(x, y) for x, y in zip(ls1, ls2)] + + +def reduce( + fn: Callable[[float, float], float], ls: Iterable[float], start: float +) -> float: + res = start + for x in ls: + res = fn(res, x) + return res + + +def negList(ls: Iterable[float]) -> Iterable[float]: + return map(neg, ls) + + +def addLists(ls1: Iterable[float], ls2: Iterable[float]) -> Iterable[float]: + return zipWith(add, ls1, ls2) + + +def sum(ls: Iterable[float]) -> float: + return reduce(add, ls, 0.0) + + +def prod(ls: Iterable[float]) -> float: + return reduce(mul, ls, 1.0) diff --git a/tests/test_operators.py b/tests/test_operators.py index f6e555af..dfce0429 100644 --- a/tests/test_operators.py +++ b/tests/test_operators.py @@ -107,41 +107,42 @@ def test_sigmoid(a: float) -> None: * It crosses 0 at 0.5 * It is strictly increasing. """ - # TODO: Implement for Task 0.2. - raise NotImplementedError("Need to implement for Task 0.2") + assert 0.0 <= sigmoid(a) <= 1.0 + assert_close(sigmoid(-a), 1.0 - sigmoid(a)) + assert_close(sigmoid(0.0), 0.5) + assert sigmoid(a) >= sigmoid(a - 1.0) @pytest.mark.task0_2 @given(small_floats, small_floats, small_floats) def test_transitive(a: float, b: float, c: float) -> None: """Test the transitive property of less-than (a < b and b < c implies a < c)""" - # TODO: Implement for Task 0.2. - raise NotImplementedError("Need to implement for Task 0.2") + if lt(a, b) and lt(b, c): + assert lt(a, c) @pytest.mark.task0_2 -def test_symmetric() -> None: +@given(small_floats, small_floats) +def test_symmetric(a: float, b: float) -> None: """Write a test that ensures that :func:`minitorch.operators.mul` is symmetric, i.e. gives the same value regardless of the order of its input. """ - # TODO: Implement for Task 0.2. - raise NotImplementedError("Need to implement for Task 0.2") + assert_close(mul(a, b), mul(b, a)) @pytest.mark.task0_2 -def test_distribute() -> None: +@given(small_floats, small_floats, small_floats) +def test_distribute(x: float, y: float, z: float) -> None: r"""Write a test that ensures that your operators distribute, i.e. :math:`z \times (x + y) = z \times x + z \times y` """ - # TODO: Implement for Task 0.2. - raise NotImplementedError("Need to implement for Task 0.2") + assert_close(mul(z, add(x, y)), add(mul(z, x), mul(z, y))) @pytest.mark.task0_2 def test_other() -> None: """Write a test that ensures some other property holds for your functions.""" - # TODO: Implement for Task 0.2. - raise NotImplementedError("Need to implement for Task 0.2") + assert_close(mul(0.0, 0.0), 0.0) # ## Task 0.3 - Higher-order functions @@ -168,8 +169,7 @@ def test_sum_distribute(ls1: List[float], ls2: List[float]) -> None: """Write a test that ensures that the sum of `ls1` plus the sum of `ls2` is the same as the sum of each element of `ls1` plus each element of `ls2`. """ - # TODO: Implement for Task 0.3. - raise NotImplementedError("Need to implement for Task 0.3") + assert_close(sum(addLists(ls1, ls2)), sum(ls1) + sum(ls2)) @pytest.mark.task0_3