From 81061c4c0dccf2cc2875bb370d47723d3a1c09c7 Mon Sep 17 00:00:00 2001
From: "github-classroom[bot]"
<66690702+github-classroom[bot]@users.noreply.github.com>
Date: Tue, 3 Sep 2024 21:31:57 +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 6ad6ee32b6e7cae80c59d687d88ca07826f277a0 Mon Sep 17 00:00:00 2001
From: "github-classroom[bot]"
<66690702+github-classroom[bot]@users.noreply.github.com>
Date: Tue, 3 Sep 2024 21:31:58 +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 d287a6568f41df0790b1e1f55ba72cdc50deece0 Mon Sep 17 00:00:00 2001
From: "github-classroom[bot]"
<66690702+github-classroom[bot]@users.noreply.github.com>
Date: Tue, 3 Sep 2024 21:31:58 +0000
Subject: [PATCH 3/5] Setting up GitHub Classroom Feedback
From 053f77e1fcf9f0c7814fdeefac1b42cc8f290622 Mon Sep 17 00:00:00 2001
From: "github-classroom[bot]"
<66690702+github-classroom[bot]@users.noreply.github.com>
Date: Tue, 3 Sep 2024 21:32:01 +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..5b674014 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,4 @@
+[](https://classroom.github.com/online_ide?assignment_repo_id=15734874&assignment_repo_type=AssignmentRepo)
# MiniTorch Module 0
From 4585eaba527f648764e8e7c4b541836ba6a73d65 Mon Sep 17 00:00:00 2001
From: patteera triamamornwooth
Date: Mon, 25 Aug 2025 01:35:57 +0700
Subject: [PATCH 5/5] First commit
---
minitorch/datasets.py | 24 +++++--
minitorch/operators.py | 146 ++++++++++++++++++++++++++++++++++------
requirements.extra.txt | 4 +-
tests/test_operators.py | 62 +++++++++++++++--
4 files changed, 200 insertions(+), 36 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..a89159f4 100644
--- a/minitorch/operators.py
+++ b/minitorch/operators.py
@@ -3,28 +3,28 @@
import math
# ## Task 0.1
-from typing import Callable, Iterable
#
# Implementation of a prelude of elementary functions.
# Mathematical functions:
-# - mul
-# - id
-# - add
-# - neg
-# - lt
-# - eq
-# - max
-# - is_close
-# - sigmoid
-# - relu
-# - log
-# - exp
-# - log_back
-# - inv
-# - inv_back
-# - relu_back
+
+# mul - Multiplies two numbers
+# id - Returns the input unchanged
+# add - Adds two numbers
+# neg - Negates a number
+# lt - Checks if one number is less than another
+# eq - Checks if two numbers are equal
+# max - Returns the larger of two numbers
+# is_close - Checks if two numbers are close in value
+# sigmoid - Calculates the sigmoid function
+# relu - Applies the ReLU activation function
+# log - Calculates the natural logarithm
+# exp - Calculates the exponential function
+# inv - Calculates the reciprocal
+# log_back - Computes the derivative of log times a second arg
+# inv_back - Computes the derivative of reciprocal times a second arg
+# relu_back - Computes the derivative of ReLU times a second arg
#
# For sigmoid calculate as:
# $f(x) = \frac{1.0}{(1.0 + e^{-x})}$ if x >=0 else $\frac{e^x}{(1.0 + e^{x})}$
@@ -35,15 +35,86 @@
# TODO: Implement for Task 0.1.
+def mul(a, b):
+ return a * b
+
+
+def id(a):
+ return a
+
+
+def add(a, b):
+ return a + b
+
+
+def neg(a):
+ return -1 * a
+
+
+def lt(a, b):
+ return a < b
+
+
+def eq(a, b):
+ return a == b
+
+
+def max(a, b):
+ return a if (a > b) else b
+
+
+def is_close(a, b):
+ return abs(a - b) < 1e-2
+
+
+def sigmoid(a):
+ if a >= 0:
+ return 1 / (1 + math.exp(-a))
+ else:
+ return math.exp(a) / (1 + math.exp(a))
+
+
+def relu(a):
+ return max(0, a)
+
+
+def log(a):
+ return math.log(a)
+
+
+def exp(a):
+ return math.exp(a)
+
+
+def inv(a):
+ return 1 / a
+
+
+def log_back(a, b):
+ return inv(a) * b
+
+
+def inv_back(a, b):
+ return (-1) / (a**2) * b
+
+
+def relu_back(a, b):
+ if a <= 0:
+ return 0
+ else:
+ return b
+
+
# ## Task 0.3
# Small practice library of elementary higher-order functions.
# Implement the following core functions
-# - map
-# - zipWith
-# - reduce
-#
+
+# map - Higher-order function that applies a given function to each element of an iterable
+# zipWith - Higher-order function that combines elements from two iterables using a given function
+# reduce - Higher-order function that reduces an iterable to a single value using a given function
+
# Use these to implement
# - negList : negate a list
# - addLists : add two lists together
@@ -52,3 +123,36 @@
# TODO: Implement for Task 0.3.
+
+
+def map(fn, iter):
+ return [fn(item) for item in iter]
+
+
+def zipWith(fn, iter1, iter2):
+ return [fn(x, y) for x, y in zip(iter1, iter2)]
+
+
+def reduce(fn, iter):
+ if len(iter) == 0:
+ return 0
+ result = iter[0]
+ for item in iter[1:]:
+ result = fn(result, item)
+ return result
+
+
+def negList(ls):
+ return map(neg, ls)
+
+
+def addLists(ls1, ls2):
+ return zipWith(add, ls1, ls2)
+
+
+def sum(ls):
+ return reduce(add, ls)
+
+
+def prod(ls):
+ return reduce(mul, ls)
diff --git a/requirements.extra.txt b/requirements.extra.txt
index 070fa1d0..81db5232 100644
--- a/requirements.extra.txt
+++ b/requirements.extra.txt
@@ -1,5 +1,7 @@
+altair==4.2.2
datasets==2.4.0
embeddings==0.0.8
+networkx==3.3
plotly==4.14.3
pydot==1.4.1
python-mnist
@@ -7,5 +9,3 @@ streamlit==1.12.0
streamlit-ace
torch
watchdog==1.0.2
-altair==4.2.2
-networkx==3.3
diff --git a/tests/test_operators.py b/tests/test_operators.py
index f6e555af..86bf05a8 100644
--- a/tests/test_operators.py
+++ b/tests/test_operators.py
@@ -23,6 +23,7 @@
relu,
relu_back,
sigmoid,
+ is_close,
)
from .strategies import assert_close, small_floats
@@ -108,7 +109,13 @@ def test_sigmoid(a: float) -> None:
* It is strictly increasing.
"""
# TODO: Implement for Task 0.2.
- raise NotImplementedError("Need to implement for Task 0.2")
+ epsilon = 1e-6
+ assert 0 <= sigmoid(a) <= 1
+ assert is_close(1 - sigmoid(a), sigmoid(-a))
+ assert is_close(sigmoid(0), 0.5)
+ assert epsilon + sigmoid(a) > sigmoid(a)
+
+ # raise NotImplementedError("Need to implement for Task 0.2")
@pytest.mark.task0_2
@@ -116,7 +123,10 @@ def test_sigmoid(a: float) -> None:
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 a < c
+ # raise NotImplementedError("Need to implement for Task 0.2")
@pytest.mark.task0_2
@@ -125,7 +135,20 @@ def test_symmetric() -> None:
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")
+ # Test some edge cases
+ edge_cases = [
+ (0, 0),
+ (1, 0),
+ (-1, 0),
+ (1, 1),
+ (-1, -1),
+ (float("inf"), 2),
+ (float("-inf"), 2),
+ ]
+
+ for a, b in edge_cases:
+ assert mul(a, b) == mul(b, a)
+ # raise NotImplementedError("Need to implement for Task 0.2")
@pytest.mark.task0_2
@@ -134,14 +157,33 @@ def test_distribute() -> None:
: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")
+ edge_cases = [
+ (0, 0, 1),
+ (1, 0, 1),
+ (-1, 0, 3),
+ (1, 1, 4),
+ (-1, -1, 6),
+ ]
+
+ for a, b, c in edge_cases:
+ assert mul(c, (add(a, b))) == (c * a) + (c * b)
+ # raise NotImplementedError("Need to implement for Task 0.2")
@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")
+ edge_cases = [
+ (0, 0, 1),
+ (1, 0, 1),
+ (-1, 0, 3),
+ (1, 1, 4),
+ (-1, -1, 6),
+ ]
+
+ for a, b, c in edge_cases:
+ assert (a * (b * c)) == (a * b) * c
# ## Task 0.3 - Higher-order functions
@@ -169,7 +211,15 @@ def test_sum_distribute(ls1: List[float], ls2: List[float]) -> None:
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")
+ if len(ls1) != len(ls2):
+ raise ValueError("Lists must be of the same length")
+ if len(ls1) == 0 or len(ls2) == 0:
+ raise ValueError("List can't be empty")
+ lhs = sum(ls1) + sum(ls2)
+ rhs = sum(addLists(ls1, ls2))
+ assert_close(lhs, rhs)
+
+ # raise NotImplementedError("Need to implement for Task 0.3")
@pytest.mark.task0_3